* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: #1b1d22;
  color: #e8e8ec;
}

#viewport {
  position: fixed;
  inset: 0;
}

#viewport canvas {
  display: block;
}

/* Brand overlay, top-left corner of the 3D view -- direct request, with the
   wording and both link targets supplied verbatim. Three deliberate choices
   here, all of them about not getting in the way of the app underneath:

   1. `pointer-events: none` on the whole block, handed back only to the two
      links. #viewport is the full-window 3D canvas and the primary gesture on
      it is orbit-dragging; an overlay that ate a drag near the corner would be
      a small, permanent annoyance with no visible cause. The same reasoning
      (and the same one-line fix) is already on #viewport-copyright below.
   2. The logo draws at its own native 83x83 with no CSS resize. It is a small
      image carrying fine lettering ("Black Scrolls Games" is a few pixels
      tall); any scale factor puts that through a resampler for no gain.
   3. The divider is its own 1px element with a fixed height, not a border on
      the text block. A border would either stretch to the logo's full height
      or shrink to whatever the text happens to measure -- and the text is the
      one part of this that can reflow. An explicit rule stays put.

   SPACING IS MEASURED AGAINST THE LOGO'S VISIBLE EDGE, NOT ITS BOX. The PNG is
   83x83 with the artwork inset inside roughly 6px of transparency on the left
   and top and 9px on the right, so a plain flex `gap` would read about 9px
   wider than it computes, and the container sits flush at 0/0 while the block
   still looks inset from the window corner by ~6px. That is why the horizontal
   spacing lives on .brand-rule's own margins instead of a `gap` -- tuned so
   what shows is ~12px logo-to-rule and ~13px rule-to-text. Replacing the PNG
   with one that has different padding is the one change that would need these
   two numbers revisited. */
#viewport-brand {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  pointer-events: none;
  user-select: none;
}

#viewport-brand a {
  /* The only parts that take the pointer back -- see note 1 above. */
  pointer-events: auto;
}

#viewport-brand .brand-logo {
  display: block;
  flex: none;
}

#viewport-brand .brand-rule {
  flex: none;
  width: 1px;
  height: 60px;
  margin: 0 13px 0 2px;
  background: #454445;
}

#viewport-brand .brand-text {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

#viewport-brand .brand-tagline {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.25;
  color: #ffffff;
}

#viewport-brand .brand-links {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.3;
}

#viewport-brand .brand-links a {
  color: #1b8cf6;
  text-decoration: none;
}

#viewport-brand .brand-links a:hover,
#viewport-brand .brand-links a:focus-visible {
  text-decoration: underline;
}

/* The arrow is a hint that the link leaves the page, not a glyph to read --
   slightly smaller and set off from the label so it reads as a mark. */
#viewport-brand .brand-arrow {
  font-size: 11px;
  margin-left: 1px;
}

#viewport-brand .brand-sep {
  width: 1px;
  height: 11px;
  background: #454445;
}

/* Recenter button for the 3D view (per direct report: "that would be great
   in the corner of 3d view, too, a center button if we drag the view too
   far by accident") -- an overlay in the corner of the (position:fixed)
   #viewport, wired in main.js to just call the existing reframe(). Same
   corner-overlay treatment as the 2D grid's own center button
   (.grid-center-btn in the editor grid styling above), for a consistent
   affordance in both places; bottom-left here since the sidebar already
   occupies the right edge. */
#viewport-center-btn {
  position: absolute;
  left: 16px;
  bottom: 16px;
  width: 36px;
  height: 36px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 19px;
  line-height: 1;
  color: #c8cad2;
  background: rgba(28, 29, 35, 0.85);
  border: 1px solid #3a3c44;
  border-radius: 50%;
  cursor: pointer;
}

#viewport-center-btn:hover {
  color: #e8e8ec;
  border-color: #6a7aa8;
}

/* Copyright/anti-copying notice, bottom-left corner of the 3D view -- per
   direct instruction, exact wording supplied. Sits directly above the
   recenter button in the same corner (that button occupies the very
   corner itself, 16px-36px-16px from the bottom edge -- this starts just
   above it). Deliberately small and low-contrast (a notice, not a call to
   action) but still legible; `pointer-events: none` so it never blocks
   orbit-dragging the 3D view underneath it, even though it visually sits
   on top. */
