/* ==========================================================================
   Base — reset, page ground, shell layout, masthead.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: clamp(.875rem, .82rem + .2vw, .95rem);
  line-height: 1.55;
  color: var(--ink);
  background: var(--page);
  overflow-x: hidden;
}

/* The game is an app shell: three full-width bands — header, plot, toolbar.
   The page itself does not scroll. It is exactly the height of the window and
   the MIDDLE band scrolls inside it, which is what keeps the header and the
   toolbar on screen without either of them being pinned there.

   `position: sticky` was the obvious answer and is the wrong one: a sticky
   element can only travel inside its own containing block, and a grid row
   sized to its content gives it nowhere to go. It never moved.

   Scoped to the game rather than left on `body`, because the asset sheet
   shares this stylesheet and is a long reference page — `height: 100dvh` with
   `overflow: hidden` left it unable to scroll past the first screenful. */
body.game-page {
  display: grid;
  grid-template-rows: auto 1fr auto;
  height: 100dvh;
  overflow: hidden;
}

/* Only the game scrolls inside itself, and only because its toolbar has to
   stay put. The scroll belongs to the middle band, not to `.shell` in
   general — the builder uses the same shell and wants the window's own
   scrollbar. */
/* The plot is a fixed size, so when it does not fit, the band scrolls rather
   than the tiles getting smaller. `safe` matters: plain centring pushes the
   top-left of an oversized child out of reach of the scrollbar. */
/* Nothing scrolls on the game page. A plot bigger than the space is looked at
   through a moving window rather than scrolled to, so the shell fills the band
   and hands its height down to the board. */
body.game-page .shell {
  overflow: hidden;
  align-content: stretch;
  width: min(100%, 1400px);
}

/* The builder is an ordinary page: the window scrolls, and the header stays
   with you because it carries the only way off the page. */
/* The builder wants the width. A plot is a fixed number of pixels across and
   the reading-width cap was squeezing large ones into the tools beside them. */
body.builder-page .shell { width: min(100%, 1700px); }

body.builder-page .masthead {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--page);
}

h1, h2, h3, p, dl, dd, ol, ul, figure { margin: 0; }
ol, ul { padding: 0; list-style: none; }

button {
  font: inherit;
  color: inherit;
  border: 0;
  background: none;
  cursor: pointer;
}

button:disabled { cursor: not-allowed; }

:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Shell --------------------------------------------------------------- */

.shell {
  position: relative;
  z-index: 1;
  display: grid;
  align-content: start;
  /* min-height:0 so this row is allowed to be shorter than its contents;
     without it a grid row refuses to shrink and the scrollbar never appears. */
  min-height: 0;
  width: min(100%, 1140px);
  margin-inline: auto;
  padding: clamp(var(--gap-4), 2.5vw, var(--gap-6)) clamp(var(--gap-3), 2.5vw, var(--gap-6));
}

/* --- Panels -------------------------------------------------------------
   The shared "wooden board with a parchment face" surface. Everything
   chrome-like in the interface is built from this one recipe.
   ------------------------------------------------------------------------ */

.panel {
  position: relative;
  border-radius: var(--radius);
  background: linear-gradient(180deg, var(--parchment) 0%, var(--parchment-sh) 100%);
  box-shadow:
    inset 0 0 0 3px var(--wood-lit),
    inset 0 0 0 6px var(--wood),
    0 var(--lift) 0 var(--wood-deep),
    0 calc(var(--lift) + 8px) 22px rgba(30, 45, 20, .38);
}

/* --- Masthead ------------------------------------------------------------
   Full width, ruled off from the plot below. Name on the left, plot picker on
   the right, nothing between them.
   ------------------------------------------------------------------------ */

.masthead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-4);
  padding: var(--gap-3) clamp(var(--gap-4), 3vw, var(--gap-6));
  border-bottom: 1px solid var(--page-rule);
}

.masthead__id {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
}

.masthead__mark {
  position: relative;
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: var(--radius-sm);
  background:
    repeating-linear-gradient(0deg, rgba(58, 36, 21, .22) 0 1px, transparent 1px 9px),
    repeating-linear-gradient(90deg, rgba(58, 36, 21, .22) 0 1px, transparent 1px 9px),
    linear-gradient(160deg, var(--grass-lit), var(--grass-deep));
  box-shadow: inset 0 0 0 2px var(--wood-deep), 0 2px 0 var(--wood-deep);
}

