/* ===== 01-base ===== */
/* =====================================================================
   MineMC vote site - the Lunar Client LAYOUT in our own look, built
   around the owner's logo (2026-11-05). public/style.css is joined from
   10 parts in this order: 01-base, 02-header, 03-hero, 04-strip,
   05-main, 06-side, 07-cta-foot, 08-ad, 09-responsive,
   10-reduced-motion. Keep the order: later parts rely on earlier ones
   (09 overrides 01-08 per breakpoint, 10 switches motion off).

   01-base: the :root tokens (the only place they are defined, incl. the
   layout lengths --page-max --gutter --nav-h --nav-sub-h --nav-full
   --strip-over --cta-over, which 09-responsive changes per breakpoint),
   reset, type helpers, the logo frame / slot / tuft materials, every .btn
   button, the full-height .block-btn (header VOTE NOW, IP bar COPY IP),
   the stone + grass .mat titles, the background layers + edges, scroll
   reveal and focus rings.

   Texture vars (--tex-*, --speck-*, --frame-*) and --ct / --ch are set
   on <html> by MineArt.buildTextures() / measureCaps() (art.js). Every
   var() below has a flat fallback, so the page still renders without them.
   The torch glow (.torch-glow, @keyframes flicker), the IP button face
   (.btn-ip) and .status-line live in 03-hero. No border-radius anywhere.
   ===================================================================== */

/* ---------- tokens ---------- */
:root {
  color-scheme: dark;
  /* COLOURS: palette reference only. The rules below use the literal hex values,
     so when you change a colour here, change the same hex in the rules too. */
  /* logo frame darks (measured: outer ring #000, inner rings #1e1c1d/#121112) */
  --black: #000000;
  --bedrock: #010101;
  --ink: #090706;            /* MINE letter outline */
  --outline-grass: #020200;  /* MC letter outline */
  --bg: #121112;             /* page base, frame inner ring */
  --bg-2: #1e1c1d;           /* frame dark ring, slots, list rows */
  --stone-0: #393537;        /* frame bottom/mid line, tags, stone side */
  --stone-1: #504b4d;        /* frame right line, slot light edge, seams */
  --frame-left: #625c5d;
  --frame-top: #7b7577;
  --glint: #afa7a8;
  /* stone letters (MINE) */
  --stone-side: #4a4341;
  --stone-3: #746a67;
  --stone-4: #958883;
  --stone-5: #a49690;
  --stone-6: #b2a29c;
  --stone-7: #cabbb3;
  /* scene stone + cobble */
  --rock: #5a5452;
  --rock-hi: #91847a;
  --mortar: #221e07;
  /* grass + dirt (MC + scene) */
  --grass-hi: #70b309;
  --grass: #529205;
  --grass-lo: #3e6106;
  --grass-scene: #559805;
  --grass-dark: #2f6102;
  --dirt-hi: #8e4f17;
  --dirt-tex: #875212;
  --dirt: #63380e;
  --dirt-lo: #432a12;
  --dirt-deep: #2a1a05;
  /* mine opening */
  --mine: #080702;
  --mine-2: #0c0a07;
  --mine-3: #120d06;
  /* torch flame */
  --torch: #dec139;
  --torch-2: #cd7703;
  --torch-3: #b16a06;
  /* kept server meanings */
  --gold: #F2B94B;     /* reward + prize values, #1 */
  --emerald: #18D978;  /* success, Online, gems, #2 - never a surface */
  --blue: #78AFFF;     /* #3 accent + diamond only */
  --bad: #FF5555;      /* refusals, Offline, barrier */
  /* text */
  --text: #EEE7E2;     /* warm stone white */
  --muted: #b2a29c;
  --faint: #958883;
  /* fonts */
  /* Silkscreen = titles (700) and buttons (400). Inter 800 = the IP, every number and the
     small labels: pixel fonts draw C like O and 5 like S at small sizes, and kids type the IP. */
  --font-title: 'Silkscreen', 'Courier New', monospace;
  --font-pixel: 'Silkscreen', 'Courier New', monospace;
  --font-ui: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  /* pixel grid: --t = one texel = one logo pixel at the current hero logo size */
  --t: 4px;
  --tile: calc(var(--t) * 16);
  --u: 3px;                         /* frame / bevel / letter-outline unit */
  --ct: 0.18em;                    /* cap top inside a 1em line, measured by JS */
  --ch: 0.64em;                     /* cap height, measured by JS */
  /* layout (plain lengths only, so MineArt.cssPx() can read them; 09-responsive changes them per breakpoint) */
  --page-max: 1360px;   /* widest content row: strip, columns, banner, footer row */
  --gutter: 40px;       /* side padding of every content row */
  --nav-h: 80px;        /* header row 1 */
  --nav-sub-h: 48px;    /* header row 2 */
  --nav-full: 128px;    /* row 1 + row 2 (app.js reads it for the hero scene) */
  --strip-over: 140px;  /* how far the tile strip overlaps the hero bottom */
  --cta-over: 96px;     /* how far the bottom banner overlaps the footer */
  /* white pixel arrow with a dark 1-texel shadow = "opens a new tab" on dark faces
     (.btn, the header row 2 links, the drawer links) */
  --arrow-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 7' shape-rendering='crispEdges'%3E%3Cpath fill='%23090706' d='M5 1h1v6H5zM6 2h1v4H6zM1 3h7v2H1z'/%3E%3Cpath fill='%23fff' d='M4 0h1v6H4zM5 1h1v4H5zM0 2h7v2H0z'/%3E%3C/svg%3E");
}
@media (min-width: 1280px) and (min-height: 900px) { :root { --t: 5px; } }
@media (max-height: 680px), (max-width: 359px) { :root { --t: 3px; } }
@media (max-height: 560px) { :root { --t: 2px; } }
@media (max-width: 640px) { :root { --u: 2px; } }

