/* The browser client's loading screen — one button, on Minecraft's dirt.
 *
 * **The job is to get the player to press Play and nothing else** (owner,
 * 2026-08-16). This screen briefly had the game's logo, a vanilla splash line
 * and a version stamp, all of which matched the main menu exactly; the owner's
 * call was that a loading screen is not a title screen, and every one of them
 * was something to look at instead of the button. So they are gone. What
 * remains is the dirt, the button, and the bar the button turns into.
 *
 * What survives from that pass is the *material*: the numbers below are still
 * derived from `crates/game/src/ui/widgets.rs` rather than styled by eye — the
 * same dirt at the same tile size, the same nine-sliced button sprite at the
 * same frame thickness, the same 24 px Monocraft label — so the button here and
 * the buttons a moment later are the same object.
 *
 * Numbers are cited to the constant they come from. If one of those moves, this
 * file is a place the game's own layout has quietly drifted away from. The one
 * deliberate departure is the progress fill's green; it says so where it lives.
 *
 * External rather than inlined, and that is a correctness requirement, not a
 * preference: `_headers` sets a site-wide CSP, Cloudflare Pages *appends* the
 * per-path one rather than replacing it, and a browser given two CSP headers
 * enforces the intersection. So `style-src 'self'` always wins over any
 * per-path `'unsafe-inline'`, and an inline <style> is silently dropped --
 * which is exactly how this page first shipped, rendering every element at
 * once with no styling at all. One extra request on an HTTP/2 connection is
 * the cheaper problem.
 */

/* Monocraft, the pixel font the game's UI draws in — same file /about already
 * ships, so a visitor who read the pitch first arrives with it cached.
 * `swap`, because a loading screen that withholds its own status text until a
 * 210 KB font lands has its priorities backwards. */
@font-face {
  font-family: "Monocraft";
  src: url("/assets/Monocraft.ttf") format("truetype");
  font-display: swap;
}

:root {
  /* ---- the game's own constants (crates/game/src/ui/widgets.rs) ---------- */

  /* `HUD_SCALE`. Everything below is a GUI-pixel count times this. */
  --scale: 3;

  /* `DIRT_TILE` = 2.0 * HUD_SCALE, i.e. 32 GUI px across a 16-texel tile —
   * `renderMenuBackgroundTexture` declares a 32x32 texture size for a 16x16
   * file, so each texel covers two GUI pixels. That is the chunky grain; at
   * 16 GUI px it reads as a visibly different surface. */
  --dirt-tile: 96px;

  /* `WIDE_BUTTON_W` / `BUTTON_H` — the main menu's headline row (Fight, Ranked).
   * Play is this screen's headline choice, so it is that button at that size. */
  --button-w: 460px;
  --button-h: 44px;
  --button-label: 24px;             /* `BUTTON_LABEL_PX` */

  /* The bar is **deliberately bigger than the button it replaces** (owner,
   * 2026-08-16). It used to match `--button-w` exactly, on the reasoning that a
   * column wants one axis — but that column had a logo in it, and with the
   * screen emptied to one control the bar was simply too small to be the only
   * thing on it. Growing on the click also reads as "now it is loading", which
   * is the one thing this screen has to communicate. */
  --bar-w: 620px;
  --bar-h: 36px;

  /* Bevy scales a nine-slice's frame with the node (`min_coef`), Minecraft does
   * not, and the menu resolves that by capping every grid button at
   * `GRID_CORNER_SCALE` = HALF_BUTTON_W / BUTTON_TEX.x = 224/200 = 1.12. So the
   * 3-px border in `button.png.mcmeta` draws at 3 * 1.12. CSS's
   * `border-image-width` is independent of the element's size, so both the
   * button and the (shorter) progress trough can simply state it. */
  --frame: 3.36px;

  /* ---- colours, sampled out of a capture of the real menu ---------------- */

  --ink: #ffffff;
  --ink-dim: #9e9e9e;
  --red: #ff8080;

  /* The progress fill, and **deliberately brighter than the game's own green
   * button** (owner, 2026-08-16). That button's face is `GREEN_TINT` over
   * button.png, which lands at (43, 112, 45) — correct for a menu widget among
   * other menu widgets, and too dark for the one moving thing on an otherwise
   * empty screen.
   *
   * So the fill is Minecraft's `§a` green, and the two bevel bands are derived
   * from it through the button sprite's *own* ratios rather than picked: the
   * sprite's face/bevel/shadow are 111/170/86, which in linear light is ×2.649
   * and ×0.628. Applied to #55ff55 (green saturating at 1.0, as it does on the
   * real sprite) that is #86ff86 and #43d043. */
  --fill: #55ff55;
  --fill-bevel: #86ff86;
  --fill-shadow: #43d043;

  /* `text_shadow()` — a hard offset copy, never a blur. Bevy composites it in
   * linear space where CSS composites in sRGB, so a literal 0.9 alpha comes out
   * far lighter here than in the game; 0.75 reproduces the measured (34,34,34)
   * over the button's 111 face, which is where most of this page's text sits. */
  --shadow-ink: rgba(0, 0, 0, 0.75);
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }

