/* Parallax editor chrome. Layered on the shared demo-theme tokens (assets/css/
   demo-theme.css) exactly the way assets/css/prop-editor.css and assets/css/
   weapon-editor.css are, and on the same eight local tokens with the same
   values: this page makes no colour decision of its own, so a theme change
   moves all three editors together and none of them can drift.

   The reasoning behind each token is written down once, in
   assets/css/weapon-editor.css's header, and is not repeated here. The short
   version: --accent, --err and --warn are fixed because they must read the same
   in both themes, --accent-ink exists because a solid accent fill needs a
   foreground that does NOT follow var(--text), and --stage is fixed dark
   because it is art ground rather than a page surface -- a menu backdrop is
   drawn to sit under the shell's own dark chrome, and a pale plate around it in
   light theme lies about what the scene will look like in the game. */
:root {
  --panel: color-mix(in srgb, var(--text) 6%, var(--bg));
  --line: color-mix(in srgb, var(--text) 16%, transparent);
  --muted: color-mix(in srgb, var(--text) 55%, transparent);
  --accent: #3e5a8e;
  --accent-ink: #eef1f8;
  --err: #e0605f;
  --warn: #d99a2b;
  --stage: #0c0d11;
}

* { box-sizing: border-box; }
/* Matches the other five editors: an author class such as .toolset sets display
   and would otherwise outrank the UA's [hidden] { display: none }, so a hidden
   panel with a layout class of its own would still show. */
[hidden] { display: none !important; }

body {
  margin: 0; font: 14px/1.4 system-ui, sans-serif;
  background: var(--bg); color: var(--text);
  height: 100vh; display: flex; flex-direction: column;
}

#bar { display: flex; align-items: center; gap: 12px; padding: 8px 12px; background: var(--panel); border-bottom: 1px solid var(--line); flex: none; }
#bar .brand { font-weight: 600; display: flex; align-items: center; gap: 6px; flex: none; }
#bar .actions { display: flex; gap: 6px; margin-left: auto; align-items: center; flex: none; }
#scenelabel { opacity: .7; flex: none; }

button, select, input {
  font: inherit; color: var(--text); background: var(--panel);
  border: 1px solid var(--line); border-radius: 6px; padding: 4px 10px;
}
button, select { cursor: pointer; }
input[type=number], input[type=text] { cursor: text; }
button.primary { background: var(--accent); color: var(--accent-ink); border-color: transparent; font-weight: 600; }
button:disabled { opacity: .4; cursor: default; }
button:focus-visible, select:focus-visible, input:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}

/* The scene strip: one button per name in the library. Names, not thumbnails --
   a scene's picture is 480x300 of layered PNGs and there is no single cell to
   cut, so the strip says what it is instead of showing it. It scrolls rather
   than wrapping, to keep the header one row tall in a narrow window. */
#scenes { display: flex; gap: 4px; align-items: center; min-width: 0; overflow-x: auto; padding: 2px; }
.spick { flex: none; padding: 3px 8px; font-size: .82rem; }
.spick[aria-current="true"] { border-color: var(--accent); box-shadow: inset 0 0 0 2px var(--accent); }

#dirty { color: var(--warn); font-size: .85rem; font-weight: 600; flex: none; }

#notice { margin: 0; padding: 6px 12px; background: var(--panel); border-bottom: 1px solid var(--line); flex: none; font-size: .85rem; }
#notice.bad { background: color-mix(in srgb, var(--err) 16%, var(--bg)); border-bottom-color: color-mix(in srgb, var(--err) 45%, transparent); color: color-mix(in srgb, var(--err) 70%, var(--text)); }

/* Two columns: the rail, and the frame the scene is presented in. There is no
   third column, unlike the prop and weapon editors -- the stage here IS the
   live preview, because it is the shipped renderer drawing the scene. */
#shell { display: grid; grid-template-columns: 260px 1fr; flex: 1; min-height: 0; }
#rail { background: var(--panel); padding: 10px; overflow-y: auto; border-right: 1px solid var(--line); display: flex; flex-direction: column; gap: 10px; }

.lab { font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; opacity: .6; margin: 0 0 6px; }

/* --- the layer stack ------------------------------------------------------
   Listed back to front, index 0 furthest from the camera, which is the order
   scene.yml itself uses. Reordering the display would put the arrows and the
   file in disagreement about which way is forward. */