#viewport-copyright {
  position: absolute;
  left: 16px;
  bottom: 60px;
  max-width: 260px;
  margin: 0;
  font-size: 10px;
  line-height: 1.5;
  color: rgba(232, 232, 236, 0.4);
  pointer-events: none;
  user-select: none;
}

#sidebar {
  position: fixed;
  top: 0;
  right: 0;
  width: 320px;
  height: 100%;
  background: rgba(20, 21, 26, 0.88);
  border-left: 1px solid #33353d;
  padding: 16px;
  overflow-y: auto;
  backdrop-filter: blur(6px);
}

#sidebar h1 {
  font-size: 15px;
  margin: 0 0 2px;
  color: #fff;
}

#sidebar .byline {
  font-size: 11px;
  margin: 0 0 8px;
  color: #9a9ca6;
}

#sidebar h1 .tag {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #9a9ca6;
  background: #2a2c34;
  padding: 2px 6px;
  border-radius: 4px;
  margin-left: 6px;
  vertical-align: middle;
}

#sidebar a {
  color: #8fb8ff;
}

/* Direct report: "after 5 visible layer buttons with the + level and remove
   level buttons they start extending that field to the right, we should start
   a new row with buttons if we reach that level."
   
   flex-wrap alone would not have done it: with `flex: 1` the basis is 0 and
   the buttons shrink indefinitely, so the row never becomes too full to fit --
   it just squeezes every label into an unreadable sliver and then overflows.
   The min-width is what gives them a floor to stop shrinking at, and only then
   does wrap have anything to act on. */
#sidebar .level-switcher {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 6px;
}

#sidebar .level-switcher button {
  flex: 1 1 auto;
  min-width: 62px;
  padding: 6px 0;
  background: #2a2c34;
  border: 1px solid #3a3c44;
  color: #e8e8ec;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
}

/* The two level ACTIONS, in their own fixed row below the tabs -- direct
   report: "it is a bit strange that the + level button keeps changing its
   place and size, it should be in one static line with the remove level, and
   the levels should change their size and row only."

   A two-column GRID, not flex, and that is the whole point: with flex, "+
   Level" would stretch to the full width whenever there is no remove button
   (a single-level build), so it would still change size -- just less often,
   which is worse to notice. A fixed pair of columns keeps it in exactly the
   same place at exactly the same width whether the second button is there or
   not. */
.level-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin: 0 0 16px;
}

.level-actions button {
  padding: 6px 0;
  background: #2a2c34;
  border: 1px solid #3a3c44;
  color: #e8e8ec;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
}

.level-actions button:hover {
  border-color: #6a7aa8;
}

/* Destructive, so it reads apart from "+ Level" sitting next to it. */
.level-actions button.remove-level {
  color: #c98a90;
  border-color: #4a3a3e;
}

.level-actions button.remove-level:hover {
  background: #3a2a2e;
  border-color: #a8565f;
  color: #ffc4c9;
}

#sidebar .level-switcher button.active {
  background: #3a5fd9;
  border-color: #3a5fd9;
  color: #fff;
}

/* Half-tall ("ht") level tabs and the "+ Half Level" button -- gray text so
   a half level (e.g. "Level 0.5") is visually distinct from a whole one at
   a glance, per direct feedback: "draw the .5 layers and + 0.5 layer button
   with a gray text so it is clear to see that they are half levels." Kept
   as its own class (added alongside .active, not instead of it) so the
   active-state highlight (background/border above) still applies normally
   -- only the text color is overridden here, and by a smaller amount while
   active (still legibly "selected" against the blue background) than while
   idle (a plainer gray against the same dark background every other tab
   uses). */
#sidebar .level-switcher button.half-level {
  color: #8a8c98;
}

#sidebar .level-switcher button.half-level.active {
  color: #cdd6f7;
}

/* Lighting toggle (per direct request: "one that keeps this lighting of
   the 3d preview and one that add a bit more cinematic lightning") -- same
   2-button row look as the level switcher above, kept as its own class
   rather than sharing .level-switcher since the two toggle different app
   state and matching the existing per-feature CSS-duplication pattern this
   file already uses for the wall-section buttons above. */
