/* The Adventures of Happyweed! — site chrome. Desktop-only by design.
   Theme: weed greens, with accents strobing through the AUTHENTIC in-game
   super-drug flash cycle — CLUT slot 140 across phase palettes 128..132
   (assets/super_drug/famcap/clut_F128..132.txt): lime, pink, green, white,
   purple. Hard steps, like the real palette flash — never a fade.
   The hero keeps the game's main-menu blue (0,0,255) so the original PICT
   art blends seamlessly. */

:root {
  --nav-h: 51px;
  --menu-blue: #0000ff;
  --page-bg: #060f06;
  --panel-bg: #0c180c;
  --panel-edge: #1d3a1d;
  --ink: #e4f0e4;
  --ink-dim: #93b093;
  --accent: #00e060;
  --link: #7fdd9f;
  /* the super-drug flash cycle, phases 128..132 */
  --sd-1: #ccff66;
  --sd-2: #ff99ff;
  --sd-3: #00ff33;
  --sd-4: #ffffff;
  --sd-5: #6633ff;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background-color: var(--page-bg);
  color: var(--ink);
  font-family: Verdana, Geneva, Tahoma, sans-serif;
  font-size: 16px;
  line-height: 1.6;
}

/* Live-simulation background — a self-playing Happyweed level generated
   CLIENT-SIDE on every load (random level set 1-1000, random level 3-21;
   static/maze-gen.js + static/maze-sim.js): the bot moves off, fires its
   starting super drug (arming the game's real palette-flash cadence), eats
   cops, exits, and chains straight into the next random level (no bonus
   screen). Rendered through the game's own per-unit baked-phase model
   (RenderState): one device-index spritesheet per pltt family
   (static/game-data/tiles_F128..132.png) + a CLUT swap
   (static/game-data/cluts.json), never a stored per-maze PNG — see
   static/maze-bg.js. */
#maze-bg-wrap {
  position: fixed;
  top: var(--nav-h); /* Starts underneath the topnav */
  left: 0;
  right: 0;
  bottom: 0;
  background: #000;
  pointer-events: none;
  z-index: 0;
}

/* The maze grid is a fixed 20x12 (5:3) tile grid — object-fit:contain keeps
   every tile perfectly square (letterboxing into the page background on
   window shapes the --nav-h fit (index.html inline script) can't fully
   absorb) instead of stretching tiles into rectangles. Opacity lives on the
   canvas itself (not the wrap) so the letterbox bars stay solid black
   instead of fading toward the page background. */
#maze-bg {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0.35;
}

main {
  position: relative;
  z-index: 1;
  max-width: 860px;
  margin: 0 auto;
  padding: 0 16px 32px;
}

/* The super-drug palette flash — hard color steps, no fades */

@keyframes sd-strobe {
  0%, 19.99%  { color: var(--sd-1); }
  20%, 39.99% { color: var(--sd-2); }
  40%, 59.99% { color: var(--sd-3); }
  60%, 79.99% { color: var(--sd-4); }
  80%, 100%   { color: var(--sd-5); }
}

@keyframes sd-strobe-border {
  0%, 19.99%  { border-color: var(--sd-1); }
  20%, 39.99% { border-color: var(--sd-2); }
  40%, 59.99% { border-color: var(--sd-3); }
  60%, 79.99% { border-color: var(--sd-4); }
  80%, 100%   { border-color: var(--sd-5); }
}

