/* The pixel editor -------------------------------------------------------- */

/* Drawing on one. The canvas keeps the picture's own pixels and is scaled up
   without smoothing, so a 32-square sprite stays 32 squares however big the
   pane is.

   .picture-box is the picture's box on screen and renderDrawing gives it both
   sides in pixels, off one scale; the canvas fills it, so the element and the
   picture are the same shape and there is no letterbox for the pointer maths
   to correct for. ⚠️ Sizing by `width: 100%` and a capped height is what does
   not work — a canvas has an intrinsic size, so that squashes rather than
   shrinks, and a 16-square sprite comes out 16 by 7. Both sides in pixels is
   exact. `contain` used to do this job and the empty strip it left is what
   the old arithmetic was for. */
.drawing { display: flex; flex-direction: column; min-height: 0; flex: 1; }
.picture-box { position: relative; flex: none; }
.pixels {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 0;
  image-rendering: pixelated;
  touch-action: none;
  cursor: crosshair;
}
/* Blocky is right for a sprite blown up and wrong for a photograph, so the
   pane picks per picture rather than once for all of them. */
.pixels.smooth { image-rendering: auto; }

/* The shape being dragged out, over the picture and never part of it. The same
   box as the canvas, so it takes the zoom for nothing; see-through where the
   shape is not, so the picture underneath shows through it. */
.pixels.preview { position: absolute; inset: 0; pointer-events: none; }

/* ⚠️ Two ways to get this wrong and both have been met. Too small a floor and
   the canvas goes to nothing, which is not a small canvas but no canvas at
   all, since a pointer has to land on it for a stroke to happen. Too big a
   one and the tools go to nothing instead — at 320 on a phone held sideways
   the palette had 24px to live in, which is a colour you cannot pick.

   So: 320 where the window can spare it, never more; never less than the old
   floor of 150, or a quarter of the window where a quarter is less than that;
   and in between, whatever is left after the 470-odd pixels the studio's own
   furniture and one band of tools need. The tools scroll under it either
   way. Measured at 1280 × 820, 390 × 844 and 844 × 390. */
.drawing .media { min-height: clamp(min(150px, 25vh), calc(100vh - 470px), 320px); }
/* Light paper (drawing.js): white and pale grey for what is see-through,
   still a checker, so a white pixel is never mistaken for an empty one. */
.drawing .media.paper-light {
  background: repeating-conic-gradient(#ffffff 0% 25%, #dcdce2 0% 50%) 0 0 / 16px 16px;
}
.drawing > .pad { min-height: 0; overflow-y: auto; }
/* The strip looping beside the frame buttons while it is edited. */
.strip-preview {
  height: 40px;
  image-rendering: pixelated;
  border: 1px solid var(--border-soft);
  border-radius: 4px;
}
/* Where the picture ends: a transparent pixel and the empty strip beside the
   picture are the same checkerboard, so without this line the edge is a
   guess — a sprite drawn to its corner looked like one drawn to nowhere.
   Inset on .picture-box, like .frame-lines below; the border sits outside the
   pixels rather than over the outer row of them, and the shadow dims the
   strip so the picture reads as the paper. */
.picture-edge {
  position: absolute;
  inset: 0;
  pointer-events: none;
  box-sizing: content-box;
  border: 1px solid var(--muted);
  box-shadow: 0 0 0 100vmax rgba(8, 4, 24, 0.4);
}
/* Frame boundaries over a strip: inset on .picture-box, so they follow a zoom
   without being sized. One screen pixel at any zoom. */
.frame-lines {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: linear-gradient(to left, var(--accent) 1px, transparent 1px);
  background-size: calc(100% / var(--frames)) 100%;
  opacity: 0.5;
}
/* The lines between the squares at 8× and up. An SVG in the picture's own
   units, so the box sizes it; non-scaling strokes keep every line one screen
   pixel at any zoom. A mid grey, partly see-through, because it has to show
   on a white pixel and on a black one; the eighths are the studio's cyan. */
.pixel-grid {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.pixel-grid path {
  fill: none;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  shape-rendering: crispEdges;
}
.pixel-grid .squares { stroke: rgba(128, 128, 150, 0.45); }
.pixel-grid .eights { stroke: var(--accent); opacity: 0.7; }
/* A square button holding one icon: a quiet one (base.css), lit the same way.
   The words live on its title and its aria-label, so nothing here is only a
   picture. */
button.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 28px;
  padding: 0;
}

/* The colour box in the first column, as tall as the tools and the brush
   widths in the second, however those wrap. Its swatch fills it, rather than
   sitting inside the browser's own padding and border. */
.toolbox { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px 10px; }
.toolbox .well { grid-row: 1 / 3; width: 56px; height: 100%; border-radius: 8px; cursor: pointer; }
.toolbox .well::-webkit-color-swatch-wrapper { padding: 0; }
.toolbox .well::-webkit-color-swatch { border: none; border-radius: 7px; }
.toolbox .well::-moz-color-swatch { border: none; border-radius: 7px; }

/* Two rows of sixteen, sized by the pane rather than fixed, so a narrow pane
   still shows the whole palette instead of wrapping it into a third row. */
.swatches { display: grid; grid-template-columns: repeat(16, minmax(0, 1fr)); gap: 3px; }
.swatch {
  width: auto;
  aspect-ratio: 1;
  min-width: 0;
  padding: 0;
  border: 2px solid oklch(0.4 0.05 295);
  border-radius: 5px;
}
.swatch.on { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 35%, transparent); }
input[type="color"] {
  width: 32px; height: 26px; padding: 0;
  border: 1px solid var(--border-soft); border-radius: 6px; background: none;
}