.lighting-toggle {
  display: flex;
  gap: 6px;
  margin: 0 0 16px;
}

.lighting-toggle button {
  flex: 1;
  padding: 6px 0;
  background: #2a2c34;
  border: 1px solid #3a3c44;
  color: #e8e8ec;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
}

.lighting-toggle button.active {
  background: #3a5fd9;
  border-color: #3a5fd9;
  color: #fff;
}

#wall-sections {
  margin: 0 0 16px;
}

.wall-section-row {
  margin: 0 0 10px;
}

.wall-section-label {
  font-size: 12px;
  color: #c8cad2;
  margin: 0 0 4px;
}

.wall-section-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.wall-section-note {
  font-size: 11px;
  color: #7c7e88;
  font-style: italic;
}

.wall-section-buttons button {
  padding: 4px 8px;
  background: #2a2c34;
  border: 1px solid #3a3c44;
  color: #e8e8ec;
  border-radius: 4px;
  cursor: pointer;
  font-size: 11px;
}

.wall-section-buttons button.active {
  background: #3a5fd9;
  border-color: #3a5fd9;
  color: #fff;
}

#sidebar h2 {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #9a9ca6;
  margin: 18px 0 8px;
}

#sidebar .hint {
  font-size: 12px;
  line-height: 1.5;
  color: #9a9ca6;
  margin: 0 0 16px;
}

#sidebar code {
  background: #2a2c34;
  padding: 1px 4px;
  border-radius: 3px;
  font-size: 11px;
}

/* Colour-scheme picker, inline in the "Floor palette" heading -- reads as part
   of the heading text ("FLOOR PALETTE (COLOR1, COLOR2)") rather than as a
   separate control, per the request's own sketch of it. */
.scheme-picker {
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: #6f7380;
}

.scheme-option {
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  color: #8b8f9c;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.scheme-option:hover {
  color: #c8ccd8;
}

.scheme-option.active {
  color: #e6e8ef;
  font-weight: 600;
  text-decoration: none;
}

/* Share / load controls (see main.js's share wiring and src/share.js). */
.share-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 8px;
}

/* `display: flex` above beats the browser's own `[hidden] { display: none }`,
   which is only a default-stylesheet rule -- so without this, setting the
   hidden PROPERTY on a .share-row does nothing at all and the row stays on
   screen. That is exactly what happened to the "Load a build" row: it was
   marked hidden in the markup and toggled in script, and was visible the whole
   time regardless. Caught by comparing a screenshot against what the DOM
   claimed. */
.share-row[hidden] {
  display: none;
}

.share-row input[type='text'] {
  flex: 1 1 160px;
  min-width: 0;
  background: #1c1d23;
  border: 1px solid #3a3c44;
  border-radius: 4px;
  color: #e8e8ec;
  font: inherit;
  font-size: 12px;
  padding: 6px 8px;
}

.share-row input[type='text']:focus {
  outline: none;
  border-color: #6a7aa8;
}

.share-row button {
  background: #2a2c34;
  border: 1px solid #3a3c44;
  border-radius: 4px;
  color: #d6d8e0;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  padding: 6px 10px;
}

.share-row button:hover {
  background: #33353d;
  border-color: #6a7aa8;
  color: #e8e8ec;
}

/* The name box takes the free space; "Copy share link" stays its own width
   beside it, so the two share one row instead of two. */
.share-row #share-link-btn {
  flex: 0 0 auto;
}

/* The secondary share paths -- "Copy the code instead" and "Load a build".
   Direct question: "Do we need the copy code and load a build buttons?" They
   earn their place (a code is host-free, and survives a chat client mangling a
   1000-character link), but not equal billing with the main button, so they
   read as small text links under it rather than a third and fourth button. */
.share-more {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  font-size: 11px;
  margin: -2px 0 8px;
}

.share-more .linkish {
  background: none;
  border: 0;
  border-bottom: 1px dotted #5a5d68;
  border-radius: 0;
  color: #8b8f9c;
  cursor: pointer;
  font: inherit;
  padding: 0;
}