@keyframes sd-strobe-glow {
  0%, 19.99%  { box-shadow: 3px 3px 0 #000, 0 0 18px var(--sd-1); }
  20%, 39.99% { box-shadow: 3px 3px 0 #000, 0 0 18px var(--sd-2); }
  40%, 59.99% { box-shadow: 3px 3px 0 #000, 0 0 18px var(--sd-3); }
  60%, 79.99% { box-shadow: 3px 3px 0 #000, 0 0 18px var(--sd-4); }
  80%, 100%   { box-shadow: 3px 3px 0 #000, 0 0 18px var(--sd-5); }
}

/* Top nav tabs */

.topnav {
  position: sticky;
  top: 0;
  z-index: 10;
  height: var(--nav-h);
  display: flex;
  align-items: stretch;
  gap: 16px;
  background: #030903;
  border-bottom: 3px solid var(--accent);
  padding: 0 20px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--accent);
  font-weight: bold;
  font-size: 18px;
  text-decoration: none;
  margin-right: 8px;
}

.brand img { image-rendering: pixelated; }

.topnav nav { display: flex; gap: 4px; }

.topnav nav a {
  display: flex;
  align-items: center;
  color: var(--ink);
  text-decoration: none;
  font-weight: bold;
  font-size: 14px;
  padding: 0 16px;
  border-radius: 8px 8px 0 0;
}

.topnav nav a:hover { background: rgba(0, 224, 96, 0.22); }

.topnav nav a.active {
  background: var(--accent);
  color: #032;
}

/* Hero — game title screen layout: plant left, wordmark top-right, buttons
   below. Mirrors the ROM's DLOG-128 proportions (640x450 canvas with
   PICT 128 at the left, PICT 129 top-right, 9 buttons lower-right). */

.hero {
  background: var(--menu-blue);
  border: 4px solid #000;
  border-radius: 12px;
  padding: 0;
  overflow: hidden;
  width: 100%;
  /* Match the game's 640:450 = ~1.42:1 aspect ratio */
  max-width: 580px;
  margin-left: auto;
  margin-right: auto;
}

/* Plant + wordmark placed at the ROM's exact DITL-128 coordinates (proc237),
   expressed as percentages of the 640x450 native canvas: plant at
   (22,36) 314x350, wordmark at (276,13) 280x220. */
.hero-art {
  position: relative;
  width: 100%;
  aspect-ratio: 640 / 450;
}

.hero-art img {
  position: absolute;
  image-rendering: auto;
}

.hero-plant {
  left: 3.4375%;
  top: 8%;
  width: 49.0625%;
  height: 77.7778%;
}

.hero-wordmark {
  left: 43.125%;
  top: 2.8889%;
  width: 43.75%;
  height: 48.8889%;
}

/* Buttons live INSIDE the art area, in the empty lower-right quadrant the
   ROM's own button grid occupies (DITL rects span x 367-600, y 257-375 of
   640x450 -> ~57-94% / ~57-83%) — reclaims the open space instead of adding
   a separate row below the box. */
.hero-cta {
  position: absolute;
  left: 55%;
  right: 6%;
  top: 54%;
  bottom: 6%;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 10px;
}

.cta-row {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.hero-cta .btn {
  text-align: center;
  padding: 9px 12px;
  font-size: 13px;
}

.hero-cta .release-note {
  text-align: center;
}

.btn {
  display: inline-block;
  padding: 10px 24px;
  border: 3px solid #000;
  border-radius: 10px;
  font-weight: bold;
  font-size: 14px;
  text-decoration: none;
  color: #000;
  box-shadow: 3px 3px 0 #000;
}

.btn:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 #000; }

.btn-play { background: var(--accent); }
.btn-download { background: #fff; }

/* Hero CTAs glow together — scoped here (not on .btn-download itself) so
   the play-page size/fullscreen buttons, which also use .btn-download,
   stay flat. */
.cta-row .btn-play, .cta-row .btn-download {
  animation: sd-strobe-glow 8s steps(1) infinite;
}

.release-note {
  color: #cfe0ff;
  font-size: 12px;
  margin: 0;
  min-height: 1em;
}

/* Content panels */

.panel {
  background: var(--panel-bg);
  border: 1px solid var(--panel-edge);
  border-radius: 12px;
  margin-top: 24px;
  padding: 8px 28px 20px;
}

/* download.html's exe button is the page's sole primary action, so it
   takes the brand accent instead of the neutral white used for secondary
   CTAs elsewhere (e.g. the homepage hero, where Play is already accent
   and Download is deliberately the secondary white). */
.no-strobe .btn-download {
  background: var(--accent);
}

/* download.html's page background goes pure black (instead of the shared
   near-black dark green --page-bg) so --panel-bg reads as a distinct
   panel against it rather than blending in. Scoped to this page only.
   The black is tiled with the leaf mark at low opacity via ::before
   (rather than directly on background-image) so the tint doesn't wash
   out the panel/nav that sit on top of it. static/leaf.png's own leaf
   artwork fills ~70% of its 256x256 canvas; static/leaf-tile.png is the
   same leaf re-padded onto a 210x210 transparent square (bbox ~15,12 of
   210) so it fills ~85%/88% (w/h) of the tile — sized to match the
   in-game leaf pickup sprite's own on-screen fill ratio within its maze
   cell (measured ~86%/95%), not just the tile PITCH, since an earlier
   pass matched pitch alone (58% fill) and visibly read as smaller than
   the homepage's leaves at the same on-screen cell size. Adjacent tiles
   still keep a clear gap at this ratio (the leaf shape's own corners are
   empty), so it doesn't read as touching/cramped.
   Tile size matches the homepage's live maze background's ACTUAL
   on-screen cell size, not the underlying sprite's native resolution.
   The homepage draws its 20x12 grid onto a canvas at the native 128px/
   cell sprite resolution (2560x1536 total — static/game-data/
   tiles-manifest.json's tile_size), then CSS object-fit:contain (see
   #maze-bg in this file) scales that canvas DOWN to fit the viewport
   below the nav bar, so the cell size a visitor actually SEES is
   128px * (that fit scale) — which shrinks as the fit scale shrinks,
   and is nowhere near 128px at ordinary window sizes. Measured directly
   with Playwright (render index.html, mark a real native 128x128 tile
   on the live canvas, screenshot, pixel-measure the mark's on-screen
   size) across common desktop viewports: it runs from ~57px at
   1280x720 up to ~116px at 2560x1440 — roughly 0.045x the viewport
   width for ordinary >=16:9 windows, jumping to ~0.05x the width for
   the rare window shapes close enough to the grid's own 5:3 aspect
   that object-fit:contain applies no letterboxing at all. That's too
   much swing across realistic desktop widths for one static number, so
   this page computes it live: static/leaf-tile-fit.js reproduces the
   SAME math (nav-fit.js's navH solve + the object-fit:contain scale
   formula) against the download page's own window size and writes the
   result into --leaf-tile-size, recomputed on resize.
   The tiling is anchored (not centered) to the homepage maze grid — a
   full tile row boundary at the nav bottom (top:var(--nav-h)), columns
   centered like the maze's pillarbox — so navigating between the two
   pages the leaf grid lands on the same lattice, just extended past the
   maze's letterbox to fill the whole viewport. See the ::before rule. */
body.page-download {
  background-color: #000;
  position: relative;
}

body.page-download::before {
  content: "";
  position: fixed;
  inset: 0;
  background-image: url("static/leaf-tile.png");
  background-size: var(--leaf-tile-size, 80px) var(--leaf-tile-size, 80px);
  /* Anchor the tiling to the homepage maze grid: a full tile row boundary
     starts at the nav bottom (the maze's row 0 sits at top:var(--nav-h)), so
     full leaves begin right under the nav instead of a centered partial row,
     and the columns stay horizontally centered like the maze's pillarbox.
     The grid then extends past the maze's letterboxed area to fill the whole
     viewport in every direction. */
  background-position: center var(--nav-h);
  background-repeat: repeat;
  opacity: 0.1;
  z-index: 0;
  pointer-events: none;
}

.page-download .topnav,
.page-download main {
  position: relative;
  z-index: 1;
}

/* about.html: the same tiled-watermark mechanic as download.html above, but
   over a random ROM wall tile (cicn 201-220 + 255) instead of the leaf —
   picked fresh per page load by static/wall-tile-bg.js, which sets
   --tile-bg-image; static/leaf-tile-fit.js supplies the shared
   --leaf-tile-size (page-agnostic despite the name). Page background color
   is left at the shared --page-bg, unlike download.html's black. */
body.page-about {
  position: relative;
}

body.page-about::before {
  content: "";
  position: fixed;
  inset: 0;
  background-image: var(--tile-bg-image, url("static/leaf-tile.png"));
  background-size: var(--leaf-tile-size, 80px) var(--leaf-tile-size, 80px);
  background-position: center var(--nav-h);
  background-repeat: repeat;
  opacity: 0.35;
  z-index: 0;
  pointer-events: none;
}

.page-about .topnav,
.page-about main {
  position: relative;
  z-index: 1;
}

/* The panel used to sit anchored near the top of a mostly-empty page at
   any reasonably tall viewport; centering it in the remaining viewport
   height gives it actual presence instead of reading as adrift above a
   dead black expanse. Widening the content column (860px -> 1120px, this
   page only: the shared main{max-width:860px} elsewhere is untouched)
   gives the fine-print lines enough room to stop wrapping to a second
   line at ordinary desktop widths. 1120px (not 1040px) accounts for the
   larger icon/gap/padding and the bigger fine-print text size the
   download-panel scale-up added. */
.page-download main {
  max-width: 1120px;
  min-height: calc(100vh - var(--nav-h));
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Neutralize the shared .panel's stacking margin now that main centers
   its one child directly — otherwise it nudges the panel off-center. */
.page-download .panel {
  margin-top: 0;
}

/* download.html's single panel: app icon beside the CTA instead of a bare
   text panel, and the "prefer not to download" path demoted to a plain
   footnote (not a competing bubble). No heading — the icon + button
   already say what this is and what to do.
   Scaled up from the shared .panel/.btn/.fine defaults (icon 108->168,
   gap 28->40, button + fine print a size step larger) so the page's one
   piece of content reads as a deliberate card instead of a thin bar lost
   in the surrounding black on large screens: the box's own content was
   the only thing making it look adrift, not the empty space around it. */
.download-panel {
  display: flex;
  align-items: center;
  gap: 40px;
  padding: 16px 40px 30px;
}

.download-panel .icon {
  width: 168px;
  height: 168px;
  flex: 0 0 auto;
}

.download-panel .content {
  flex: 1 1 auto;
  min-width: 0;
}

.download-panel .btn {
  padding: 15px 34px;
  font-size: 18px;
}

.download-panel .fine {
  font-size: 16px;
}

@media (max-width: 560px) {
  .download-panel { flex-direction: column; text-align: center; }
}

h2 {
  font-size: 20px;
  animation: sd-strobe 8s steps(1) infinite;
}

/* Download page opts out of the strobe (steady ink instead) */
.no-strobe h2 {
  animation: none;
  color: var(--ink);
}

/* About page headers stay steady accent green instead of the download
   page's plain ink */
.page-about h2 {
  color: var(--accent);
}

.panel a { color: var(--link); }
.panel a.btn { color: #000; }

.panel ul {
  list-style: none;
  padding-left: 6px;
}

.panel li {
  margin: 8px 0;
  padding-left: 30px;
  background: url("static/leaf-bullet.png") no-repeat 0 3px;
  background-size: 20px 20px;
}

code {
  background: #000;
  border-radius: 4px;
  padding: 1px 6px;
  font-size: 14px;
}

.fine { color: var(--ink-dim); font-size: 14px; min-height: 1em; }

pre {
  background: #000;
  border-radius: 8px;
  padding: 14px 18px;
  overflow-x: auto;
  font-size: 14px;
}

/* Leaderboard */

.board-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.board-head img {
  border-radius: 10px;
  border: 2px solid #000;
  background: #000;
  animation: sd-strobe-border 8s steps(1) infinite;
}

.board-head h2 {
  font-size: 28px;
  margin: 4px 0 0;
  text-align: center;
}

/* Leaderboard scope tabs (Port / All-Time) */
.scope-tabs {
  display: flex;
  justify-content: center;
  gap: 4px;
  margin: 16px 0 8px;
}

.scope-tab {
  padding: 8px 24px;
  border: 2px solid var(--panel-edge);
  border-radius: 8px 8px 0 0;
  background: transparent;
  color: var(--ink-dim);
  font-weight: bold;
  font-size: 14px;
  cursor: pointer;
  border-bottom: 2px solid var(--panel-edge);
  transition: background 0.15s, color 0.15s;
}

.scope-tab:hover {
  background: #10240f;
  color: var(--ink);
}

.scope-tab.active {
  background: var(--accent);
  color: #032;
  border-color: var(--accent);
  border-bottom-color: transparent;
}

/* View toggle (All Scores / Top Scores) */
.view-toggle {
  display: flex;
  justify-content: center;
  gap: 0;
  margin: 8px 0 12px;
}

.view-btn {
  padding: 6px 20px;
  border: 2px solid var(--panel-edge);
  background: transparent;
  color: var(--ink-dim);
  font-size: 13px;
  font-weight: bold;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}

.view-btn:first-child {
  border-radius: 6px 0 0 6px;
  border-right: 1px solid var(--panel-edge);
}

.view-btn:last-child {
  border-radius: 0 6px 6px 0;
  border-left: 1px solid var(--panel-edge);
}

.view-btn:hover {
  background: #10240f;
  color: var(--ink);
}

.view-btn.active {
  background: var(--accent);
  color: #032;
  border-color: var(--accent);
}

/* Scrolls the board itself (like the game's own ~12-row Scrollbar widget)
   instead of growing the whole page with up to 100 rows. */
.board-scroll {
  max-height: 480px;
  overflow-y: auto;
  margin-top: 10px;
  scrollbar-color: var(--panel-edge) var(--panel-bg);
}

.board-scroll::-webkit-scrollbar { width: 10px; }
.board-scroll::-webkit-scrollbar-track { background: var(--panel-bg); }
.board-scroll::-webkit-scrollbar-thumb {
  background: var(--panel-edge);
  border-radius: 6px;
}
.board-scroll::-webkit-scrollbar-thumb:hover { background: var(--accent); }

.board {
  width: 100%;
  border-collapse: collapse;
  font-size: 15px;
}

.board th, .board td {
  padding: 8px 12px;
  text-align: left;
  white-space: nowrap;
}

.board th {
  color: var(--accent);
  background: var(--panel-bg);
  border-bottom: 2px solid var(--panel-edge);
  position: sticky;
  top: 0;
}

.board .num { text-align: right; }

.board tbody tr:nth-child(even) { background: #091309; }

.board tbody tr:first-child td { color: #ffd24a; font-weight: bold; }

.board-status { color: var(--ink-dim); text-align: center !important; padding: 24px 0 !important; }

footer {
  text-align: center;
  color: var(--ink-dim);
  font-size: 13px;
  padding: 24px 0 40px;
}

footer a { color: var(--link); }