.masthead__mark::after {
  content: "";
  position: absolute;
  inset: 60% 60% 12% 12%;
  border-radius: 2px;
  background: var(--gold);
  box-shadow: 0 0 0 1px var(--wood-deep), 0 0 10px var(--gold);
}

.masthead__title {
  font-family: var(--font-pixel);
  font-size: clamp(1.5rem, 1.2rem + 1.6vw, 2.15rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: .04em;
  color: var(--ink);
}

.masthead__tag {
  font-size: .8rem;
  font-style: italic;
  color: var(--ink-soft);
}

/* --- Level picker -------------------------------------------------------- */

.levelpick {
  display: flex;
  align-items: stretch;
  gap: var(--gap-2);
}

.levelpick__step {
  width: 2.1rem;
  border-radius: var(--radius-sm);
  font-family: var(--font-pixel);
  font-size: 1.15rem;
  line-height: 1;
  color: var(--parchment);
  background: linear-gradient(180deg, var(--wood-lit), var(--wood));
  box-shadow: inset 0 0 0 2px var(--wood-deep), 0 3px 0 var(--wood-deep);
  transition: transform 90ms var(--ease-out), box-shadow 90ms var(--ease-out), filter 120ms;
}

.levelpick__step:hover { filter: brightness(1.08); }

.levelpick__step:active {
  transform: translateY(3px);
  box-shadow: inset 0 0 0 2px var(--wood-deep), 0 0 0 var(--wood-deep);
}

.levelpick__body {
  display: grid;
  align-content: center;
  gap: 1px;
  min-width: 9.5rem;
  padding: var(--gap-1) var(--gap-3);
  border-radius: var(--radius-sm);
  text-align: center;
  background: rgba(58, 36, 21, .1);
  box-shadow: inset 0 0 0 2px var(--wood);
}

.levelpick__index {
  font-family: var(--font-pixel);
  font-size: .68rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.levelpick__name {
  font-family: var(--font-pixel);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.1;
  color: var(--ink);
}

/* --- Stage ---------------------------------------------------------------
   Just the plot now. Everything that used to sit beside it is in the toolbar.
   ------------------------------------------------------------------------ */

/* Stretches, rather than centring on its contents.
   
   The board holds nothing but an absolutely-positioned plot, so it has no
   height of its own to be centred around — `place-content: center` sized it
   to zero and `overflow: hidden` then clipped the whole game away. Its height
   has to come DOWN the layout: body's `1fr` row, to the shell, to here, to
   the board. */
.stage {
  display: grid;
  align-content: stretch;
  min-height: 0;
}

/* The board stretches, and the plot centres itself inside it with its own
   auto margins.

   NOT `justify-items: center` on the stage: that sizes the board to its
   contents, and the plot's `width: min(100%, …)` then has no definite width
   to resolve the 100% against, so it collapses to nothing and the grid
   disappears entirely. */
/* THE WINDOW. The plot is positioned inside it and moved about; this clips.
   Sized by the band it sits in, so it is as big as the page can spare. */
.board {
  position: relative;
  min-width: 0;
  min-height: 0;
  height: 100%;
  overflow: hidden;
}

/* --- Section labels ------------------------------------------------------ */

.label {
  display: block;
  font-family: var(--font-pixel);
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Links between the three pages — the game, the builder and the asset sheet.

   In `base.css` rather than in the builder's own stylesheet because all three
   pages carry it, and a class only one page can style is a class the other
   two quietly render unstyled. Named `crosslink` and not `sidenav`, which the
   asset sheet already uses for its jump links. */

/* The map toggle sits with the page links: both are about what you are
   looking at rather than what the robot is doing, and grouping them keeps the
   masthead to three parts instead of five spread across it. */
.masthead__aside {
  display: flex;
  align-items: center;
  gap: var(--gap-3);
}

.crosslink { display: flex; gap: var(--gap-3); }

.crosslink__link {
  font-family: var(--font-pixel);
  font-size: .76rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-decoration: none;
  padding: var(--gap-2) var(--gap-3);
  border-radius: var(--radius-sm);
  box-shadow: inset 0 0 0 1px var(--page-line);
}

.crosslink__link:hover { color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink-soft); }

/* The page you are on stays in the list rather than being left out of it, so
   the three links never move about between pages. */
.crosslink__link[aria-current="page"] {
  color: var(--wood-deep);
  background: var(--gold);
  box-shadow: inset 0 0 0 1px var(--gold-deep);
}