#layerlist { display: flex; flex-direction: column; gap: 4px; }
.lrow {
  display: flex; align-items: center; gap: 6px; padding: 4px 6px;
  border: 1px solid var(--line); border-radius: 6px; background: var(--bg);
  cursor: pointer; text-align: left; width: 100%;
}
.lrow[aria-current="true"] { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.lrow .lname { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Tabular numerals: the readout sits beside a layer being dragged, and a
   proportional 1 would make every row twitch as the number changes. */
.lrow .lnum { flex: none; font-size: .74rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.stackops { display: flex; gap: 4px; margin-top: 2px; }
.stackops button { flex: 1 1 0; min-width: 0; padding: 3px 4px; font-size: .8rem; }

/* --- the selected layer's numbers ----------------------------------------- */
.field { display: flex; align-items: center; gap: 8px; margin: 6px 0; }
.field > span { flex: 0 0 40%; opacity: .85; font-size: .85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.field input { flex: 1 1 0; min-width: 0; padding: 3px 6px; }
/* The row is marked, not the input: the row carries the field's name, so
   reddening it puts the colour and the name in one glance. */
.field.invalid input { border-color: var(--err); background: color-mix(in srgb, var(--err) 12%, var(--panel)); }
.note { margin: 6px 0 2px; font-size: .74rem; color: var(--muted); }

/* --- what is wrong with the scene ----------------------------------------- */
#problems { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
#problems li {
  font-size: .78rem; line-height: 1.35; padding: 5px 7px; border-radius: 5px;
  border-left: 3px solid transparent;
}
#problems li.error { border-left-color: var(--err); background: color-mix(in srgb, var(--err) 14%, transparent); }
#problems li.warn { border-left-color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent); }
#problems li.clean { color: var(--muted); }

#stage {
  position: relative; overflow: hidden; background: var(--stage);
  display: flex; flex-direction: column; align-items: stretch; gap: 8px;
  padding: 10px;
}

/* The scroll box the shell's frame is presented in. min-height: 0 lets it
   shrink below its content inside the column flex; without it a zoomed-in
   canvas pushes the stage bar off the bottom instead of scrolling. */
#viewport { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; }
/* margin: auto rather than the parent's centring: both centre a canvas smaller
   than the box, and only this one keeps the top-left corner of a canvas LARGER
   than the box reachable, since a scroll container cannot scroll to negative
   offsets. The CSS width is driven from JS -- the backing store stays 480x300
   at every zoom, so a frame pixel on screen is a frame pixel of the game. */
#view {
  margin: auto; flex: none; display: block; image-rendering: pixelated;
  background: #05060a; border: 1px solid color-mix(in srgb, #fff 12%, transparent);
  cursor: move; touch-action: none;
}

#stagebar { flex: none; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.toolset { display: flex; gap: 4px; }
.mode[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
#aimbox { display: flex; align-items: center; gap: 6px; font-size: .8rem; color: #cfd3dc; }
#aimbox input[type=range] { width: 140px; padding: 0; accent-color: var(--accent); }
#stagebar .toolset[aria-label="Zoom"] { margin-left: auto; }
#zoom-pct { min-width: 4.2em; }

/* The paint bar, same row shape as #stagebar above and the same idiom as
   assets/css/prop-editor.css's own #brushbar -- the two editors' repair
   surfaces read as siblings. */
#brushbar { flex: none; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tool[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
#ink { display: flex; align-items: center; gap: 6px; font-size: .8rem; color: #cfd3dc; }
#inkchip { width: 18px; height: 18px; border-radius: 4px; border: 1px solid color-mix(in srgb, #fff 25%, transparent); }
/* Tabular numerals: a hex digit changing beside a picked colour should not
   twitch the row the way a proportional font would. */
#inkhex { font-variant-numeric: tabular-nums; opacity: .8; }

/* --- the header's icon ----------------------------------------------------
   Same idiom as the other five editors' assets/css/*.css: a 12x12 crispEdges
   SVG in a data URI masked over currentColor. The mask is defined HERE as well
   as in assets/css/site.css, and that is not a duplicate by accident: site.css
   dresses the landing page's Tools card, and this page links only
   demo-theme.css and this sheet, so a rule that lived only in site.css would
   never reach this header. Two consumers, two rules.
   The default is an EMPTY svg rather than no mask at all: an undefined --m
   leaves mask-image as none, which shows the currentColor background as a solid
   1.5em block. Masked by nothing is what "blank" has to mean here. */
.ic {
  display: inline-block; width: 1.5em; height: 1.5em; flex: none;
  background: currentColor;
  --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3C/svg%3E");
  -webkit-mask: var(--m) center / contain no-repeat; mask: var(--m) center / contain no-repeat;
}

/* Three offset bands, read as layers at different depths. */
.ic-parallax { --m: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' shape-rendering='crispEdges'%3E%3Crect x='0' y='2' width='12' height='2'/%3E%3Crect x='1' y='5' width='10' height='2'/%3E%3Crect x='2' y='8' width='8' height='2'/%3E%3C/svg%3E"); }