.share-more .linkish:hover {
  border-bottom-color: #8fa0d0;
  color: #c6cbdb;
}

/* "Start Over" -- destructive, so it reads apart from the three share buttons
   above it rather than sitting in the same row looking like another of them.
   Muted until hovered: the point is that it is findable, not that it is the
   first thing the eye lands on. */
.share-row button.danger {
  color: #c98a90;
  border-color: #4a3a3e;
}

.share-row button.danger:hover {
  background: #3a2a2e;
  border-color: #a8565f;
  color: #ffc4c9;
}

/* Armed: one click has landed and the next one clears. Filled rather than
   outlined, so the change of state is unmistakable at a glance. */
.share-row button.danger.armed,
.share-row button.danger.armed:hover {
  background: #8f3a43;
  border-color: #c0616b;
  color: #fff1f2;
}

.share-status {
  font-size: 12px;
  margin: 0 0 12px;
  color: #8b8f9c;
}

.share-status.ok { color: #7ee2a0; }
.share-status.error { color: #ff9aa2; }

/* Three fixed columns rather than flex-wrap. Direct request: "let's add the
   4x4 round next to the 4x4 in the floor palette, so perhaps it will fit into
   two rows instead of 3."

   Reordering alone would not have done it: the swatches are as wide as their
   own labels, so "2x2 corner" and "2x2 round" claimed most of a row between
   them and the sixth piece always spilled onto a third. A 3-column grid makes
   every swatch the same width, which fits all six in exactly two rows and --
   the same complaint as the "+ Level" button -- stops them resizing as labels
   change. With the order below it also lands the three PLAIN pieces on the
   first row and the three SHAPED ones on the second. */
.floor-palette {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  margin: 0 0 16px;
}

/* Tightened once the palette became a fixed 3-column grid: at the old 10px
   side padding and 12px type, "2x2 corner" and "4x4 round" no longer fit a
   cell on one line, so the shaped row wrapped to two lines and stood visibly
   taller than the plain row above it. Measured against the widest label at the
   sidebar's 272px. */
.palette-swatch {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  white-space: nowrap;
  padding: 6px 4px;
  font-size: 11px;
  background: #2a2c34;
  border: 1px solid #3a3c44;
  color: #e8e8ec;
  border-radius: 4px;
  cursor: pointer;
}

.palette-swatch::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 2px;
  background: var(--swatch-color, #888);
  flex: none;
}

.palette-swatch.active {
  border-color: var(--swatch-color, #3a5fd9);
  background: #23252d;
  box-shadow: 0 0 0 1px var(--swatch-color, #3a5fd9);
}

/* Collapsible "How to use" tip under the Level N layout heading -- native
   <details>/<summary> (no JS needed for open/close), styled to match the
   rest of the dark sidebar rather than the browser's bare default
   disclosure triangle. Closed by default so it doesn't eat vertical space;
   customers open it on demand. */
.how-to-use {
  margin: 0 0 8px;
}

.how-to-use summary {
  cursor: pointer;
  font-size: 12px;
  color: #c8cad2;
  padding: 6px 8px;
  background: #2a2c34;
  border: 1px solid #3a3c44;
  border-radius: 4px;
  user-select: none;
}

.how-to-use summary:hover {
  border-color: #6a7aa8;
}

.how-to-use[open] summary {
  border-radius: 4px 4px 0 0;
}

.how-to-use .hint {
  margin: 0;
  padding: 8px;
  background: #1c1d23;
  border: 1px solid #3a3c44;
  border-top: none;
  border-radius: 0 0 4px 4px;
}

.editor-grid {
  margin: 0 0 16px;
  display: flex;
  justify-content: center;
}

.editor-grid-svg {
  display: block;
}

/* Outer positioning root (editor.js's `viewport`) for the pannable/
   expandable grid feature -- fixed-size, but deliberately NOT clipped
   itself (see `.editor-grid-clip` below for what is): the wall-variant
   popup needs to be able to render past the grid's own visible edge
   without getting cut off, so it lives in a sibling of the clipped
   element, not a descendant of it. position:relative so the center button
   (a direct child) can sit fixed in a corner via position:absolute; the
   grab/grabbing cursor lives here too since dragging is initiated on this
   element (see editor.js's onDragStart). */
.editor-grid-viewport {
  position: relative;
  cursor: grab;
}

.editor-grid-viewport.dragging {
  cursor: grabbing;
}

/* The actual clipping window (editor.js's `svgClip`) -- fixed to the
   ORIGINAL GRID_COLS x GRID_ROWS window size, same as `.editor-grid-
   viewport` above. The SVG inside is now much bigger than this (it draws
   GRID_PAD extra cells on every side, see editor.js's module note), and
   gets dragged around underneath this window via a CSS transform on
   `.editor-grid-inner`. Carries the border/background/radius that used to
   live on the SVG itself, since the SVG's own edges mostly sit off-screen
   now -- the rounded corners clip together with the content this way.
   `position: relative` is NOT decorative here -- found live, the hard way:
   without it, `overflow: hidden` alone did NOT clip `.editor-grid-inner`
   (a `position: absolute` descendant whose transform pushes it, and
   therefore the whole SVG, well outside this box) -- the grid rendered at
   its full, un-clipped 3x size and blew out the whole sidebar's layout.
   This element needs to actually BE the containing block its absolutely-
   positioned child resolves against (not just an ancestor with overflow
   set) for the clip to take visual effect. */
.editor-grid-clip {
  position: relative;
  overflow: hidden;
  background: #14151a;
  border: 1px solid #3a3c44;
  border-radius: 4px;
}

/* The pan layer: wraps just the editor SVG. position:absolute (top:0/
   left:0 is the untransformed anchor; editor.js drives its actual position
   via an inline `transform: translate(...)`, applied in lockstep to
   `.editor-grid-popup-layer` below). */
.editor-grid-inner {
  position: absolute;
  top: 0;
  left: 0;
}

/* The wall-variant popup's (Phase 7) own layer -- a SIBLING of
   `.editor-grid-clip`, not a descendant, specifically so the popup itself
   is never clipped by it (a badge near the visible window's edge would
   otherwise cut its own popup off mid-button). Gets the identical pan
   transform as `.editor-grid-inner` (see editor.js's applyPan) so it still
   tracks the grid correctly while panned -- the popup's own absolute pixel
   coordinates (set inline per-open by editor.js, matching the SVG's own
   lattice-to-pixel mapping, plus a PAD_PX compensation since the popup is
   plain HTML and doesn't get the SVG's viewBox remapping) are relative to
   THIS element, same as they used to be relative to `.editor-grid-inner`. */
.editor-grid-popup-layer {
  position: absolute;
  top: 0;
  left: 0;
}

/* Center button (per direct report: "a center button in the corner to jump
   back to center in layout view"), fixed in the viewport's own
   bottom-right corner regardless of how far the grid has been panned --
   it's a sibling of `.editor-grid-inner`, not a descendant, so it's never
   itself dragged. Same corner-overlay treatment as the 3D view's own
   center button below, for a consistent affordance in both places. */
.grid-center-btn {
  position: absolute;
  right: 6px;
  bottom: 6px;
  width: 26px;
  height: 26px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  line-height: 1;
  color: #c8cad2;
  background: rgba(28, 29, 35, 0.85);
  border: 1px solid #3a3c44;
  border-radius: 50%;
  cursor: pointer;
}

.grid-center-btn:hover {
  color: #e8e8ec;
  border-color: #6a7aa8;
}

.wall-variant-badge {
  stroke: #14151a;
  stroke-width: 1.5;
  cursor: pointer;
}

.wall-variant-badge:hover {
  stroke: #e8e8ec;
}

.wall-badge-popup {
  position: absolute;
  transform: translate(-50%, -50%);
  background: #1c1d23;
  border: 1px solid #3a3c44;
  border-radius: 6px;
  padding: 8px;
  min-width: 150px;
  z-index: 10;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
}

.wall-badge-popup-label {
  font-size: 11px;
  color: #c8cad2;
  margin: 0 0 6px;
}

/* 2-per-row instead of the shared `.wall-section-buttons` default's
   flex-wrap-to-fit (still used as-is by the "Wall sections" debug list,
   which has the whole sidebar's width to work with) -- this popup is much
   narrower, and 4 buttons in one row made it awkwardly wide. Scoped to
   just the popup so the debug list's own layout is untouched. */
.wall-badge-popup .wall-section-buttons {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}

.wall-badge-popup .wall-section-buttons button {
  text-align: center;
}

.editor-cell {
  fill: #22242b;
  stroke: #33353d;
  stroke-width: 1;
  cursor: pointer;
}

.editor-cell:hover {
  stroke: #6a7aa8;
}

/* An occupied cell's own background rect is never painted any more -- every
   tile is drawn as a stroke-less <path> on top of it (see editor.js's
   refresh()). Its stroke has to go with it: a stroke straddles the edge it is
   drawn on, so half of it stayed visible AROUND each covered cell, outlining a
   single-slot tile and drawing seams across the inside of a multi-cell one.
   Direct report: "it seems like the basic 2x2 shape an extra border/outline. we
   should delete that because now it has a slight misfit among other pieces."
   What separates two neighbouring tiles is the 2px gap the cell inset already
   leaves between them. Kept as a rule (rather than dropping the class) so the
   preview rules below, which come later and win on order, still override it. */
.editor-cell.occupied {
  stroke: none;
}

/* Hover preview of the selected palette type's footprint (editor.js's
   showPreview) -- most useful for multi-slot types (floor_2x4/floor_4x4)
   where it's otherwise not obvious how big an area a click will cover.
   `.preview`'s stroke color is set inline per-hover (matching the selected
   type's own swatch, see SWATCH_BY_ID in editor.js) so only the shared
   fill/dash styling lives here; `.preview-blocked` overrides with a fixed
   red to signal the placement would overlap an existing tile. */
.editor-cell.preview {
  fill: rgba(255, 255, 255, 0.12);
  stroke-width: 2;
  stroke-dasharray: 4 2;
}

.editor-cell.preview-blocked {
  fill: rgba(255, 70, 70, 0.22);
  stroke: #ff4d4d;
  stroke-width: 2;
  stroke-dasharray: 4 2;
}

.editor-origin {
  fill: #ff9aa2;
  pointer-events: none;
}

.editor-cell-triangle {
  pointer-events: none;
}

.editor-cell-rotation {
  fill: #14151a;
  stroke: #14151a;
  pointer-events: none;
}

/* Ghost outline of the level BELOW, shown underneath the active level's
   own grid so the two can be lined up by eye. Deliberately a thin,
   mostly-transparent overlay (not a solid fill) so it reads as an outline
   whether the cell underneath is empty (dark background) or already has a
   real tile of its own (its color should still show through clearly). */
.editor-cell-ghost {
  fill: rgba(255, 255, 255, 0.08);
  stroke: rgba(255, 255, 255, 0.35);
  stroke-width: 1;
  stroke-dasharray: 3 2;
  pointer-events: none;
}

/* Half-tall ("ht") reference/ghost -- same element and class as
   .editor-cell-ghost above (this is an ADDITIONAL class, toggled on
   alongside it, not a replacement -- see editor.js's refresh()), just
   darker/grayer instead of white so a half-level's ghost reads as visually
   distinct at a glance, per direct feedback: "perhaps we should make them
   darker? to see they are half height?" */
.editor-cell-ghost.editor-cell-ghost-half {
  fill: rgba(110, 112, 124, 0.18);
  stroke: rgba(140, 142, 156, 0.5);
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: #c7c9d1;
  margin: 0 0 16px;
  cursor: pointer;
}

.checkbox-row input {
  cursor: pointer;
}

.offset-row {
  display: flex;
  gap: 14px;
  margin: 0 0 16px;
}

.offset-row label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: #c7c9d1;
}

.offset-row input[type="number"] {
  width: 64px;
  background: #2a2c34;
  border: 1px solid #3a3c44;
  color: #e8e8ec;
  border-radius: 4px;
  padding: 4px 6px;
  font-size: 12px;
}

.offset-row select {
  background: #2a2c34;
  border: 1px solid #3a3c44;
  color: #e8e8ec;
  border-radius: 4px;
  padding: 4px 6px;
  font-size: 12px;
}

#status-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
}

.status-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 6px;
  border-radius: 4px;
}

/* The ht filenames run to 46 characters and are joined by UNDERSCORES, which
   are not line-break opportunities -- `overflow-wrap: break-word` would leave
   them as one unbreakable word and let them run off the panel. `anywhere` is
   what actually lets them wrap.
   
   Wrapping rather than truncating was settled directly. Several of these names
   differ only at the END (..._connector_floor vs ..._connector_levels,
   ..._quarter_round_bottom vs _top), so a trailing ellipsis would render two
   different pieces as the same row, in a list whose whole job is saying which
   file to print. */
.status-row .name {
  font-family: "SF Mono", Menlo, Consolas, monospace;
  font-size: 11px;
  overflow-wrap: anywhere;
  min-width: 0;
}

/* The count must never be squeezed or pushed off by a long name beside it. */
.status-row .badge {
  flex: 0 0 auto;
}

.status-row .badge {
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.status-row.pending .badge { background: #3a3c44; color: #b7b9c2; }
.status-row.ok .badge { background: #1e4d2b; color: #7ee2a0; }
.status-row.error .badge { background: #5a1f24; color: #ff9aa2; }
.status-row.error .name { color: #ff9aa2; }

/* Click a row to spotlight that piece type in the 3D view (main.js's
   toggleHighlight) -- only "ok" rows (a real placed piece type) are
   clickable; the empty-layout placeholder and error rows aren't. */
.status-row.ok {
  cursor: pointer;
}
.status-row.ok:hover {
  background: #2a2c34;
}
.status-row.ok.selected {
  background: #223256;
}
.status-row.ok.selected .name {
  color: #8fb8ff;
}

/* Approximate printed size -- direct request: "we should add another area
   called: Approximate printed size: where we write out the size in inches and
   in cm." Three labelled rows so nobody has to guess which number is the
   height, then the one-line form underneath for copying into a listing. */
.printed-size {
  margin: 0 0 16px;
}

/* Two lines per entry, with the centimetres on their own line aligned under
   the inches. At the sidebar's 320px a single row cannot hold a label plus
   both units, and letting it wrap naturally broke the cm figure across lines
   mid-number ("15.2 x 10.2 x | 12.7 cm"). Forcing the break at a place chosen
   here, with nowrap on each figure, keeps every entry aligned and readable. */
.printed-size-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 8px;
  font-size: 12px;
  padding: 3px 0;
}

.printed-size-row .axis {
  flex: 0 0 72px;
  color: #8b8f9c;
}

.printed-size-row .inches {
  flex: 1 1 auto;
  color: #e8e8ec;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.printed-size-row .cm {
  flex: 1 1 100%;
  padding-left: 80px;
  font-size: 11px;
  color: #8b8f9c;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* The playable-floor line answers a different question from the two above it
   (area, not extents), so it is set off rather than read as a third variant of
   the same measurement. */
.printed-size-row.useful {
  margin-top: 5px;
  padding-top: 7px;
  border-top: 1px solid #2f313a;
}

.printed-size-empty {
  font-size: 12px;
  color: #8b8f9c;
}

/* Collapsible sections -- direct request: "make every section acordian, to be
   able to show hide its content, open content should be the basic." The
   markup is transformed at startup (see the block at the end of main.js), so
   these rules only have to dress a header and a body that already exist. */
#sidebar h2.section-head {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  user-select: none;
}

#sidebar h2.section-head:hover {
  color: #c8ccd8;
}

/* The disclosure triangle, drawn rather than typed so it can rotate smoothly
   and never depends on a glyph being present in the user's font. */
#sidebar h2.section-head::before {
  content: '';
  flex: 0 0 auto;
  width: 0;
  height: 0;
  border-left: 4px solid currentColor;
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
  transform: rotate(90deg);
  transform-origin: 2px 50%;
  transition: transform 120ms ease;
}

#sidebar h2.section-head.collapsed::before {
  transform: rotate(0deg);
}

/* The scheme picker lives inside the Floor palette heading and must stay
   clickable in its own right (main.js ignores clicks that land on a control
   inside a header), so it keeps its normal cursor rather than inheriting the
   header's pointer. */
#sidebar h2.section-head .scheme-option {
  cursor: pointer;
}

/* A collapsed section takes up nothing. Explicit rather than relying on the
   browser's own [hidden] rule -- exactly the trap .share-row fell into, where
   a `display` declaration silently beat it. */
.section-body[hidden] {
  display: none;
}

/* A collapsed header should not leave the big gap a section normally has
   under it. */
#sidebar h2.section-head.collapsed {
  margin-bottom: 4px;
}