body {
  color: var(--ink);
  font-family: "Monocraft", ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace;
  display: grid; place-items: center;
  overflow: hidden;

  /* The menu's backdrop. The tile is **pre-darkened in the asset**
   * (tools/gen_boot_assets.py applies `DIRT_DIM` in linear space) rather than
   * dimmed here, because CSS has no linear-space multiply: `filter: brightness`
   * and `background-blend-mode` both work in sRGB and land nowhere near it.
   * The generated palette is byte-identical to a capture of the running menu. */
  background: #251710 url("/assets/menu-dirt.png") repeat 0 0 / var(--dirt-tile) var(--dirt-tile);
  image-rendering: pixelated;
}

/* The canvas Bevy takes over (Window::canvas = "#stage"). **Covered** until the
 * client is warmed, so a half-initialised black rectangle never sits in front of
 * the user.
 *
 * *Covered* and not `display: none`, and that distinction is the whole warm-up
 * (crates/game/src/warmup.rs). The client now renders a throwaway match behind
 * this screen so every render pipeline is compiled where a hitch is free — and a
 * `display: none` canvas has no layout box, so `fit_canvas_to_parent` would size
 * its drawing buffer to nothing and those frames would warm nothing at all. So
 * the canvas is laid out and live the whole time, and #boot is a real opaque
 * cover on top of it.
 *
 * **`position: fixed; inset: 0` is load-bearing, not tidiness.** Bevy's
 * `fit_canvas_to_parent` does exactly one thing: it writes `width: 100%;
 * height: 100%` onto the canvas as an *inline* style, which beats anything
 * declared here. With the canvas as a normal child of this `display: grid`
 * body, that 100% resolves against a grid row sized `auto` — i.e. against the
 * canvas's own content height — which is circular, so the element fell back to
 * its intrinsic size: the `width`/`height` *attributes*, which winit sets in
 * **physical** pixels. On a 150%-scaled display that is a 1920x1080 element in
 * a 1280x720 viewport, and you see the top-left two thirds of the game with the
 * bottom cut off. Bevy's own docs warn about this ("will not behave as expected
 * for parents that set their size according to the size of their children");
 * the trap is that a `place-items: center` grid *is* such a parent.
 *
 * Taking the canvas out of flow makes the containing block the viewport, so
 * Bevy's inline 100%/100% means what it looks like it means, and the boot
 * overlay keeps the centred grid to itself. */
canvas { display: block; outline: none; }
#stage { position: fixed; inset: 0; width: 100%; height: 100%; }
/* ⚠️ **Every element of the loading screen has to be listed here**, not just the
 * cover. The version line used to be a sibling of `#boot` rather than a child —
 * it had to be, being pinned to the viewport where `#boot` is a centred grid —
 * and it survived the reveal to sit over the running game for the whole
 * session. It is gone now, but anything added outside `#boot` needs adding
 * here too. */
#stage.ready ~ #boot { display: none; }

/* The cover, and the thing that has to stay opaque and on top: the game is
 * drawing full-rate frames underneath it from the moment the client starts.
 * It repeats the body's backdrop rather than inheriting it — the body's is what
 * a visitor sees for the few milliseconds before this element has laid out. */
#boot {
  position: fixed; inset: 0; z-index: 2;
  display: grid; place-items: center; align-content: center;
  background: inherit;
  padding: 1.5rem; text-align: center;
}

/* One column, one width. `width` on the children themselves does not work here:
 * `#boot > *` and `#play` have the *same* specificity, so `#play { width: 100% }`
 * won a cascade tie by being written later and stretched the button across the
 * whole viewport (owner, 2026-08-10). A sized wrapper cannot be argued with. */
#boot-inner {
  display: flex; flex-direction: column; align-items: center;
  /* Sized by the *wider* of the two things in the slot, so the bar has room;
   * the button centres inside it at its own width. */
  width: min(92vw, var(--bar-w));
}

/* ------------------------------------------------------- the action slot -- */

/* Play and the progress trough share **one grid cell**, so the bar appears
 * exactly where the button was and nothing on the screen moves at the click.
 * The slot keeps the button's full height whichever is showing. */
#slot {
  display: grid;
  width: 100%;
  min-height: var(--button-h);
}
#slot > * { grid-area: 1 / 1; align-self: center; justify-self: center; }

/* The real `widget/button` sprite, nine-sliced exactly as its .mcmeta declares
 * (200x20 source, 3px border) — the same widget the menu's Fight button is, at
 * the same size. `repeat` matches Minecraft's own nine-slice, which tiles the
 * edges rather than stretching them. */