/* ---------- base / reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
/* in-page links land below the fixed header row */
html { scroll-padding-top: calc(var(--nav-h) + 12px); }
body {
  margin: 0;
  background: #121112;
  color: #EEE7E2;
  font: 400 16px/1.55 var(--font-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  /* every raster on this page is pixel art drawn at whole-texel sizes:
     keep the texels square on 2x / 3x screens too (inherited). The
     owner's logo is always shown at whole multiples of 64 px. */
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
a { color: inherit; text-decoration: none; }
h1, h2, h3, p { margin: 0; }
button, input { font: inherit; color: inherit; }
canvas {
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
::selection { background: #3e6106; color: #fff; }

/* ---------- type helpers ---------- */
.muted { color: #b2a29c; }
.center { text-align: center; }
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.kicker {
  font: 800 17px/1.2 var(--font-ui);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #dec139;
  text-shadow: 2px 2px 0 #090706;
}
.kicker-sm {
  font: 800 16px/1.2 var(--font-ui);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: #b2a29c;
  text-shadow: 2px 2px 0 #090706;
}
.msg { min-height: 22px; margin-top: 8px; font: 600 16px/1.4 var(--font-body); }
.msg.ok { color: #18D978; }
.msg.bad { color: #FF5555; }
.msg.muted { font-weight: 400; margin-top: 0; color: #b2a29c; }

/* ---------- the logo frame (our redraw, 9-slice from --frame-3 / --frame-2) ----------
   The image is made at its exact size, so 'repeat' never stretches it.
   No var -> border-image is invalid -> none, and the solid #393537 border shows.
   background-clip: padding-box keeps the notched corners open; parts that
   give a .frame a background use longhands or repeat the padding-box clip
   (the background shorthand resets it). Never clip-path on these. */
.frame {
  border: 18px solid #393537;
  border-image: var(--frame-3) 18 / 18px repeat;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
  background-clip: padding-box;
}
.frame-sm {
  border-width: 12px;
  border-image: var(--frame-2) 12 / 12px repeat;
}

/* recessed inventory slot */
.slot {
  background: #1e1c1d;
  box-shadow: inset 3px 3px 0 #010101, inset -3px -3px 0 #504b4d, 0 0 0 2px #010101;
}

/* grass tuft growing over a frame's top edge, like the grass over the logo.
   top = -(frame border) - 12px. Flat fallback: a plain grass strip. */
.tuft {
  position: absolute;
  left: 6px;
  top: -30px;
  z-index: 3;
  width: 96px;
  height: 24px;
  background: var(--tex-tuft, linear-gradient(transparent 9px, #529205 9px 18px, #3e6106 18px 21px, transparent 21px)) 0 0 / 96px 24px no-repeat;
  pointer-events: none;
}
.frame > .tuft { top: -30px; }
.frame-sm > .tuft { top: -24px; }

/* ---------- buttons ----------
   A pixel block: light top line, dark bottom line, 1u dark ring, a solid
   "side" under the face and a dark line under that, all box-shadows (no
   radius, no clip-path, so focus rings and taps stay normal).
   --rest = the resting side depth. The margin is built from --rest, so a
   press (side 6 -> 2, face down 4) never moves the page below the button. */
.btn {
  --u: 3px;
  --rest: 6px;
  --side: var(--rest);
  --hi: rgba(255, 255, 255, .30);
  --lo: rgba(1, 1, 1, .25);
  --edge: #010101;
  --side-c: #2a1a05;
  /* pixel arrow for links that open a new tab: white with a 2px shadow (dark
     faces) or plain dark (bright faces); 2px texels, crisp edges */
  --arrow: var(--arrow-light);
  --arrow-w: 16px;
  --arrow-h: 14px;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 56px;
  max-width: calc(100% - var(--u) * 2);
  padding: 0 28px;
  margin: var(--u) var(--u) calc(var(--rest) + var(--u) * 2);
  border: 0;
  border-radius: 0;
  background: #393537;
  font: 400 20px/1 var(--font-pixel);
  color: #fff;
  text-align: center;
  text-decoration: none;
  text-shadow: 2px 2px 0 #090706;
  white-space: nowrap;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  box-shadow:
    inset 0 var(--u) 0 var(--hi),
    inset 0 calc(var(--u) * -1) 0 var(--lo),
    0 0 0 var(--u) var(--edge),
    0 var(--side) 0 var(--u) var(--side-c),
    0 calc(var(--side) + var(--u)) 0 var(--u) var(--edge);
  transition: transform .06s, filter .1s;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) {
  .btn:hover { filter: brightness(1.08); transform: translateY(-2px); }
}
.btn:active { --side: 2px; transform: translateY(calc(var(--rest) - 2px)); }
.btn:focus-visible { outline: 3px solid #dec139; outline-offset: 6px; }
.btn:disabled,
.btn[aria-disabled="true"] { cursor: not-allowed; filter: grayscale(.5) brightness(.75); transform: none; }

/* primary = grass block: bright green face, dark label (8:1), dirt side */
.btn-grass {
  background: #70b309;
  color: #010101;
  text-shadow: none;
  --hi: rgba(255, 255, 255, .35);
  --lo: #3e6106;
  --edge: #020200;
  --side-c: #63380e;
  --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 7 6' shape-rendering='crispEdges'%3E%3Cpath fill='%23010101' d='M4 0h1v6H4zM5 1h1v4H5zM0 2h7v2H0z'/%3E%3C/svg%3E");
  --arrow-w: 14px;
  --arrow-h: 12px;
}
/* stone block: specked stone face (flat #6a605d without the texture) */
.btn-stone {
  background: var(--speck-stone, none) 0 0, #6a605d;
  --hi: #a49690;
  --lo: #4a4341;
  --edge: #090706;
  --side-c: #393537;
}
/* gold block (Copy IP, store ad link) */
.btn-gold {
  background: #dec139;
  color: #2a1a05;
  text-shadow: none;
  --hi: #f2dc78;
  --lo: #cd7703;
  --edge: #090706;
  --side-c: #b16a06;
  --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 7 6' shape-rendering='crispEdges'%3E%3Cpath fill='%232a1a05' d='M4 0h1v6H4zM5 1h1v4H5zM0 2h7v2H0z'/%3E%3C/svg%3E");
  --arrow-w: 14px;
  --arrow-h: 12px;
}
.btn-lg { min-height: 64px; font-size: 24px; padding: 0 34px; }
.btn-sm { --rest: 4px; min-height: 44px; font-size: 17px; padding: 0 18px; }
.btn-square { --rest: 4px; width: 44px; height: 44px; min-height: 44px; padding: 0; flex: none; }
.btn-square svg { display: block; width: 20px; height: 20px; shape-rendering: crispEdges; }
.sound[aria-pressed="false"] #sound-waves { opacity: 0; }
.sound[aria-pressed="false"] { background: #393537; }
/* links that open a new tab get the pixel arrow (decorative, nothing read out) */
#ad-link[data-copy="1"]::after { display: none; }
.btn[target=_blank]::after {
  content: '';
  flex: none;
  width: var(--arrow-w);
  height: var(--arrow-h);
  background: var(--arrow) 0 0 / 100% 100% no-repeat;
}

/* ---------- full-height block buttons (header VOTE NOW, IP bar COPY IP) ----------
   A flat block that fills its bar's height: light top line, dark side lines,
   no 3D side (the bar is the base). Size the grass block with padding
   LONGHANDS (padding-left / padding-right) so its 12px bottom padding (the
   dirt band) survives. */
.block-btn {
  --hi: rgba(255, 255, 255, .35);
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  margin: 0; padding: 0 28px; border: 0; border-radius: 0;
  font: 400 20px/1 var(--font-pixel); letter-spacing: .06em; text-transform: uppercase;
  text-decoration: none; text-align: center; white-space: nowrap; cursor: pointer;
  -webkit-appearance: none; appearance: none; touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  box-shadow: inset 0 3px 0 var(--hi), inset 3px 0 0 rgba(1, 1, 1, .35), inset -3px 0 0 rgba(1, 1, 1, .35);
  transition: filter .1s;
}
.block-btn:hover { filter: brightness(1.08); }
.block-btn:active { filter: brightness(.92); }
.block-btn:focus-visible { outline: 3px dashed #010101; outline-offset: -8px; }
/* grass block: green face, 4px dark-green line, 12px dirt band at the bottom; label centred on the green face */
.block-btn.grass {
  color: #010101; padding-bottom: 12px;
  background-color: #63380e;
  background-image: linear-gradient(180deg, #70b309 0 calc(100% - 16px), #3e6106 calc(100% - 16px) calc(100% - 12px), transparent calc(100% - 12px)), var(--tex-dirt, none);
  background-repeat: no-repeat, repeat; background-size: 100% 100%, auto; background-position: 0 0, 0 100%;
}
.block-btn.gold { --hi: #f2dc78; color: #2a1a05; background: #dec139; box-shadow: inset 0 3px 0 var(--hi), inset 0 -5px 0 #b16a06; }

/* ---------- stone + grass titles (MINE look and MC look) ----------
   richText() fills every .title with sibling spans: .mat.stone / .mat.grass.
   Each span has its own clip and its own filter; they are never nested and
   the h2 itself has no clip. Background LONGHANDS only on .mat (the
   shorthand resets the text clip). */
.title {
  --u: 3px;
  margin: 0;
  font: 700 clamp(34px, 6.5vw, 72px)/1 var(--font-title);
  text-transform: uppercase;
  letter-spacing: .02em;
  text-wrap: balance;
  color: #a49690;
}
.title .mat { margin: 0 .12em; }
.title-sm { font-size: clamp(28px, 5.5vw, 44px); --u: 2px; }
/* stacked title: each word on its own line, left aligned (the server card's "MineMC / [Factions]") */
.title-stack .mat { display: block; width: max-content; max-width: 100%; margin: 0 0 .12em; }

.mat {
  --o: var(--u);
  display: inline-block;
  vertical-align: top;
  max-width: 100%;
  line-height: 1;
  color: #a49690;
  text-shadow: none;   /* a shadow would show through the clipped (transparent) letters */
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
/* only hide the glyph fill where the background can be clipped to the text */
@supports (-webkit-background-clip: text) or (background-clip: text) {
  .mat {
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
  }
}
/* hard colour stops = pixel bands: light top, darker toward the bottom.
   100% 1em repeat-y re-bands every wrapped line (line-height 1). */
.mat.stone {
  background-image:
    var(--speck-stone, linear-gradient(transparent, transparent)),
    linear-gradient(180deg,
      #cabbb3 0 calc(var(--ct) + var(--ch) * .12),
      #b2a29c 0 calc(var(--ct) + var(--ch) * .30),
      #a49690 0 calc(var(--ct) + var(--ch) * .58),
      #958883 0 calc(var(--ct) + var(--ch) * .82),
      #746a67 0);
  background-size: auto, 100% 1em;
  background-repeat: repeat, repeat-y;
  background-position: 0 0, 0 0;
  /* 1u #cabbb3 highlight top-left, a 2u extrude, then a 1u outline in 4
     directions (diagonal corners stay open = a pixel-art outline) */
  filter:
    drop-shadow(calc(var(--o) * -1) calc(var(--o) * -1) 0 #cabbb3)
    drop-shadow(0 calc(var(--o) * 2) 0 #4a4341)
    drop-shadow(var(--o) 0 0 #090706)
    drop-shadow(calc(var(--o) * -1) 0 0 #090706)
    drop-shadow(0 var(--o) 0 #090706)
    drop-shadow(0 calc(var(--o) * -1) 0 #090706);
}
/* grass over the top 58% of the caps, drips into bright dirt below, like the logo's MC
   (the drop-shadow is the dark extrude under the letter) */
.mat.grass {
  color: #70b309;
  background-image:
    var(--speck-grass, linear-gradient(transparent, transparent)),
    var(--tex-grass-drip, linear-gradient(transparent, transparent)),
    linear-gradient(180deg,
      #70b309 0 calc(var(--ct) + var(--ch) * .20),
      #529205 0 calc(var(--ct) + var(--ch) * .46),
      #3e6106 0 calc(var(--ct) + var(--ch) * .58),
      #8e4f17 0 calc(var(--ct) + var(--ch) * .82),
      #63380e 0);
  background-size: auto, auto, 100% 1em;
  background-repeat: repeat, repeat-x, repeat-y;
  background-position: 0 0, 0 calc(var(--ct) + var(--ch) * .58), 0 0;
  filter:
    drop-shadow(0 calc(var(--o) * 2) 0 #2a1a05)
    drop-shadow(var(--o) 0 0 #020200)
    drop-shadow(calc(var(--o) * -1) 0 0 #020200)
    drop-shadow(0 var(--o) 0 #020200)
    drop-shadow(0 calc(var(--o) * -1) 0 #020200);
}

/* ---------- background layers + edges ----------
   Textures are made at the exact texel size, so background-size stays
   natural. The rgba overlays equal SHADE in art.js. */
.layer { position: relative; overflow-x: clip; }
.layer-dirt { background: linear-gradient(rgba(20, 12, 3, .78), rgba(20, 12, 3, .78)), var(--tex-dirt, none) 0 0, #2a1a05; }
.layer-bedrock { background: linear-gradient(rgba(1, 1, 1, .55), rgba(1, 1, 1, .55)), var(--tex-bedrock, none) 0 0, #010101; }
/* jagged material change at the top of a section (one tile tall); the
   modifier class sets the picture. Without the texture it is simply
   see-through: the section's own colour. */
.edge {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: var(--tile);
  background: none 0 0 repeat-x;
  pointer-events: none;
}
.edge-4 { background-image: var(--tex-edge-4, none); }   /* dirt -> bedrock at the footer top */

/* ---------- scroll reveal (only when JS runs: app.js adds html.js) ---------- */
.js .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .5s cubic-bezier(.2, .8, .2, 1), transform .5s cubic-bezier(.2, .8, .2, 1);
}
.js .reveal.in { opacity: 1; transform: none; }
/* the in-page link targets only fade: a slide would make a header link land 24px too high, under the fixed header */
.js #vote.reveal, .js #top.reveal { transform: none; }

/* ---------- focus: one torch-yellow ring everywhere (keyboard only) ---------- */
:focus-visible { outline: 3px solid #dec139; outline-offset: 3px; }
:focus:not(:focus-visible) { outline: none; }
/* ===== 02-header ===== */
/* =====================================================================
   02-header  -  the fixed two-row header (Lunar layout) + the menu drawer
   - Row 1 .nav-main (var(--nav-h), #121112): owner's logo 64 px + MINEMC
     wordmark / "* N online" (.nav-status) / the full-height grass
     .block-btn VOTE NOW (.nav-vote) / pixel 3-bar icon + MENU (#menu-btn).
   - Row 2 .nav-sub (var(--nav-sub-h)): centred page links. app.js adds
     #nav.compact past 40 px of scroll, which hides row 2; 09-responsive
     hides it below 768 px.
   - #drawer: the menu (z 40, under the house ad's 50). app.js toggles
     [hidden], body.menu-open and #menu-btn[aria-expanded].
   Relies on 01-base: tokens (--nav-h, --nav-sub-h, --gutter, --font-*),
   .frame, .btn*, .block-btn, .sr. .status-line + .ip-label are in
   03-hero. Phone sizes live in 09-responsive, no-motion in 10.
   ===================================================================== */

/* ---------- header ---------- */
.nav { position: fixed; inset: 0 0 auto 0; z-index: 30; box-shadow: 0 3px 0 rgba(1, 1, 1, .35); }
.nav-main { display: flex; align-items: stretch; height: var(--nav-h); padding-left: var(--gutter); background: #121112; box-shadow: inset 0 -3px 0 #010101; }
.brand { display: flex; align-items: center; gap: 14px; margin-right: auto; min-width: 0; }   /* margin-right:auto = all free space after the brand */
.brand:focus-visible { outline-offset: -6px; }   /* the brand fills the bar height: keep the ring inside the bar */
.brand-logo {
  display: block;
  flex: none;
  width: 64px;
  height: 64px;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
/* Silkscreen 400, not 700: in 700 the M is drawn like an H ("HINEHC") */
.brand-word { font: 400 28px/1 var(--font-title); letter-spacing: .06em; text-transform: uppercase; color: #EEE7E2; text-shadow: 3px 3px 0 #090706; white-space: nowrap; }
.brand:hover .brand-word { color: #dec139; }
.nav-status { display: flex; align-items: center; padding: 0 28px; }
.nav-vote { min-width: 240px; padding-left: 32px; padding-right: 32px; font-size: 24px; letter-spacing: .08em; }
.nav-menu { flex: none; display: flex; align-items: center; gap: 12px; margin: 0; padding: 0 var(--gutter) 0 28px; border: 0; border-radius: 0; background: none; cursor: pointer;
  font: 400 20px/1 var(--font-pixel); letter-spacing: .06em; text-transform: uppercase; color: #EEE7E2; text-shadow: 2px 2px 0 #090706; }
.nav-menu svg { display: block; width: 24px; height: 20px; filter: drop-shadow(2px 2px 0 #090706); }
.nav-menu:hover, .nav-menu[aria-expanded="true"] { color: #dec139; }
.nav-menu:focus-visible { outline-offset: -6px; }
.nav-sub { display: flex; align-items: center; justify-content: center; gap: 40px; height: var(--nav-sub-h); padding: 0 var(--gutter);
  background: rgba(9, 7, 6, .72); box-shadow: inset 0 -3px 0 rgba(1, 1, 1, .55); }
.nav-sub a { display: inline-flex; align-items: center; min-height: 44px; font: 400 15px/1 var(--font-pixel); letter-spacing: .06em; text-transform: uppercase; color: #EEE7E2; text-shadow: 2px 2px 0 #090706; white-space: nowrap; }
.nav-sub a:hover, .nav-sub a:focus-visible, .nav-sub a.is-active { color: #dec139; text-decoration-line: underline; text-decoration-thickness: 3px; text-decoration-color: #70b309; text-underline-offset: 6px; }
.nav.compact .nav-sub { display: none; }
/* Discord / Store open a new tab: the same white pixel arrow the buttons get */
.nav-sub a[target=_blank]::after,
.drawer-links a[target=_blank]::after { content: ''; flex: none; width: 14px; height: 12px; margin-left: 8px; background: var(--arrow-light) 0 0 / 100% 100% no-repeat; }

/* ---------- menu drawer (z 40, under the house ad's 50) ----------
   .drawer-panel is a .frame: background longhands + padding-box clip only. */
.drawer { position: fixed; inset: 0; z-index: 40; }
.drawer-shade { position: absolute; inset: 0; background: rgba(1, 1, 1, .72); }
.drawer-panel { position: absolute; top: 0; right: 0; bottom: 0; width: min(380px, 100%); display: flex; flex-direction: column; gap: 16px; padding: 16px;
  overflow-y: auto; overscroll-behavior: contain; background-color: #121112;
  background-image: linear-gradient(rgba(1, 1, 1, .78), rgba(1, 1, 1, .78)), var(--tex-stone, none); background-clip: padding-box;
  animation: drawerIn .18s steps(3); }
.drawer-panel:focus { outline: none; }
@keyframes drawerIn { from { transform: translateX(32px); opacity: 0; } }
.drawer-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.drawer-logo {
  display: block;
  flex: none;
  width: 64px;
  height: 64px;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
.drawer-top .btn { margin: 3px 3px 10px; }
.drawer-links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.drawer-links a { display: flex; align-items: center; min-height: 52px; padding: 0 16px; font: 400 19px/1 var(--font-pixel); letter-spacing: .04em; text-transform: uppercase;
  color: #EEE7E2; text-shadow: 2px 2px 0 #090706; background: #1e1c1d; box-shadow: 0 0 0 2px #010101, inset 0 3px 0 #393537, inset 0 -3px 0 #121112; }
.drawer-links a:hover, .drawer-links a:focus-visible, .drawer-links a.is-active { color: #dec139; background: #393537; }
.drawer-status { display: flex; justify-content: center; margin: 0; }
.drawer-vote, .drawer-ip .btn { width: calc(100% - 6px); }
.drawer-ip { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; }
.drawer-ip-text { font: 800 22px/1.2 var(--font-ui); color: #fff; text-shadow: 2px 2px 0 #090706; }
body.menu-open { overflow: hidden; }
/* short screens (the 320x568 phone): the whole drawer fits without scrolling, down to COPY IP
   (measured 2026-11-08: 544 of 544 px at 320x568, with every tap target still 44 px or taller).
   The status is in the hero meta already; the IP needs no label next to its own text. */
@media (max-height: 680px) {
  .drawer-panel { gap: 8px; padding-top: 12px; padding-bottom: 12px; }
  .drawer-top .btn { margin-bottom: 3px; }
  .drawer-logo { width: 48px; height: 48px; }
  .drawer-links { gap: 3px; }
  .drawer-links a { min-height: 44px; font-size: 17px; }
  .drawer-vote { min-height: 56px; font-size: 20px; }
  .drawer-status { display: none; }
  .drawer-ip { gap: 4px; }
  .drawer-ip .ip-label { display: none; }
  .drawer-ip-text { font-size: 18px; }
  .drawer-ip .btn { min-height: 48px; font-size: 18px; }
}
/* ===== 03-hero ===== */
/* =====================================================================
   03-hero  -  the full-width title screen (Lunar layout) + torch glows
   - The owner's logo is only an <img>, shown at 320 / 256 / 192 / 128 px
     (same breakpoints as --t in 01-base, so one logo pixel = one texel).
     Nothing on the img except size + crisp pixels. Decoration lives on
     .logo-wrap only.
   - #hero-art is painted by MineArt.drawTitleScene (JS sets its size from
     the hero box; never give it a CSS width/height).
   - Stacking inside the (isolated) hero: canvas -> .hero-shade ->
     .torches (z 1) -> .hero-inner (z 2).
   - .torch-glow left/top come from MineArt.placeTorches (inline px).
   - .hero-inner gets inline transform/opacity from the parallax.
   - The bottom var(--strip-over) of the hero sits under the tile strip
     (04-strip pulls it up), so the padding keeps the content above it.
   - .btn-ip, .ip-label and .status-line are shared: the IP bar, the
     drawer, the header and the server row use them too.
   Relies on 01-base: tokens (--t, --tile, --nav-full, --strip-over,
   --font-*), .btn, .btn-grass, .btn-lg, .kicker, .kicker-sm.
   Phone / short-screen rules live in 09-responsive, no-motion in 10.
   ===================================================================== */

/* ---------- hero box ---------- */
.hero { position: relative; isolation: isolate; overflow: hidden;
  min-height: 100vh; min-height: clamp(560px, 100svh, 940px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: calc(var(--nav-full) + 24px) 16px calc(var(--strip-over) + 32px);
  /* flat fallback: night bands, then the shaded dirt; shows until / unless the canvas paints */
  background:
    linear-gradient(180deg, #070809 0 25%, #0b0d0f 0 50%, #0f1315 0 75%, #141c1f 0) 0 0 / 100% calc(100% - var(--tile, 64px) * 3) no-repeat,
    linear-gradient(rgba(20, 12, 3, .78), rgba(20, 12, 3, .78)),
    #2a1a05; }

/* title scene canvas: JS sets style.width/height from the hero box */
.hero-art {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  pointer-events: none;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}

/* dark tint like Lunar's: darker under the header, vignette, faded out over the bottom tiles so it meets .ground with no seam */
.hero-shade { position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(1, 1, 1, .45) 0, rgba(1, 1, 1, 0) 30%), radial-gradient(ellipse at 50% 40%, transparent 45%, rgba(1, 1, 1, .5) 100%);
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - var(--tile, 64px) * 3), transparent calc(100% - var(--tile, 64px)));
  mask-image: linear-gradient(180deg, #000 calc(100% - var(--tile, 64px) * 3), transparent calc(100% - var(--tile, 64px))); }

/* the hero scene ends in a 1-block jagged pixel edge (lit scene -> the body dirt of
   .ground), like the footer's .edge-4. It sits behind the tile strip, so the scene
   carries on down behind the strip and the change only shows beside it.
   One tile tall at the hero bottom, so the dirt texture lines up with .ground's.
   The mask is 2 tiles wide (32 x 16 texels); dirt fills the bottom 5-11 texels.
   No mask support = a straight one-block dirt band, which is fine too. */
.hero::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  height: var(--tile, 64px);
  background: linear-gradient(rgba(20, 12, 3, .78), rgba(20, 12, 3, .78)), var(--tex-dirt, none) 0 0, #2a1a05;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 16' shape-rendering='crispEdges'%3E%3Cpath d='M0 16V8H1V9H3V7H4V6H6V7H7V9H8V10H10V9H11V11H13V10H14V8H15V7H17V6H18V5H20V6H21V8H22V9H24V8H25V10H26V11H27V10H28V9H29V8H32V16Z'/%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 16' shape-rendering='crispEdges'%3E%3Cpath d='M0 16V8H1V9H3V7H4V6H6V7H7V9H8V10H10V9H11V11H13V10H14V8H15V7H17V6H18V5H20V6H21V8H22V9H24V8H25V10H26V11H27V10H28V9H29V8H32V16Z'/%3E%3C/svg%3E");
  -webkit-mask-size: calc(var(--tile, 64px) * 2) var(--tile, 64px);
  mask-size: calc(var(--tile, 64px) * 2) var(--tile, 64px);
  -webkit-mask-repeat: repeat-x;
  mask-repeat: repeat-x;
  -webkit-mask-position: 0 0;
  mask-position: 0 0;
  pointer-events: none;
}

/* holder for the two hero torch glows (the torch sprites are in the canvas) */
.torches {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}

/* ---------- the centred column: logo, kicker, buttons, meta ---------- */
.hero-inner { position: relative; z-index: 2; display: flex; flex-direction: column; align-items: center; width: 100%; text-align: center; will-change: transform, opacity; }

/* ---------- the logo (never touched: size + crisp pixels only) ----------
   The page shows logo-clear.png: the owner's logo.png with only the black outside the stone frame made see-through
   (tools/logo-clear.js, owner 2026-11-08). No black block shadow under it any more, so nothing black around it. */
.logo-wrap {
  position: relative;
  isolation: isolate;
  flex: none;
  line-height: 0;
}
/* faint static torch glow behind the logo (stays faint, it also shows through the logo's see-through corners) */
.logo-wrap::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: -1;
  width: 200%;
  height: 200%;
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(222, 193, 57, .14), rgba(205, 119, 3, .06) 55%, transparent 80%);
  pointer-events: none;
}
.hero-logo {
  margin: 0;
  line-height: 0;
}
.hero-logo img {
  display: block;
  width: 256px;
  height: 256px;
  max-width: none;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
@media (min-width: 1280px) and (min-height: 900px) {
  .hero-logo img { width: 320px; height: 320px; }
}
@media (max-height: 680px), (max-width: 359px) {
  .hero-logo img { width: 192px; height: 192px; }
}
@media (max-height: 560px) {
  .hero-logo img { width: 128px; height: 128px; }
}

/* ---------- kicker under the logo ---------- */
.hero-kicker {
  margin-top: 22px;
  font-size: 18px;
  letter-spacing: .2em;
  padding-left: .2em;          /* balances the trailing letter-spacing so it centres */
  text-align: center;
}

/* IP button: dark face, light edge, 16px lines */
.btn-ip {
  flex-direction: column;
  gap: 4px;
  min-height: 88px;
  background: #121112;
  --hi: #393537;
  --lo: #010101;
  --edge: #746a67;
  --side-c: #4a4341;
}
.ip-label {
  font: 800 16px/1.1 var(--font-ui);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #cabbb3;
  text-shadow: 2px 2px 0 #090706;
}
.ip-text {
  font: 800 24px/1.1 var(--font-ui);
  letter-spacing: .01em;
  color: #fff;
  text-shadow: 3px 3px 0 #090706;
}
.ip-copy {
  font: 800 16px/1.1 var(--font-ui);
  color: #70b309;
  text-shadow: 2px 2px 0 #090706;
}
.btn-ip:hover .ip-text,
.btn-ip:focus-visible .ip-text { color: #dec139; }

/* ---------- the two side-by-side buttons: grass Vote now + the dark IP button ---------- */
.hero-buttons { display: flex; flex-wrap: wrap; justify-content: center; gap: 0 16px; margin-top: 24px; }
.hero-buttons .btn { min-width: 272px; min-height: 72px; }
.hero-buttons .btn-ip { gap: 2px; padding: 0 24px; }

/* ---------- small meta line: status (narrow screens only, 09) + version ----------
   on a dark nameplate at every width: it lands on the textured grass row of the scene */
.hero-meta { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px 16px; margin-top: 10px; min-height: 24px;
  background: rgba(1, 1, 1, .72); box-shadow: 0 0 0 2px #010101; padding: 4px 10px; width: fit-content; margin-left: auto; margin-right: auto; }
.hero-meta .kicker-sm { color: #EEE7E2; }
.hero-meta .kicker-sm:empty { display: none; }

/* ---------- server status (header, drawer, hero meta, server row); app.js sets .on / .off ---------- */
.status-line {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font: 800 16px/1.2 var(--font-ui);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: #b2a29c;
  text-shadow: 2px 2px 0 #090706;
}
.status-line .dot {
  flex: none;
  width: 10px;
  height: 10px;
  background: #b2a29c;
  box-shadow: 0 0 0 2px #010101;
}
.status-line.on { color: #18D978; }
.status-line.on .dot { background: #18D978; }
.status-line.off { color: #FF5555; }
.status-line.off .dot { background: #FF5555; }

/* ---------- hero torch glows: plain alpha, opacity-only flicker, no blend modes ---------- */
@keyframes flicker {
  0%   { opacity: 1; }
  23%  { opacity: .82; }
  41%  { opacity: .95; }
  67%  { opacity: .78; }
  84%  { opacity: .92; }
}

/* hero glows: centred on the canvas torch flames (left/top set by JS);
   parked off-screen until placed so nothing flashes in the corner */
.torch-glow {
  position: absolute;
  left: -999px;
  top: -999px;
  width: calc(var(--tile, 64px) * 6);
  height: calc(var(--tile, 64px) * 6);
  transform: translate(-50%, -50%);
  background: radial-gradient(closest-side, rgba(222, 193, 57, .30), rgba(205, 119, 3, .14) 45%, rgba(177, 106, 6, 0) 100%);
  animation: flicker 2.6s steps(1, end) infinite;
  pointer-events: none;
}
.torch-glow:nth-child(2) { animation-delay: -1.3s; }

/* ---------- the hero reel (reel.js) or the owner's hero video: the moving layer over the still scene ----------
   .hero-media holds #hero-reel (our drawn feature film) and #hero-video (only when SITE.reel.video is set).
   It sits between #hero-art and .hero-shade in the HTML, so it paints over the still scene and under the tint.
   app.js unhides it and puts .reel-on / .video-on on .hero only once something really runs; without them the
   hero looks exactly as before. #hero-art stays painted underneath: it shows again if the reel stops, it is the
   "reduce motion" picture, and its two shaded dirt rows show through the reel's faded bottom edge, so the hero
   still meets the dirt (.ground) below with no seam. */
.hero-media {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - var(--tile, 64px) * 2), transparent calc(100% - var(--tile, 64px) / 2));
  mask-image: linear-gradient(180deg, #000 calc(100% - var(--tile, 64px) * 2), transparent calc(100% - var(--tile, 64px) / 2));
}
/* the drawn film: reel.js renders it small (about 480x270) and the browser scales it up with square pixels.
   object-fit only matters if reel.js keeps a fixed 16:9 bitmap; it pans its own camera on tall phone screens. */
.hero-reel {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
/* the owner's own video (SITE.reel.video): see-through until it really plays, then fades in */
.hero-video {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  image-rendering: auto;            /* real footage scales smooth, not with the page's square pixels */
  opacity: 0;
  transition: opacity .6s ease-out;
}
.hero.video-on .hero-video { opacity: 1; }
/* the film's own dark tint (about 45 %, a little darker behind the logo); .hero-shade above it still adds the
   header band and the vignette, so the logo and the buttons stay easy to read */
.hero.reel-on .hero-media::after,
.hero.video-on .hero-media::after {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: radial-gradient(ellipse 36% 44% at 50% 46%, rgba(1, 1, 1, .34), rgba(1, 1, 1, 0)), rgba(7, 8, 9, .45);
}
/* the still scene's torch glows belong to its mine arch: off while the film or the video covers it */
.hero.reel-on .torches,
.hero.video-on .torches { display: none; }

/* ---------- the reel caption: the feature now playing, small, bottom-left, just above the tile strip ----------
   Lined up with the strip's left edge. It lives in the hero's 32 px bottom padding band (24 px tall + its 2 px
   ring, 6 px above the strip), so it never covers the logo or the buttons, from 320 px phones to big desktops.
   Text from SITE.reel.labels (texts.js); app.js shows it and replays the slide-in on every new scene. */
.hero-caption {
  position: absolute;
  z-index: 2;
  left: var(--gutter);
  left: max(var(--gutter), calc(50% - var(--page-max) / 2 + var(--gutter)));
  bottom: calc(var(--strip-over) + 6px);
  max-width: calc(100% - var(--gutter) * 2);
  margin: 0;
  padding: 4px 10px 4px 8px;
  font: 800 16px/16px var(--font-ui);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #EEE7E2;
  text-shadow: 2px 2px 0 #090706;
  background: rgba(1, 1, 1, .72);
  box-shadow: 0 0 0 2px #010101;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}
/* a small grass-block square in front of the name */
.hero-caption::before {
  content: '';
  display: inline-block;
  width: 10px;
  height: 10px;
  margin: 0 8px 0 0;
  vertical-align: 1px;
  background: #70b309;
  box-shadow: inset -2px -2px 0 #3e6106;
}
@keyframes reel-caption-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.hero-caption.swap { animation: reel-caption-in .35s ease-out both; }
/* ===== 04-strip ===== */
/* =====================================================================
   04 - HOW IT WORKS STRIP (the overlap trick)
   Four picture tiles in one framed strip that overlaps the bottom of
   the hero by --strip-over, like Lunar's feature strip. app.js builds
   each tile; art.js paints .tile-art (sized inline from the .tile box,
   so no CSS width/height on the canvas here).
   .ground is a flow-root so the strip's negative top margin pulls only
   the strip up and does not collapse into .ground (which would drag the
   dirt background up over the hero). .ground keeps .layer
   (position: relative; overflow-x: clip), so y overflow stays visible.
   Tile sizes per breakpoint live in 09-responsive.
   ===================================================================== */
.ground { display: flow-root; }

.strip-wrap { position: relative; z-index: 3; max-width: var(--page-max); margin: calc(var(--strip-over) * -1) auto 0; padding: 0 var(--gutter); }
/* also .frame (18px logo frame): background longhands only, padding-box clip */
.strip { --tile-h: 300px; --tile-pad: 44px; --tile-title: 28px;   /* 28 below 1280: a 6-letter word must fit a 4-across tile at 900-1279 */
  background-color: #121112; background-clip: padding-box; box-shadow: 0 12px 0 rgba(1, 1, 1, .45); }
.tiles { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 3px; background: #010101; }   /* the 3px gap = black seams between tiles */
.tile { position: relative; overflow: hidden; min-width: 0; min-height: var(--tile-h); display: flex; flex-direction: column; align-items: center;
  padding: var(--tile-pad) 14px 16px; text-align: center; background: linear-gradient(180deg, #393537, #121112); }
.tile-art { position: absolute; left: 0; top: 0; display: block; }
.tile::after { content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, rgba(1, 1, 1, .62) 0, rgba(1, 1, 1, .40) 40%, rgba(1, 1, 1, 0) 68%); }
.tile-text { position: relative; z-index: 2; display: flex; flex-direction: column; align-items: center; gap: 10px; max-width: 100%; }
.tile-kicker { font: 800 15px/1.25 var(--font-ui); letter-spacing: .14em; padding-left: .14em; text-transform: uppercase; color: #dec139; text-shadow: 2px 2px 0 #090706;
  text-wrap: balance; }   /* a kicker that must wrap (narrow phones) breaks into two even lines, never one lone word */
.tile-title { font-size: var(--tile-title); }
.tile-title .mat { display: block; width: max-content; max-width: 100%; margin: 0 auto .14em; }   /* the 2-line title */
/* tile titles are small (22-40px): a thinner outline, and the stone words drop the
   speck layer and the top-left highlight, which fill the 1-pixel letter holes
   (W turned into a block, WIN read like UIN). The big titles keep the full look. */
.strip .tile-title, .feature-title { --u: 2px; }
@media (max-width: 640px) { .strip .tile-title, .feature-title { --u: 1px; } }
.strip .tile-title .mat.stone, .feature-title .mat.stone {
  background-image: linear-gradient(180deg,
    #cabbb3 0 calc(var(--ct) + var(--ch) * .30),
    #b2a29c 0 calc(var(--ct) + var(--ch) * .58),
    #958883 0);
  background-size: 100% 1em;
  background-repeat: repeat-y;
  background-position: 0 0;
  filter:
    drop-shadow(0 calc(var(--o) * 2) 0 #4a4341)
    drop-shadow(var(--o) 0 0 #090706)
    drop-shadow(calc(var(--o) * -1) 0 0 #090706)
    drop-shadow(0 var(--o) 0 #090706)
    drop-shadow(0 calc(var(--o) * -1) 0 #090706);
}
/* ===== 05-main ===== */
/* =====================================================================
   05 - TWO COLUMNS, IP BAR, VOTE FEATURE CARD + VOTE CARD INTERNALS
   .cols = Lunar's two-column body (left 2fr: IP bar + the vote card as
   the big featured card; right 1fr: 06-side). The vote card internals
   (step badges, name input, watch screen, hotbar, reward line, key drop,
   Turnstile, result box) are kept unchanged from the old stylesheet.
   Elements that are also .frame / .frame-sm (.ip-bar, .vote-feature,
   #watch, #result) use background longhands or repeat
   background-clip: padding-box, so the notched corners stay see-through.
   No CSS width/height on .vote-art (art.js sizes it from .vote-banner).
   ===================================================================== */
.cols { max-width: var(--page-max); margin: 0 auto; padding: 40px var(--gutter) 32px; display: grid;   /* 32px down to the server row */
  grid-template-columns: minmax(0, 2fr) minmax(320px, 1fr); gap: 32px; align-items: start; }
.col-main, .col-side { min-width: 0; display: flex; flex-direction: column; gap: 24px; }

/* ---------- the slim IP bar (Lunar's partner bar); also .frame-sm 12px ---------- */
.ip-bar { display: flex; align-items: stretch; min-height: 72px; background-color: #121112; background-clip: padding-box; }
.ip-bar-block { flex: none; align-self: center; width: 40px; height: 40px; margin: 0 4px 0 16px;
  background: linear-gradient(180deg, #70b309 0 11px, #3e6106 11px 14px, #8e4f17 14px 28px, #63380e 28px); box-shadow: 0 0 0 3px #020200; }
.ip-bar-ip { flex: none; display: flex; flex-direction: column; justify-content: center; gap: 2px; padding: 8px 16px; }
.ip-bar-text { font: 800 22px/1.15 var(--font-ui); color: #fff; text-shadow: 2px 2px 0 #090706; white-space: nowrap; }
.ip-bar-line { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; padding: 8px 16px; font: 600 16px/1.4 var(--font-body); color: #EEE7E2; box-shadow: inset 3px 0 0 #393537; }
.ip-bar-btn { flex: none; min-width: 176px; font-size: 18px; }

/* ---------- the vote feature card (Lunar's big featured card) ---------- */
.vote-feature { position: relative; background-color: #0c0a07; background-clip: padding-box; }   /* .frame 18px */
.vote-banner { position: relative; overflow: hidden; min-height: 240px; display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 64px 72px 28px; text-align: center; background-color: #1e1c1d;
  background-image: linear-gradient(rgba(14, 13, 14, .80), rgba(14, 13, 14, .80)), var(--tex-ore-wall, var(--tex-stone, none));
  box-shadow: inset 0 -3px 0 #010101; }
.vote-art { position: absolute; left: 0; top: 0; display: block; }
.vote-banner::after { content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(ellipse 62% 72% at 50% 58%, rgba(1, 1, 1, .66) 0, rgba(1, 1, 1, .30) 62%, rgba(1, 1, 1, 0) 100%); }
.vote-banner-text { position: relative; z-index: 2; display: flex; flex-direction: column; align-items: center; gap: 12px; max-width: 100%; }
.vote-banner .title { font-size: clamp(30px, 3.6vw, 52px); }
/* Lunar's corner ribbon as a flat grass-block tab */
.ribbon { position: absolute; left: 0; top: 16px; z-index: 3; margin: 0; padding: 8px 16px 12px 14px; font: 800 15px/1 var(--font-ui); letter-spacing: .1em; text-transform: uppercase; color: #010101;
  background: linear-gradient(180deg, #70b309 0 calc(100% - 7px), #3e6106 calc(100% - 7px) calc(100% - 4px), #63380e calc(100% - 4px));
  box-shadow: 3px 0 0 #020200, 0 3px 0 #020200, 3px 3px 0 #020200; }
.vote-banner .sound { position: absolute; top: 14px; right: 14px; z-index: 3; margin: 3px; }

/* solid dark mine interior: no texture behind small text */
.vote-card { position: relative; padding: 24px 32px 32px; background: linear-gradient(180deg, #120d06 0, #0c0a07 240px), #0c0a07; }
.vote-sub { font-size: 16px; }

/* ---------- step badges + name input ---------- */
.step {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 24px 0 12px;
  font: 800 22px/1.1 var(--font-ui);
  text-transform: uppercase;
  letter-spacing: .02em;
  color: #EEE7E2;
  text-shadow: 2px 2px 0 #090706;
}
/* the number badge: a little stone block */
.num {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: var(--speck-stone, none) 0 0, #746a67;
  box-shadow: 0 0 0 3px #010101, inset 3px 3px 0 #958883, inset -3px -3px 0 #4a4341;
  font: 800 19px var(--font-ui);
  color: #fff;
  text-shadow: 2px 2px 0 #090706;
  image-rendering: pixelated;
}
/* step 1 found the name: the stone block turns into a grass block */
.step.done .num {
  background: linear-gradient(180deg, #70b309 0 10px, #3e6106 10px 13px, #8e4f17 13px);
  box-shadow: 0 0 0 3px #020200;
  padding-top: 8px;
  text-shadow: 2px 2px 0 #2a1a05;
  animation: slotPop .25s steps(4);
}
.name-row {
  display: flex;
  align-items: center;
  gap: 12px;
}
/* the player head sits in a recessed slot */
.head {
  flex: none;
  width: 56px;
  height: 56px;
  padding: 4px;
  background: #1e1c1d;
  box-shadow: inset 3px 3px 0 #010101, inset -3px -3px 0 #504b4d, 0 0 0 2px #010101;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
#name {
  flex: 1;
  min-width: 0;
  height: 56px;
  margin: 0;
  padding: 0 16px;
  font: 600 20px var(--font-body);   /* 20px: no iOS zoom on focus */
  color: #fff;
  caret-color: #70b309;
  background: #010101;
  border: 3px solid #746a67;
  border-radius: 0;
  box-shadow: inset 3px 3px 0 #121112;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}
#name::placeholder {
  color: #958883;
  opacity: 1;
  font-weight: 400;
  font-style: italic;
}
#name:focus {
  border-color: #70b309;
  box-shadow: inset 3px 3px 0 #121112, 0 0 0 3px #3e6106;
}
/* browser autofill would paint the box pale yellow/blue: keep it dark */
#name:-webkit-autofill {
  -webkit-text-fill-color: #fff;
  box-shadow: inset 3px 3px 0 #121112, inset 0 0 0 100px #010101;
}
#name:-webkit-autofill:focus {
  box-shadow: inset 3px 3px 0 #121112, inset 0 0 0 100px #010101, 0 0 0 3px #3e6106;
}

/* ---------- watch screen ---------- */
.stage {
  position: relative;
  height: 250px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  -webkit-user-select: none;
  user-select: none;
  background:
    radial-gradient(circle at 50% 55%, rgba(222, 193, 57, .14), transparent 60%),
    linear-gradient(rgba(1, 1, 1, .6), rgba(1, 1, 1, .6)),
    var(--tex-stone, none) 0 0,
    #1e1c1d;
  box-shadow: inset 3px 3px 0 #010101, inset -3px -3px 0 #504b4d;
}
.fx {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 2;
}
/* #watch also has .frame .frame-sm (12px logo frame from 01-base).
   Only background longhands here, plus padding-box clip, so the frame's
   notched corners stay see-through. */
.screen {
  position: relative;
  display: block;
  width: 320px;
  max-width: calc(100% - 32px);
  aspect-ratio: 16 / 9;
  margin: 0;
  padding: 0;
  overflow: hidden;
  cursor: pointer;
  background-color: #070809;
  background-clip: padding-box;
  box-shadow: 0 8px 0 rgba(1, 1, 1, .45);
  transition: transform .12s;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.screen-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* the play button: a grass block with a dark triangle */
.play {
  position: absolute;
  left: 50%;
  top: 44%;
  width: 80px;
  height: 80px;
  margin: -40px 0 0 -40px;
  background: linear-gradient(180deg, #70b309 0 calc(100% - 10px), #3e6106 calc(100% - 10px) calc(100% - 6px), #63380e calc(100% - 6px));
  box-shadow: 0 0 0 3px #010101, 0 0 0 9px rgba(112, 179, 9, .28), 0 6px 0 3px rgba(1, 1, 1, .5);
  transition: transform .1s;
}
.play::after {
  content: '';
  position: absolute;
  left: 30px;
  top: 20px;
  border-style: solid;
  border-width: 16px 0 16px 24px;
  border-color: transparent transparent transparent #010101;
}
/* refused click: the play block is swapped for the red barrier for 2s */
.barrier {
  display: none;
  position: absolute;
  left: 50%;
  top: 44%;
  width: 64px;
  height: 64px;
  margin: -32px 0 0 -32px;
  background: var(--tex-barrier, radial-gradient(closest-side, transparent 56%, #FF5555 57% 84%, #8a1f1f 85% 98%, transparent 99%)) 0 0 / 64px 64px no-repeat;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
.screen.denied .play {
  visibility: hidden;
}
.screen.denied .barrier {
  display: block;
}
/* label on a .72 black strip, never straight on the art */
.screen-label {
  position: absolute;
  inset: auto 0 0 0;
  display: block;
  padding: 8px 0;
  background: rgba(1, 1, 1, .72);
  font: 400 22px/1.2 var(--font-pixel);
  letter-spacing: .12em;
  text-transform: uppercase;
  text-align: center;
  color: #fff;
  text-shadow: 2px 2px 0 #090706;
}
@media (hover: hover) {
  .screen:hover .play { transform: translateY(-3px); }
  .screen.locked:hover .play { transform: none; }
}
.screen:active .play {
  transform: translateY(4px);
}
.screen.locked:active .play {
  transform: none;
}
.screen:focus-visible {
  outline: 3px solid #dec139;
  outline-offset: 4px;
}
.screen.locked {
  cursor: not-allowed;
}
/* grey out the art, never the frame */
.screen.locked .screen-art,
.screen.locked .play,
.screen.locked .screen-label {
  filter: grayscale(.85) brightness(.55);
}
.screen.busy {
  cursor: progress;
}
.screen.busy .play {
  animation: pulse 1s steps(2) infinite;
}
@keyframes pulse {
  50% { opacity: .7; }
}
.screen.shake {
  animation: shake .35s;
}
@keyframes shake {
  20%, 60% { transform: translateX(-8px); }
  40%, 80% { transform: translateX(8px); }
}

/* ---------- hotbar (today's ads) + reward line ---------- */
.today {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 16px;
  flex-wrap: wrap;
}
.hotbar {
  display: flex;
  flex-wrap: wrap;            /* only wraps if the server allows many ads a day */
  justify-content: center;
  gap: 4px;
  max-width: 100%;
}
.hotbar .slot {
  flex: none;
  display: block;
  width: 44px;
  height: 44px;
  background: #1e1c1d;
  box-shadow: inset 3px 3px 0 #010101, inset -3px -3px 0 #504b4d, 0 0 0 2px #010101;
}
/* a watched ad = an emerald in the slot */
.hotbar .slot.on {
  background: var(--tex-emerald, linear-gradient(#18D978 0 50%, #0e8a4a 50%)) center / 32px 32px no-repeat, #1e1c1d;
  image-rendering: pixelated;
  animation: slotPop .25s steps(4);
}
@keyframes slotPop {
  0% { transform: scale(.4); }
  60% { transform: scale(1.1); }
  100% { transform: scale(1); }
}
.today .kicker-sm {
  color: #EEE7E2;
}
.reward {
  margin-top: 10px;
  text-align: center;
  font: 700 17px/1.4 var(--font-body);
  color: #F2B94B;
  text-shadow: 1px 1px 0 #090706;
}
/* the gold key in front of the reward (fallback: a small gold bar) */
.reward::before {
  content: '';
  display: inline-block;
  width: 32px;
  height: 32px;
  margin-right: 8px;
  vertical-align: -9px;
  background: var(--tex-key, linear-gradient(transparent 10px, #F2B94B 10px 22px, transparent 22px)) 0 0 / 32px 32px no-repeat;
  image-rendering: pixelated;
}
.reward:empty {
  display: none;
}

/* ---------- key drop after a vote ---------- */
/* #drop is a 16x16 canvas: 80px = a crisp 5x */
.drop {
  position: absolute;
  width: 80px;
  height: 80px;
  left: 50%;
  top: 50%;
  margin: -40px 0 0 -40px;
  opacity: 0;
  pointer-events: none;
  z-index: 3;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
  filter: drop-shadow(0 0 18px rgba(222, 193, 57, .7));
}
.drop.show {
  animation: pop .5s ease-out forwards, float 2s ease-in-out .5s infinite;
}
@keyframes pop {
  0% { opacity: 0; transform: scale(.2) translateY(30px); }
  60% { opacity: 1; transform: scale(1.15) translateY(-14px); }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes float {
  0%, 100% { opacity: 1; transform: translateY(0) rotate(-4deg); }
  50% { opacity: 1; transform: translateY(-8px) rotate(4deg); }
}

/* ---------- Turnstile ---------- */
/* when Cloudflare shows its 300px box on a very narrow phone it overflows
   evenly on both sides (justify-content: center), never off one edge */
.turnstile {
  display: flex;
  justify-content: center;
  margin-top: 8px;
}
.turnstile:empty {
  margin: 0;
}

/* ---------- result box ---------- */
/* also .frame .frame-sm; the title is filled by richText (all grass) */
.result {
  margin-top: 16px;
  padding: 18px;
  text-align: center;
  background: #14100a;
  background-clip: padding-box;
  animation: pop .4s ease-out;
}
.result-title {
  margin-bottom: 10px;
  font-size: 40px;
}
.result-reward {
  font-weight: 700;
  color: #F2B94B;
  margin-bottom: 4px;
}
.result #result-line {
  color: #EEE7E2;
}
.result .muted {
  margin-top: 4px;
}

/* ---------- desktop: a bigger watch screen ---------- */
@media (min-width: 960px) { .stage { height: 290px; } .screen { width: 400px; } }
/* ===== 06-side ===== */
/* =====================================================================================
   06  SIDE COLUMN (Join us card, top voters: 3 picture cards #1-#3, rows #4-#10, notes)
   and the FULL-WIDTH SERVER ROW under the two columns (head | about | tags).
   Relies on 01-base for: tokens (fonts, --t), .frame / .frame-sm (border-image,
   background-clip: padding-box), .tuft, .btn*, .kicker, .kicker-sm, .muted, .title,
   .title-sm, .title-stack, .status-line. Phone / 359 rules live in 09-responsive.
   Every element here that is also .frame / .frame-sm gets longhands only (never the
   background shorthand) so the notched corners stay open. Every var(--tex-*) has a
   flat background-color under it.
   ===================================================================================== */

/* ---------- side cards (Join us) ---------- */
.side-card { position: relative; display: flex; flex-direction: column; gap: 12px; padding: 20px; background-color: #121112;
  background-image: linear-gradient(rgba(1, 1, 1, .78), rgba(1, 1, 1, .78)), var(--tex-stone, none); background-clip: padding-box; }   /* .frame-sm 12px */
.join-card { align-items: center; text-align: center; }
.join-line { font-size: 16px; }
.join-buttons { align-self: stretch; display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0 12px; }
.join-buttons .btn { width: calc(100% - 6px); padding: 0 12px; font-size: 18px; }

/* ---------- top voters: head + 3 stacked picture cards (Lunar's blog cards) ---------- */
.voters { display: flex; flex-direction: column; gap: 12px; }
.side-head { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 8px 0 4px; text-align: center; }
.side-head .title { font-size: clamp(28px, 2.6vw, 40px); }
.side-head .kicker { text-wrap: balance; }   /* "NOVEMBER · ENDS IN 24D 13H" wraps into two even lines, never one lone word */
.vcards { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.vcard { position: relative; overflow: hidden; min-height: 132px; display: flex; align-items: center; padding: 12px 124px 12px 16px;
  background-color: #121112; background-clip: padding-box;
  background-image: linear-gradient(90deg, rgba(18, 17, 18, .94) 0 45%, rgba(18, 17, 18, .50) 100%), var(--tex-ore-1, none); }
.vcard.p2 { background-image: linear-gradient(90deg, rgba(18, 17, 18, .94) 0 45%, rgba(18, 17, 18, .50) 100%), var(--tex-ore-2, none); }
.vcard.p3 { background-image: linear-gradient(90deg, rgba(18, 17, 18, .94) 0 45%, rgba(18, 17, 18, .50) 100%), var(--tex-ore-3, none); }
.vcard.free { background-image: linear-gradient(90deg, rgba(18, 17, 18, .94) 0 45%, rgba(18, 17, 18, .60) 100%), var(--tex-stone, none); }
.vcard-text { position: relative; z-index: 2; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.vcard-top { display: flex; align-items: center; gap: 10px; }
.vcard-badge { flex: none; padding: 4px 8px; font: 800 20px/1 var(--font-ui); color: #2a1a05; background: #F2B94B; box-shadow: 0 0 0 3px #090706, 0 3px 0 3px #b16a06; }
.vcard.p2 .vcard-badge { background: #18D978; box-shadow: 0 0 0 3px #090706, 0 3px 0 3px #0e8a4a; }
.vcard.p3 .vcard-badge { background: #78AFFF; box-shadow: 0 0 0 3px #090706, 0 3px 0 3px #4a76c2; }
.vcard.free .vcard-badge { background: #393537; color: #b2a29c; box-shadow: 0 0 0 3px #090706, 0 3px 0 3px #1e1c1d; }
.vcard-votes { font: 800 15px/1.2 var(--font-ui); letter-spacing: .06em; text-transform: uppercase; color: #cabbb3; text-shadow: 2px 2px 0 #090706; }
.vcard-name { font: 800 24px/1.15 var(--font-ui); color: #fff; text-shadow: 3px 3px 0 #090706; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vcard-prize { font: 600 15px/1.35 var(--font-body); color: #F2B94B; text-wrap: balance; }
/* the skin, cropped by the card: head and chest show, like Lunar's card pictures */
.vcard-body { position: absolute; right: 16px; top: 8px; z-index: 1; height: 196px; width: auto; max-width: none; pointer-events: none; filter: drop-shadow(4px 4px 0 rgba(1, 1, 1, .45)); }
.vcard.free .vcard-body { opacity: .35; filter: grayscale(1) brightness(.4); }

/* ---------- #4-#10 list rows + foot notes ----------
   padding 0 2px: the rows' 2px outer ring then ends exactly on the card frames above */
.list { list-style: none; max-width: none; margin: 0; padding: 0 2px; display: flex; flex-direction: column; gap: 8px; }
.list:empty { display: none; }
.list li {
  display: flex; align-items: center; gap: 14px; min-height: 56px; padding: 0 14px;
  background: #1e1c1d; box-shadow: 0 0 0 2px #010101, inset 0 3px 0 #393537, inset 0 -3px 0 #121112;
}
/* the rank: app.js writes it into a .lrank span (text from SITE.text.badge, like the #1-#3 cards) */
.list .lrank { flex: none; width: 40px; white-space: nowrap; font: 800 20px var(--font-ui); color: #b2a29c; text-shadow: 2px 2px 0 #090706; }
.list img { flex: none; display: block; width: 32px; height: 32px; image-rendering: pixelated; box-shadow: 0 0 0 2px #010101; }
.list .lname { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 800 20px var(--font-ui); color: #EEE7E2; text-shadow: 2px 2px 0 #090706; }
.list .lvotes { flex: none; white-space: nowrap; font: 800 18px var(--font-ui); color: #F2B94B; text-shadow: 2px 2px 0 #090706; }
.foot-note { text-align: center; color: #cabbb3; font-size: 15px; margin-top: 0; text-wrap: balance; }
.foot-note:empty { display: none; }
.empty {
  max-width: none; margin: 0; padding: 14px; text-align: center; color: #EEE7E2; font-size: 16px;
  background: #14100a; box-shadow: 0 0 0 3px #010101, inset 3px 3px 0 #393537;
}

/* ---------- the server row: ONE full-width card under the two columns (head | about | tags), stacked under 960 ---------- */
.server-wrap { max-width: var(--page-max); margin: 0 auto; padding: 0 var(--gutter) 72px; }
.server-card { display: grid; grid-template-columns: minmax(240px, 1fr) minmax(0, 1.5fr) minmax(0, 1.2fr); align-items: center; gap: 20px 40px; padding: 28px 32px;
  background-color: #121112; background-image: linear-gradient(rgba(1, 1, 1, .78), rgba(1, 1, 1, .78)), var(--tex-stone, none); background-clip: padding-box; }   /* .frame-sm 12px */
.server-head { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.server-card .title-stack { font-size: clamp(26px, 2.4vw, 36px); }
.server-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
.server-meta .kicker-sm:empty { display: none; }
.server-about, .server-card .tags { min-width: 0; }

/* about text + tags (kept from the old stylesheet; #about p now 16px) */
#about p { font-size: 16px; color: #EEE7E2; }
#about p + p { margin-top: 8px; }
.tags { display: flex; flex-wrap: wrap; gap: 8px; }
.tags span {
  font: 800 15px var(--font-ui); letter-spacing: .06em; text-transform: uppercase; color: #EEE7E2;
  padding: 8px 12px; background: #393537;
  box-shadow: 0 0 0 2px #010101, inset 0 3px 0 #504b4d, inset 0 -3px 0 #1e1c1d;
}

/* ---------- the "Server features" row: one card per feature, each with a small moving picture ----------
   Between the server row and the bottom banner, as wide as the page row. A card is a .frame-sm box of dark stone:
   the picture on top (features.js draws a 128 x 72 canvas, scaled up here with square pixels), then the title (the
   tiles' small-title look, see .strip .tile-title), one line and the command. 5 across on big screens, 3-4 on
   laptops, 2-3 on tablets; phones get one card per row with the picture on the left (09-responsive).
   The list and every word: SITE.features in texts.js. */
.features-wrap { max-width: var(--page-max); margin: 0 auto; padding: 0 var(--gutter) 72px; }
.features-head { display: flex; flex-direction: column; align-items: center; gap: 10px; margin-bottom: 28px; text-align: center; }
.feature-groups { display: flex; flex-direction: column; gap: 32px; }
.feature-group-name { margin: 0 0 14px; }
.features { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(232px, 1fr)); gap: 18px; }
.feature { min-width: 0; display: flex; flex-direction: column; background-color: #121112;
  background-image: linear-gradient(rgba(1, 1, 1, .78), rgba(1, 1, 1, .78)), var(--tex-stone, none); background-clip: padding-box; }   /* .frame-sm 12px */
.feature-art-wrap { line-height: 0; background: #070809; box-shadow: inset 0 -3px 0 #010101; }
.feature-art { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9;
  image-rendering: -moz-crisp-edges; image-rendering: crisp-edges; image-rendering: pixelated; }
.feature-text { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; padding: 14px 14px 16px; }
.feature-title { font-size: 20px; }
.feature-title .mat { margin: 0 .3em 0 0; }
.feature-line { margin: 0; font: 500 15px/1.4 var(--font-body); color: #EEE7E2; }
.feature-cmd { margin: auto 0 0; padding: 5px 9px; font: 800 14px/1 var(--font-ui); letter-spacing: .04em; color: #dec139;
  background: #1e1c1d; box-shadow: 0 0 0 2px #010101, inset 0 2px 0 #393537; }
/* ===== 07-cta-foot ===== */
/* =====================================================================================
   07  BOTTOM BANNER (CTA) + FOOTER (bedrock)
   The overlap trick: .cta-wrap is the last child of .ground (a flow-root, see 04-strip),
   so its negative bottom margin shortens .ground and the banner sticks out into the
   footer; z-index: 3 paints it above the footer, which has position: relative from
   .layer and no z-index (the footer's jagged .edge-4 sits behind the banner).
   Relies on 01-base for: tokens (--t, --page-max, --gutter, --cta-over, fonts), .frame,
   .btn*, .title, .layer / .layer-bedrock, .edge / .edge-4. Narrow-screen rules live in
   09-responsive. .cta is a .frame: longhands only, background-clip: padding-box kept.
   ===================================================================================== */

/* ---------- the banner: logo / text / VOTE NOW ---------- */
.cta-wrap { position: relative; z-index: 3; max-width: var(--page-max); margin: 0 auto calc(var(--cta-over) * -1); padding: 0 var(--gutter); }
.cta { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 32px; min-height: 200px; padding: 24px 40px;
  background-color: #2a1a05;
  background-image: linear-gradient(180deg, transparent 0 calc(var(--t) * 4), rgba(20, 12, 3, .70) calc(var(--t) * 4)), var(--tex-grass, none), var(--tex-dirt, none);
  background-repeat: no-repeat, repeat-x, repeat; background-size: 100% 100%, auto, auto; background-position: 0 0, 0 0, 0 0;
  background-clip: padding-box; box-shadow: 0 12px 0 rgba(1, 1, 1, .5); }   /* grass-block row on top (bright), washed dirt under the text */
.cta-logo { display: block; width: 128px; height: 128px; }
.cta-copy { min-width: 0; }
.title-cta { font-size: clamp(26px, 3vw, 44px); }
.cta-line { margin-top: 12px; font: 700 18px/1.4 var(--font-body); color: #EEE7E2; text-shadow: 2px 2px 0 #090706; text-wrap: balance; }
.cta-btn { min-width: 240px; }

/* ---------- footer: centred Discord / Store buttons, then logo + (c) + legal left, links right ---------- */
.foot { display: flex; flex-direction: column; align-items: center; gap: 40px; padding: calc(var(--cta-over) + 56px) var(--gutter) 40px; color: #958883; }
.foot-social { display: flex; flex-wrap: wrap; justify-content: center; gap: 0 16px; }
/* one row (brand left, links right) down to 641 px: the brand text shrinks and wraps, the links never drop under it */
.foot-bottom { width: 100%; max-width: calc(var(--page-max) - 80px); display: flex; flex-wrap: nowrap; align-items: center; justify-content: space-between; gap: 24px; }
.foot-brand { flex: 0 1 auto; min-width: 0; display: flex; align-items: center; gap: 14px; }
.foot-logo { display: block; flex: none; width: 64px; height: 64px; }
.foot-copy { font: 800 15px/1.3 var(--font-ui); color: #cabbb3; }
.foot-legal { max-width: 460px; font-size: 14px; line-height: 1.45; color: #958883; }
.foot-links { flex: none; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0 24px; }
.foot-links a { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 44px; font: 600 15px/1 var(--font-body); color: #cabbb3; }   /* 44 wide too: "Vote" is a short word */
.foot-links a:hover, .foot-links a:focus-visible, .foot-links a.is-active { color: #dec139; text-decoration: underline; text-decoration-color: #70b309; text-underline-offset: 4px; }
/* ===== 08-ad ===== */
/* =====================================================================
   08-ad  -  the house ad overlay #ad (z 50, above the header 30 and the
   drawer 40), kept verbatim from the old stylesheet. app.js opens it
   (removes [hidden], adds body.ad-open), fills the art / texts, runs the
   XP bar (#ad-fill width every 100 ms) and shows #ad-claim at the end.
   Relies on 01-base (.frame, .frame-sm, .btn*, .kicker*, .title) and on
   @keyframes pop in 05-main. Phone / short-screen sizes live in
   09-responsive, no-motion in 10-reduced-motion.
   ===================================================================== */

/* ---------- house ad overlay ---------- */
.ad {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(1, 1, 1, .88);
}
.ad[hidden] {
  display: none;
}
/* the dialog: logo frame (.frame) around dark stone (.78 black over the
   texture, so small text is allowed on it) */
.ad-box {
  position: relative;
  width: min(680px, 100%);
  max-height: 100%;
  overflow: auto;
  overscroll-behavior: contain;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  background: linear-gradient(rgba(1, 1, 1, .78), rgba(1, 1, 1, .78)), var(--tex-stone, none) 0 0, #121112;
  background-clip: padding-box;
  scrollbar-color: #504b4d #121112;
  scrollbar-width: thin;
  animation: adIn .3s ease-out;
}
.ad-box > * {
  flex-shrink: 0;             /* scroll the box instead of squashing the parts */
}
.ad-box:focus {
  outline: none;
}
@keyframes adIn {
  from { opacity: 0; transform: translateY(20px); }
}
.ad-top {
  display: flex;
  align-items: center;
  gap: 12px;
}
.ad-tag {
  flex: none;
  font: 800 14px var(--font-ui);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #2a1a05;
  background: #dec139;
  padding: 4px 10px;
  box-shadow: 0 0 0 3px #090706, 0 3px 0 3px #b16a06;
}
.ad-top .kicker-sm {
  margin-left: auto;
  min-width: 0;
  text-align: right;
  color: #EEE7E2;
}
/* .btn .btn-stone .btn-square (44px) from 01-base */
.ad-close {
  margin: 3px 3px 10px;
}
/* the art sits in its own small logo frame */
.ad-art-wrap {
  line-height: 0;
  background-color: #0c0a07;
  background-clip: padding-box;
}
.ad-art {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 7;
  image-rendering: -moz-crisp-edges;
  image-rendering: crisp-edges;
  image-rendering: pixelated;
}
.ad-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}
.ad-title {
  max-width: 100%;
}
.ad-text .btn {
  margin-top: 6px;
}
/* XP-style countdown bar */
.ad-bar {
  height: 16px;
  padding: 4px;
  background: #010101;
  box-shadow: inset 0 0 0 2px #010101, inset 0 0 0 4px #1e1c1d;
}
.ad-bar span {
  display: block;
  height: 100%;
  width: 0;
  background:
    repeating-linear-gradient(90deg, transparent 0 16px, #2f6102 16px 18px),
    linear-gradient(180deg, #70b309 0 calc(100% - 3px), #3e6106 calc(100% - 3px));
  transition: width .1s linear;   /* JS sets the width every 100ms */
}
.ad-claim {
  align-self: center;
  animation: pop .4s ease-out;
}
body.ad-open {
  overflow: hidden;
}
/* ===== 09-responsive ===== */
/* Breakpoints: default = desktop; >= 1280 big desktop; 960-1279 small desktop; <= 959 one body column;
   <= 899 header status hidden, strip 2x2, CTA 2 rows; <= 767 header row 2 hidden; <= 640 phones;
   <= 479 strip 1-column stack; <= 374 header MENU word hidden; <= 359 320 phones.
   The layout-token overrides (--gutter, --nav-*, --strip-over, --cta-over) live here, 767 before 640. */

@media (min-width: 1280px) { :root { --strip-over: 160px; } .strip { --tile-h: 360px; --tile-pad: 56px; --tile-title: 40px; } }
/* small desktop (1024x768): the left column is only ~590 px, so the IP bar drops its sentence and keeps one slim row */
@media (min-width: 960px) and (max-width: 1279px) { .ip-bar-line { display: none; } .ip-bar-btn { margin-left: auto; } }
/* 4 tiles across below 1280: a tile is only ~175-200 px wide, so the kicker gets a little tighter to stay on one line */
@media (min-width: 900px) and (max-width: 1279px) {
  .tile { padding-left: 10px; padding-right: 10px; }
  .tile-kicker { font-size: 14px; letter-spacing: .08em; padding-left: .08em; }
}
@media (min-width: 900px) { .hero-meta .status-line { display: none; } }          /* status is in the header there */
/* two columns: the IP bar shows above the vote card (in the HTML it comes after it, so on
   phones the Tab order and the picture match: vote card first, then the IP bar) */
@media (min-width: 960px) { .ip-bar { order: -1; } }
@media (max-width: 959px) {
  :root { --gutter: 24px; }
  /* 720 px of content (plus the gutters), the same width as the strip and the bottom banner above / below */
  .cols { grid-template-columns: minmax(0, 1fr); max-width: calc(720px + 2 * var(--gutter)); gap: 24px; }
  .server-wrap { max-width: calc(720px + 2 * var(--gutter)); }
  .server-card { grid-template-columns: minmax(0, 1fr); gap: 16px; padding: 24px; }
}
@media (max-width: 899px) {
  :root { --strip-over: 112px; --cta-over: 80px; }
  .nav-status { display: none; }
  .nav-vote { min-width: 200px; padding-left: 24px; padding-right: 24px; font-size: 20px; }
  .nav-sub { gap: 24px; }
  .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .strip { --tile-h: 232px; --tile-pad: 32px; --tile-title: 28px; }
  .cta { grid-template-columns: auto minmax(0, 1fr); }
  .cta-btn { grid-column: 1 / -1; justify-self: center; }
}
@media (max-width: 767px) { :root { --nav-sub-h: 0px; --nav-full: 80px; } .nav-sub { display: none; } }
@media (max-width: 640px) {
  :root { --nav-h: 72px; --nav-full: 72px; --gutter: 16px; --strip-over: 48px; --cta-over: 56px; }
  /* phone sizes: smaller kicker, the 12px frame, a smaller big button, thinner title outlines */
  .kicker { font-size: 16px; }
  .frame { border-width: 12px; border-image: var(--frame-2) 12 / 12px repeat; }
  .frame > .tuft { top: -24px; }
  .btn-lg { min-height: 56px; font-size: 22px; }
  .title { --u: 2px; }
  /* header */
  .nav-main { padding-left: 16px; }
  .brand-word { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .nav-vote { min-width: 0; padding-left: 16px; padding-right: 16px; font-size: 18px; }
  /* the MENU word stays (easier than the icon alone for young players); hidden only under 375 */
  .nav-menu { min-width: 56px; justify-content: center; gap: 8px; padding: 0 16px; font-size: 18px; }
  /* hero: the kicker lies over the busy scene, so it gets the same dark nameplate as .hero-meta (03-hero) */
  .hero-kicker { background: rgba(1, 1, 1, .72); box-shadow: 0 0 0 2px #010101; padding: 4px 10px; width: fit-content; margin-left: auto; margin-right: auto; }
  .hero-kicker { padding-left: calc(10px + .2em); }                              /* keeps its .2em left padding (letter-spacing balance) */
  /* the hero is as tall as its content (not a full screen), so the first tile peeks above the fold */
  .hero { min-height: 0; }
  .hero-buttons { flex-direction: column; align-items: center; width: min(358px, 100%); }
  .hero-buttons .btn { width: calc(100% - 6px); min-width: 0; min-height: 64px; }
  /* strip */
  .strip { --tile-h: 220px; --tile-pad: 24px; --tile-title: 24px; }
  /* main */
  .ip-bar { flex-direction: column; align-items: stretch; text-align: center; }
  .ip-bar-block { display: none; }
  .ip-bar-ip { align-items: center; padding: 12px 12px 6px; }
  .ip-bar-line { justify-content: center; padding: 6px 12px 12px; box-shadow: none; }
  .ip-bar-btn { min-height: 56px; }
  .vote-banner { min-height: 0; padding: 76px 16px 20px; }                       /* 76: the kicker starts under the ribbon + sound button row */
  .vote-card { padding: 16px; }
  .side-card, .server-card { padding: 16px; }
  .vcard { min-height: 120px; padding: 10px 104px 10px 12px; }
  .vcard-body { right: 12px; height: 168px; }
  .vcard-name { font-size: 20px; }
  /* CTA + footer */
  .cta { grid-template-columns: minmax(0, 1fr); justify-items: center; gap: 16px; padding: 20px 16px; text-align: center; }
  .cta-logo { width: 64px; height: 64px; }
  .cta-btn { grid-column: auto; width: calc(100% - 6px); min-width: 0; }
  .foot-bottom { flex-direction: column; flex-wrap: wrap; text-align: center; }
  .foot-brand { flex-direction: column; }
  .foot-links { flex: 0 1 auto; justify-content: center; }
}
/* phones <= 479: the strip becomes a 1-column stack (text left, picture right). Must come AFTER the 899 and 640
   rules, otherwise the 899 rule's 2 columns would win */
@media (max-width: 479px) {
  .strip { --tile-h: 120px; --tile-pad: 0px; --tile-title: 22px; }
  .tiles { grid-template-columns: minmax(0, 1fr); }
  .tile { align-items: flex-start; justify-content: center; padding: 12px 16px; text-align: left; }
  .tile::after { background: linear-gradient(90deg, rgba(1, 1, 1, .70) 0, rgba(1, 1, 1, .45) 55%, rgba(1, 1, 1, 0) 82%); }
  .tile-text { align-items: flex-start; gap: 6px; max-width: 66%; }
  .tile-kicker { padding-left: 0; letter-spacing: .1em; }
  .tile-title .mat { display: inline-block; width: auto; margin: 0 .12em 0 0; }
}
@media (max-width: 374px) {
  .nav-menu-label { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
@media (max-width: 359px) {
  .btn { white-space: normal; line-height: 1.05; }
  .nav-vote { padding-left: 12px; padding-right: 12px; font-size: 16px; }
  .vcard-name { font-size: 18px; }
  .vote-banner .kicker { font-size: 14px; letter-spacing: .08em; }              /* "FREE REWARDS EVERY DAY" on one line */
  /* footer: Discord + Store side by side, and the 4 links as an even 2 x 2 (not 3 + 1) */
  .foot-social { gap: 0 8px; }
  .foot-social .btn { padding-left: 12px; padding-right: 12px; }
  .foot-links { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
}

/* ---------- vote card + house ad on phones / 320 / short screens ---------- */
/* ---------- phones ---------- */
@media (max-width: 640px) {
  .step { font-size: 18px; }   /* 18 (was 20): "YOUR MINECRAFT NAME" stays on one line at 390 inside the framed card */
  .head { width: 52px; height: 52px; padding: 2px; }

  .stage { height: 220px; }
  /* 8px each side keeps room for the focus ring inside the stage */
  .screen { width: 280px; max-width: calc(100% - 16px); }
  /* the 16:9 screen is short here: centre the play block (and the
     barrier) in the space above the 36px label so they never overlap */
  .screen-label { padding: 6px 0; line-height: 1.1; }
  .play { top: calc((100% - 36px) / 2); width: 72px; height: 72px; margin: -36px 0 0 -36px; }
  .play::after { left: 26px; top: 17px; border-width: 15px 0 15px 22px; }
  .barrier { top: calc((100% - 36px) / 2); }
  .hotbar .slot { width: 40px; height: 40px; }

  .result-title { font-size: 32px; }

  .ad { padding: 12px; }
  .ad-box { padding: 12px; }
  .ad-art { aspect-ratio: 16 / 9; }
  .ad-text .btn,
  .ad-claim {
    align-self: stretch;
    white-space: normal;
    text-align: center;
  }
}
/* 320px-wide phones: an even shorter screen, so a smaller play block
   and a 30px label */
@media (max-width: 359px) {
  .screen-label { font-size: 18px; padding: 5px 0; }
  .play { top: calc((100% - 30px) / 2); width: 60px; height: 60px; margin: -30px 0 0 -30px; }
  .play::after { left: 22px; top: 14px; border-width: 12px 0 12px 18px; }
  .barrier { top: calc((100% - 30px) / 2); }
}
/* short screens: keep the ad's reward button in view without scrolling
   (375x667 fits exactly with the 12px gap); the hero kicker sits a little closer to the smaller logo */
@media (max-height: 680px) {
  .ad-box { gap: 12px; }
  .hero-kicker { margin-top: 18px; }
}
/* 600 px tall or less (the 320x568 phone, phones turned sideways): a smaller picture and no one-line text
   under the title (#ad-line), so the whole end screen fits: 511 of 544 px at 320x568 (measured 2026-11-08) */
@media (max-height: 600px) {
  .ad-box { gap: 10px; }
  .ad-art { max-height: 20vh; }
  #ad-line { display: none; }
}

/* ---------- #4-#10 list rows on phones / 320 ---------- */
@media (max-width: 640px) {
  .list li { min-height: 52px; }
}
@media (max-width: 359px) {
  .list li { gap: 10px; padding: 0 10px; }
  .list .lrank { width: 36px; }
}

/* ---------- feature cards on phones: one per row, the picture on the left, the words on the right ---------- */
@media (max-width: 559px) {
  .feature-groups { gap: 24px; }
  .features { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .feature { flex-direction: row; }
  .feature-art-wrap { flex: 0 0 46%; display: flex; align-items: center; box-shadow: inset -3px 0 0 #010101; }
  .feature-text { gap: 6px; padding: 10px 12px; }
  .feature-title { font-size: 18px; }
  .feature-line { font-size: 14px; line-height: 1.35; }
  .feature-cmd { font-size: 13px; padding: 4px 7px; }
}
/* ===== 10-reduced-motion ===== */
/* =====================================================================
   10-reduced-motion  -  last part, so it wins over 01-09: no parallax,
   no drawer slide, no torch flicker, no reveal fades, no button / vote /
   ad animations. The !important on .hero-inner beats the inline
   transform / opacity the hero parallax writes.
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .btn, .block-btn, .nav, .nav-vote { transition: none; }
  .drawer-panel { animation: none; }
  .torch-glow { animation: none; opacity: 1; }
  .hero-inner { transform: none !important; opacity: 1 !important; will-change: auto; }
  /* the hero reel: no caption slide-in, no video fade (app.js keeps the still scene or one frozen reel frame) */
  .hero-caption.swap { animation: none; }
  .hero-video { transition: none; }
  /* the vote card + house ad (kept from the old stylesheet) */
  .drop.show,
  .screen.busy .play,
  .ad-box,
  .ad-claim,
  .result,
  .hotbar .slot.on,
  .step.done .num {
    animation: none;
    opacity: 1;
  }
  .screen.shake { animation: none; }
  .screen,
  .play,
  .ad-bar span { transition: none; }
}