/* ---------------------------------------------------------------------------
   Promotional block, pinned to the bottom of the sidebar.

   Direct request: "add an area under the right appr. printed size fields, it
   will be a static unhideable promotional area on the bottom as enyone can use
   this site for free." Every colour below was supplied verbatim; see
   index.html's own comment for the two separate things that make it unhideable
   (no <h2> of its own, plus an entry in the accordion's break condition).

   The panel itself follows the app's existing rounded-panel treatment -- 1px
   border, 6px radius, same as .wall-badge-popup -- with the supplied
   #1b2028 / #4a6175 instead of the sidebar's own greys, which is what sets it
   apart from the tool's controls without shouting.
   --------------------------------------------------------------------------- */
#promo {
  margin: 18px 0 4px;
  padding: 12px;
  background: #1b2028;
  border: 1px solid #4a6175;
  border-radius: 6px;
}

#promo .promo-head {
  display: flex;
  align-items: center;
  gap: 12px;
}

#promo .promo-logo {
  flex: none;
  width: 78px;
  height: auto;
}

/* A <p>, not a heading element, on purpose: a top-level <h2> in the sidebar is
   what the accordion turns into a collapsible header, and this block must not
   be collapsible. Styled to read as a heading all the same. */
#promo .promo-title {
  margin: 0;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.3;
  /* The two lines are two supplied colours, so they are two spans rather than
     one wrapped string -- the break between them is meaning, not reflow, and
     must not move when the sidebar's width or font does. */
}