#play {
  width: min(100%, var(--button-w)); height: var(--button-h);
  display: none;
  padding: 0 1rem;

  font-family: inherit;
  font-size: var(--button-label);
  line-height: 1;
  color: var(--ink);
  text-shadow: 3px 3px 0 var(--shadow-ink);

  background: none;
  border: var(--frame) solid transparent;
  border-image-source: url("/assets/button.png");
  border-image-slice: 3 fill;
  border-image-width: var(--frame);
  border-image-repeat: repeat;
  image-rendering: pixelated;

  cursor: pointer;
}
#play.show { display: block; }
#play:hover, #play:focus-visible {
  border-image-source: url("/assets/button_highlighted.png");
  outline: none;
}

/* Minecraft's world-gen bar, in the menu's own material: a disabled-button
 * trough with a hard-edged green fill. No transition on the width, deliberately
 * — the bar reports real bytes, and easing it would make it lie about where the
 * download is. */
.track {
  width: 100%; height: var(--bar-h);
  border: var(--frame) solid transparent;
  border-image-source: url("/assets/button_disabled.png");
  border-image-slice: 3 fill;
  border-image-width: var(--frame);
  border-image-repeat: repeat;
  image-rendering: pixelated;
}
/* Nothing is downloading until the Play button is pressed, so an empty trough
 * above it is a bar reporting on work that has not started (owner, 2026-08-10).
 * `client-boot.js` clears this class at the click. */
#boot.awaiting-play .track { visibility: hidden; }
/* The button sprite's own bevel, stated rather than nine-sliced: a zero-width
 * border-image still paints both its corners, so a 0% bar would show a stub. */
.fill {
  height: 100%; width: 0%;
  background: var(--fill);
  box-shadow: inset 0 3px 0 var(--fill-bevel), inset 0 -3px 0 var(--fill-shadow);
}

/* The only words on the screen once Play is pressed, so they are white and a
 * size up from the 16 px they were — this is the whole of the feedback now
 * that the logo and the version line are gone (owner, 2026-08-16). */
#pct {
  margin-top: 1rem;
  min-height: 1.2em;              /* reserved, so an empty status never reflows */
  font-size: 20px;
  color: var(--ink);
  text-shadow: 3px 3px 0 var(--shadow-ink);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------- failure -- */

/* Positioned so it can never end up *behind* the canvas or the boot cover:
 * `#stage` is `position: fixed` and therefore paints above in-flow content, and
 * this panel has to stay readable if the client dies after the canvas was
 * revealed. A z-index above #boot's, because a failure can also happen while the
 * cover is still up (`fail()` hides it, but not before the browser has painted a
 * frame of both).
 *
 * The bevelled stone panel is the site's own (`web/style.css`), which is in turn
 * Minecraft's container bevel: a light top/left edge and a dark bottom/right one.
 * A failure is the one screen here that is a block of prose, and prose on bare
 * dirt is what the rest of this page is styled to avoid. */
#fail {
  display: none; position: relative; z-index: 4;
  width: min(92vw, 34rem);
  padding: 24px 28px;
  text-align: center;

  background-color: #101010;
  background-image:
    linear-gradient(rgba(0, 0, 0, 0.78), rgba(0, 0, 0, 0.78)),
    url("/assets/stone.png");
  background-size: auto, 48px 48px;
  border-top: 3px solid #6d6d6d;
  border-left: 3px solid #6d6d6d;
  border-bottom: 3px solid #191919;
  border-right: 3px solid #191919;
}
#fail.show { display: block; }
#fail h1 {
  margin: 0 0 14px;
  font-size: 22px; font-weight: normal;
  color: var(--red);
  text-shadow: 2px 2px 0 #2a1010;
}
#fail p {
  font-size: 15px; line-height: 1.7;
  color: var(--ink-dim);
  text-shadow: 2px 2px 0 var(--shadow-ink);
  margin: 0 0 20px;
}
#fail code { background: #00000066; padding: 0.1rem 0.3rem; font-size: 0.9em; color: var(--ink); }

/* The same widget as #play, as a link. Narrower than the menu's rows because it
 * lives inside a panel rather than in the centred column. */
.btn {
  display: inline-block;
  min-height: var(--button-h);
  padding: 11px 20px;

  font-family: inherit;
  font-size: 16px; line-height: 1.3;
  color: var(--ink);
  text-decoration: none;
  text-shadow: 2px 2px 0 var(--shadow-ink);

  border: var(--frame) solid transparent;
  border-image-source: url("/assets/button.png");
  border-image-slice: 3 fill;
  border-image-width: var(--frame);
  border-image-repeat: repeat;
  image-rendering: pixelated;

  cursor: pointer;
}
.btn:hover, .btn:focus-visible {
  border-image-source: url("/assets/button_highlighted.png");
  outline: none;
}