#promo .promo-title span {
  display: block;
}

#promo .promo-title-a { color: #cebba1; }
#promo .promo-title-b { color: #f1b16e; }

#promo .promo-hero,
#promo .promo-compare {
  display: block;
  width: 100%;
  /* Overrides the height ATTRIBUTE, which is there for the aspect ratio (so the
     box is reserved before the image loads) rather than to size it. */
  height: auto;
}

#promo .promo-hero {
  margin: 4px 0 0;
}

/* 7px, not the ~16px the gap actually reads as: promotion_T2_picture carries
   20px of transparent padding along its bottom edge (of 422), which at this
   column's scale is another ~9px of empty space below the artwork. Same
   measure-the-visible-edge problem as the brand overlay's logo at the top of
   this file. Swapping that image for one padded differently is what would make
   this number wrong. */
#promo .promo-copy {
  margin: 7px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: #ffffff;
}

#promo .promo-btn {
  display: block;
  margin: 18px 0 0;
  padding: 10px 12px;
  border-radius: 4px;
  text-align: center;
  text-decoration: none;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.3;
}

/* Written in sentence case in the markup and uppercased here, so the label a
   screen reader announces is a sentence rather than an acronym soup. */
#promo .promo-btn-primary {
  background: #cd9654;
  border: 1px solid #cd9654;
  color: #1b1b1b;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

#promo .promo-btn-secondary {
  margin-top: 9px;
  background: #2a2a2a;
  border: 1px solid #3d3d3d;
  color: #ffffff;
  /* Lighter than the primary button on purpose, matching the reference: the
     two are not equal choices, and the weight is what says so before anyone
     reads either label. */
  font-weight: 500;
}

/* `filter: brightness` rather than a second hard-coded colour for each button:
   the supplied palette has one value per button, and inventing a hover shade
   for each would be inventing brand colour. This stays a lightening of exactly
   what was given. */
#promo .promo-btn:hover,
#promo .promo-btn:focus-visible {
  filter: brightness(1.12);
}

#promo .promo-or {
  margin: 10px 0 0;
  text-align: center;
  font-size: 11px;
  letter-spacing: 0.08em;
  color: #ffffff;
}

#promo .promo-caption {
  margin: 24px 0 0;
  text-align: center;
  font-size: 12px;
  color: #ffffff;
}

#promo .promo-compare {
  margin: 12px 0 0;
}
