/* ============================================================
   Plinth — tool-specific styling.
   Loaded after tokens, components and the app shell.
   ============================================================ */

/* Two columns, not three: there is no list here, and a panel filled with
   padding is worse than a panel that does not exist.

   Held inside a min-width query on purpose. The shell stacks its panels under
   960px from a media block of its own, and this file loads after it, so an
   unconditional rule wins on source order alone and the phone layout silently
   goes back to columns. */
/* Three columns: what it could look like, the thing itself, and how it is set.
 *
 * The layouts went to their own column because they are the one control anybody
 * uses first and the one that reads worst in a list — they want to be big, and
 * a column of big previews on the left is what every tool of this kind settles
 * on. It also stops the settings column being a scroll with the interesting
 * part buried at the top of it. */
@media (min-width: 961px) {
  .workspace {
    grid-template-columns: 260px minmax(0, 1fr) 320px;
    /* A row that cannot exceed the height it was given. Left at auto, a grid
       row grows to fit its content, and the content here is a canvas sized
       from the row — so a tall frame would quietly push the page open instead
       of being scaled down into it. */
    grid-template-rows: minmax(0, 1fr);
  }
}
@media (min-width: 961px) and (max-width: 1280px) {
  .workspace { grid-template-columns: 216px minmax(0, 1fr) 292px; }
}

/* ---------- the stage ---------- */

/* No studio panel behind the composition, and no padding in front of it.
 *
 * The shell gives this cell a dark gradient, a hairline and a rounded corner of
 * its own, which was a surface for the composition to sit on. With a fixed
 * frame shape inside a cell of a different shape, that surface can only ever
 * show as two bands — above and below on a wide frame, either side on a tall
 * one — and they read as a gap rather than as a mat, because the composition
 * already has its own edge.
 *
 * So the cell gives all of its room to the canvas: the frame is as large as it
 * can be, and what is left over is the same background as everywhere else
 * rather than a second panel with a border on it. */
.viewport {
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  padding: 0;
  min-height: 0;
  min-width: 0;
  background: none;
  box-shadow: none;
  border-radius: 0;
}

.stage-wrap {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 0;
  min-height: 0;
}

.viewport canvas#stage {
  display: block;
  /* Width and height are written on by the renderer; these are the backstop for
     the frame before the first measurement lands. */
  max-width: 100%;
  max-height: 100%;
  border-radius: var(--md-sys-shape-corner-medium);
  box-shadow: var(--app-hairline);
  image-rendering: auto;
  /* Dragging turns the picture, and there is nowhere on the canvas that does
     nothing, so the cursor says so everywhere rather than only over the
     picture itself. */
  cursor: grab;
  touch-action: none;
}
.viewport canvas#stage.posing { cursor: grabbing; }
/* Shift slides the card rather than turning it, and the cursor says which of
   the two is about to happen. */
.viewport canvas#stage.sliding { cursor: move; }

/* Behind a transparent backdrop. Drawn on the element rather than in the canvas
   so it can never reach an export. */
.viewport canvas#stage.clear {
  --check: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent);
  background-color: var(--md-sys-color-surface);
  background-image:
    linear-gradient(45deg, var(--check) 25%, transparent 25% 75%, var(--check) 75%),
    linear-gradient(45deg, var(--check) 25%, transparent 25% 75%, var(--check) 75%);
  background-size: 18px 18px;
  background-position: 0 0, 9px 9px;
}

/* ---------- inspector ---------- */

.panel--inspector .controls {
  display: flex; flex-direction: column; gap: 14px;
  padding: 4px 4px 12px;
}

/* Headings, not disclosures. Seventeen controls want grouping; none of them
   wants hiding, and a group you can fold away is a place for a control to get
   lost. */
.group-title {
  margin: 10px 0 -4px;
  font: 500 11px/16px var(--md-sys-typescale-plain-font);
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--md-sys-color-on-surface-variant);
}
.group-title:first-child { margin-top: 0; }

/* ---------- dropdowns ---------- */

/* Laid out like a slider row so a column of sliders and a couple of dropdowns
   read as one list rather than two kinds of thing stacked up. */
.md-field { display: flex; align-items: center; gap: 10px; min-height: 36px; }
.md-field > label {
  flex: 0 0 auto;
  font-size: 13px;
  color: var(--md-sys-color-on-surface-variant);
}
.md-select {
  flex: 1 1 auto;
  min-width: 0;
  height: 32px;
  padding: 0 26px 0 10px;
  border-radius: 8px;
  border: 1px solid var(--md-sys-color-outline);
  background-color: var(--md-sys-color-surface);
  color: var(--md-sys-color-on-surface);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  /* The arrow drawn rather than left to the platform: the native one is a
     different shape on every operating system, and this panel has one icon
     family in it on purpose. */
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 13px center, right 8px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.md-select:hover { background-color: var(--md-sys-color-surface-container); }
.md-select:focus-visible { outline: 2px solid var(--md-sys-color-on-surface); outline-offset: 1px; }
/* The open list is drawn by the operating system, which knows nothing of the
   page theme. Saying both colours is what stops a dark app opening a white
   menu. */
.md-select option {
  background: var(--md-sys-color-surface-container);
  color: var(--md-sys-color-on-surface);
}

/* ---------- colours ---------- */

/* Built like a slider row — label and value above, the control below — so a
   colour sits in the column of sliders without interrupting it. The swatch is
   full width rather than a small square: it is the only control here whose
   current value is the thing itself rather than a number, so it may as well be
   big enough to judge. */
.md-colour { display: flex; flex-direction: column; gap: 6px; }
.md-colour .row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
}
.md-colour .row label {
  font-size: 13px;
  color: var(--md-sys-color-on-surface-variant);
}
.md-colour-value {
  font: 400 11px/16px var(--md-sys-typescale-plain-font);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  color: var(--md-sys-color-on-surface-variant);
}
.md-colour-input {
  /* A native colour input is drawn with its own padding and border on every
     platform, and the only reliable way to get a plain swatch is to take the
     chrome off and put the shape back on the element itself. */
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  height: 30px;
  padding: 0;
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: 8px;
  background: none;
  cursor: pointer;
}
.md-colour-input::-webkit-color-swatch-wrapper { padding: 0; }
.md-colour-input::-webkit-color-swatch { border: none; border-radius: 7px; }
.md-colour-input::-moz-color-swatch { border: none; border-radius: 7px; }
.md-colour-input:focus-visible {
  outline: 2px solid var(--md-sys-color-on-surface);
  outline-offset: 2px;
}


/* ---------- the gradient bar ---------- */

.gradient { display: flex; flex-direction: column; gap: 10px; }

/* The bar is the control, so it is big enough to aim at: a stop has to be
   grabbable and the gap between two of them has to be clickable. */
.gradient-bar {
  position: relative;
  height: 28px;
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: 8px;
  cursor: copy;
  touch-action: none;
}

/* Each stop is a handle straddling the bar's edge, so it reads as attached to
   the gradient rather than floating over it, and its own colour is visible in
   the middle without being confused with the ramp underneath. */
.gradient-stop {
  position: absolute;
  top: 50%;
  width: 14px;
  height: 34px;
  margin: 0;
  padding: 0;
  transform: translate(-50%, -50%);
  border: 1px solid var(--md-sys-color-outline);
  border-radius: 5px;
  background:
    linear-gradient(var(--stop), var(--stop)) padding-box,
    var(--md-sys-color-surface) border-box;
  box-shadow: 0 0 0 2px var(--md-sys-color-surface);
  cursor: grab;
}
.gradient-stop[data-on="true"] {
  border-color: var(--md-sys-color-on-surface);
  border-width: 2px;
  z-index: 1;
}
.gradient-stop:focus-visible {
  outline: 2px solid var(--md-sys-color-on-surface);
  outline-offset: 2px;
}
.gradient-bar:active .gradient-stop[data-on="true"] { cursor: grabbing; }

.gradient-meta { display: flex; align-items: baseline; gap: 8px; }
.gradient-where {
  font: 400 11px/16px var(--md-sys-typescale-plain-font);
  font-variant-numeric: tabular-nums;
  color: var(--md-sys-color-on-surface-variant);
}

/* The swatch takes the room, the remove button takes what it needs. */
.gradient-edit { display: flex; align-items: stretch; gap: 8px; }
.gradient-edit .md-colour-input { flex: 1; }

.gradient-drop {
  display: grid;
  place-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: 8px;
  background: none;
  color: var(--md-sys-color-on-surface-variant);
  cursor: pointer;
}
/* Disabled rather than hidden on the two end stops: a button that comes and
   goes as you select different stops makes the row jump about, and the reason
   it cannot be pressed is worth showing. */
.gradient-drop:disabled { opacity: 0.35; cursor: default; }

/* ---------- the export dialog ---------- */

.md-dialog { max-width: 420px; }
.dialog-note {
  margin: 0 0 14px;
  font: 400 13px/19px var(--md-sys-typescale-plain-font);
  color: var(--md-sys-color-on-surface-variant);
}
.export-row { display: flex; flex-wrap: wrap; gap: 8px; }
.export-row .md-button {
  flex: 1 1 auto; justify-content: center; font-variant-numeric: tabular-nums;
}
.export-row--small { margin-bottom: 4px; }
#export-modes .dialog-note:not(:first-child) { margin-top: 20px; margin-bottom: 8px; }

/* ---------- narrow ---------- */

@media (max-width: 960px) {
  /* How tall the frame is, written once: the shell sizes both the grid row and
     the viewport's own minimum, and setting only one of them makes the viewport
     overflow its row and print the panel over its own canvas. */
  .workspace {
    --picture: max(320px, 44dvh);
    grid-template-rows: var(--picture) auto;
    gap: 20px;
  }
  .viewport { padding: 12px; min-height: var(--picture); }
}

/* A bar of five buttons and a title does not fit across a phone, and a bar that
   overflows widens the page under it rather than scrolling — which cuts off the
   canvas and the panels to the right of it. Everything with a word on it loses
   the word. */
@media (max-width: 620px) {
  .md-top-app-bar { gap: 2px; padding: 0 6px 0 10px; }
  /* The shortcuts list is no use without a keyboard, and this is the width
     where there is unlikely to be one. */
  .md-top-app-bar #btn-shortcuts { display: none; }
  .md-top-app-bar .md-button.has-icon {
    width: 40px; padding: 0; gap: 0; font-size: 0;
  }
  .md-top-app-bar .md-button.has-icon svg { width: 20px; height: 20px; }
}

/* ---------- galleries ---------- */

/* Choices shown as pictures of themselves. Two per row for most groups, three
   for the backdrops, where there are more of them and the thing being judged is
   a colour rather than a shape. */
.controls--galleries { gap: 0; padding-bottom: 4px; }

.gallery {
  display: grid;
  gap: 8px;
  margin: 8px 0 14px;
}
.gallery--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.gallery--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.gallery--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }

.gallery-item {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 5px;
  padding: 5px 5px 6px;
  border: 1px solid transparent;
  border-radius: 11px;
  background: none;
  color: var(--md-sys-color-on-surface-variant);
  font: inherit;
  cursor: pointer;
  /* The selected state is a ring rather than a fill, so the swatch inside is
     never judged against a background that only the selected one has. */
  transition: border-color var(--md-sys-motion-duration-short) var(--md-sys-motion-standard),
              background-color var(--md-sys-motion-duration-short) var(--md-sys-motion-standard);
}
/* Folded behind Show more. The rule above sets display, which beats the
   hidden attribute on its own. */
.gallery-item[hidden] { display: none; }
.gallery-item:hover { background: var(--md-sys-color-surface-container); }
.gallery-item:focus-visible {
  outline: 2px solid var(--md-sys-color-on-surface);
  outline-offset: 1px;
}
.gallery-item[data-on="true"] {
  border-color: var(--md-sys-color-on-surface);
  background: var(--md-sys-color-surface-container);
  color: var(--md-sys-color-on-surface);
}

/* Sized from the canvas's own dimensions rather than by a fixed ratio, so the
   preview is the shape of the frame you are actually making. Both maxima are
   needed: the width one keeps a panoramic frame inside its column, the height
   one stops a nine by sixteen turning the gallery into a skyscraper. */
.gallery-thumb {
  display: block;
  max-width: 100%;
  max-height: 92px;
  width: auto;
  height: auto;
  margin: 0 auto;
  border-radius: 7px;
  /* A hairline, because several of the backdrops are nearly the colour of the
     panel and would otherwise have no edge at all. */
  box-shadow: inset 0 0 0 1px var(--md-sys-color-outline-variant);
  background: var(--md-sys-color-surface-container-high);
}

.gallery-name {
  font-size: 11px;
  line-height: 14px;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The heading above the sliders, which are a different kind of thing from the
   galleries above them and need a stronger break than another group title. */
.group-title--major {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--md-sys-color-outline-variant);
  color: var(--md-sys-color-on-surface);
}

/* ---------- the two halves of the panel ---------- */

/* The panel had grown to four galleries and sixteen sliders in one column, and
   the bottom half of it was never seen. Splitting it is the same split every
   tool of this kind arrives at: the thing you are posing, and everything
   around it. */
.tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px;
  margin: 0 0 14px;
  padding: 3px;
  border-radius: 10px;
  background: var(--md-sys-color-surface-container);
}
.tab {
  padding: 7px 10px;
  border: none;
  border-radius: 7px;
  background: none;
  color: var(--md-sys-color-on-surface-variant);
  font: 500 13px/16px var(--md-sys-typescale-plain-font);
  cursor: pointer;
}
.tab:hover { color: var(--md-sys-color-on-surface); }
.tab[data-on="true"] {
  background: var(--md-sys-color-surface);
  color: var(--md-sys-color-on-surface);
  box-shadow: var(--app-hairline);
}
.tab:focus-visible { outline: 2px solid var(--md-sys-color-on-surface); outline-offset: -2px; }

/* ---------- ground swatches ---------- */

/* A colour can be read off a small square, so these are square and small.
   Four to a row, which fits thirteen grounds in the space three full
   compositions used to take. */
.gallery-item--ground { gap: 4px; padding: 3px; }
.gallery-item--ground .gallery-thumb {
  max-height: none;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 6px;
}
.gallery-item--ground .gallery-name { font-size: 10px; line-height: 13px; }

/* ---------- the frame ---------- */

/* Three across and two down. Six in one row gave each button about forty
   pixels, which is the width of the widest shape and nothing to spare, so the
   landscape frames sat edge to edge with their buttons and read as a strip of
   outlines rather than as six choices. A third of the panel each gives every
   shape room around it. */
.frames { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; margin: 8px 0 6px; }
.frame-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Centred, where it used to be bottom-aligned so that the row of names
     underneath sat on one line. The names are inside the shapes now, so there
     is no line to keep. */
  justify-content: center;
  height: 62px;
  /* No side padding. The button is barely wider than its widest shape, and
     two pixels either side left less room inside than the shape needed: the
     overhang was clipped by the button's overflow, which took exactly the
     outline's width off each side and left the landscape frames as two
     horizontal lines. */
  padding: 6px 0;
  min-width: 0;
  border: 1px solid transparent;
  border-radius: 9px;
  background: none;
  color: var(--md-sys-color-on-surface-variant);
  font: inherit;
  cursor: pointer;
}
.frame-item:hover { background: var(--md-sys-color-surface-container); }
.frame-item[data-on="true"] {
  border-color: var(--md-sys-color-on-surface);
  background: var(--md-sys-color-surface-container);
  color: var(--md-sys-color-on-surface);
}
.frame-item:focus-visible { outline: 2px solid var(--md-sys-color-on-surface); outline-offset: 1px; }

/* Proportioned from the ratio itself rather than drawn per shape, so the little
   rectangle cannot disagree with the numbers printed under it. */
.frame-shape {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Forty rather than twenty-six, because the label lives in here now and the
     narrowest shape — nine by sixteen — is only a bit over half the long side
     wide. At twenty-six that came to fifteen pixels, which fits no text at
     all. The twelve pixels the label used to take up underneath pay for most
     of the increase. */
  /* Forty-four on the long side: with three to a row each button has room to
     spare across, and the height is what limits it — sixty tall, less the
     padding and the border, leaves forty-six for the tallest shape. */
  width: calc(var(--w) / max(var(--w), var(--h)) * 44px);
  /* Held to its proportions and never wider than the button it sits in, so a
     narrower panel scales the rectangle down rather than cropping its sides.
     The height follows from the ratio instead of being set beside it, which
     is what lets it shrink with the width. */
  aspect-ratio: var(--w) / var(--h);
  max-width: 100%;
  box-sizing: border-box;
  border: 1.5px solid currentColor;
  border-radius: 3px;
  opacity: 0.75;
}
.frame-item[data-on="true"] .frame-shape { opacity: 1; }
/* Small enough to sit inside the narrowest of them with room either side, and
   tabular so the colons line up down the row. */
.frame-name {
  font-size: 9px;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

/* ---------- denser sliders ---------- */

/* The panel carries a lot of them, and every pixel of height between the label
   and its track is a pixel of gallery somebody has to scroll past. */
.controls { gap: 11px; }
.md-slider .row { margin-bottom: 1px; }
.md-slider .row label { font-size: 12px; }

/* ---------- the layouts column ---------- */

/* One preview per row, as large as the column allows. These are the control
   people reach for first, and a pose is the one thing in the tool that cannot
   be judged small. */
.panel--layers .scroll { padding: 10px; }
/* ---------- the layers panel ---------- */

.layers { display: flex; flex-direction: column; gap: 6px; }

/* A card: the picture down the left, the name beside it, the eye and the bin
   under the name, and the arrows at the right.

   A grid rather than a row of rows, so the picture can span the whole height
   whatever is stacked next to it, and so the name and the tools under it line
   up on the same left edge. */
.layer {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-rows: auto auto;
  align-items: center;
  column-gap: 12px;
  padding: 10px;
  border: 1px solid transparent;
  border-radius: 16px;
  background: var(--md-sys-color-surface-container-low);
}
.layer[data-on="true"] {
  border-color: var(--md-sys-color-on-surface);
  background: var(--md-sys-color-surface-container);
}
/* Hidden says so by going quiet, and the picture goes quieter than the name:
   what is switched off is the layer, not the row you still have to read. */
.layer[data-hidden="true"] .layer-thumb { opacity: 0.25; }

/* The thing that selects: stretched across the whole card, behind everything
   else in it. A button cannot contain another button, so the tools cannot sit
   inside the one that selects — and a card whose picture did not select would
   have a dead spot exactly where the eye goes first. */
.layer-pick {
  position: absolute;
  inset: 0;
  width: 100%;
  padding: 0;
  border: none;
  border-radius: inherit;
  background: none;
  cursor: pointer;
}

.layer-thumb,
.layer-add {
  grid-column: 1;
  grid-row: 1 / span 2;
  width: 84px;
  height: 64px;
  flex: none;
  border-radius: 10px;
}
.layer-thumb {
  background: var(--md-sys-color-surface-container-high);
  object-fit: cover;
}

/* An empty layer's slot: the same box the picture would fill, holding the
   offer to fill it. Dashed, because a dashed box is the one shape that reads
   as "something goes here" without a word of explanation. Above the stretched
   button, since it does something else. */
.layer-add {
  position: relative;
  z-index: 1;
  display: grid;
  place-content: center;
  padding: 0;
  border: 1px dashed var(--md-sys-color-outline);
  background: none;
  color: var(--md-sys-color-on-surface-variant);
  cursor: pointer;
}
.layer-add:hover {
  border-style: solid;
  background: var(--md-sys-color-surface-container-high);
  color: var(--md-sys-color-on-surface);
}
.layer-add:focus-visible {
  outline: 2px solid var(--md-sys-color-on-surface);
  outline-offset: 2px;
}

.layer-label {
  grid-column: 2;
  grid-row: 1;
  align-self: end;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-bottom: 2px;
}
.layer-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 15px;
  color: var(--md-sys-color-on-surface-variant);
}
/* An empty row says what to do with it, once, and stops saying it the moment
   there is a picture to look at instead. */
.layer-hint {
  font-size: 11px;
  line-height: 14px;
  color: var(--md-sys-color-on-surface-variant);
}

/* The two that act on the layer itself, under its name; and the two that move
   it through the stack, at the right. Both above the stretched button. */
.layer-tools {
  grid-column: 2;
  grid-row: 2;
  align-self: start;
  position: relative;
  z-index: 1;
  display: flex;
  gap: 2px;
  margin-left: -6px;
}
.layer-order {
  grid-column: 3;
  grid-row: 1 / span 2;
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
}

.layer-tool,
.layer-step {
  display: grid;
  place-content: center;
  width: 30px;
  height: 28px;
  padding: 0;
  border: none;
  border-radius: 8px;
  background: none;
  color: var(--md-sys-color-on-surface);
  cursor: pointer;
}
.layer-step { height: 24px; color: var(--md-sys-color-on-surface-variant); }
.layer-tool:hover,
.layer-step:hover { background: var(--md-sys-color-surface-container-highest); }
.layer-tool:disabled,
.layer-step:disabled { opacity: 0.3; cursor: default; }
.layer-tool:disabled:hover,
.layer-step:disabled:hover { background: none; }

/* The plus in the panel's header, which makes a layer and asks for a picture. */
.layer-adds { display: flex; gap: 4px; }

.add-layer {
  display: grid;
  place-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--md-sys-color-outline-variant);
  border-radius: 8px;
  background: none;
  color: var(--md-sys-color-on-surface-variant);
  cursor: pointer;
}
.add-layer:hover { background: var(--md-sys-color-surface-container-high); }

@media (min-width: 961px) and (max-width: 1280px) {
  .panel--layers .scroll { padding: 8px; }
}

@media (max-width: 960px) {
  .layers { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); }
}

@media (prefers-reduced-motion: reduce) { .layer-tools { transition: none; } }

/* ---------- a heading with an action against it ---------- */

.group-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  margin: 10px 0 -4px;
}
.group-head:first-child { margin-top: 0; }
.group-head .group-title { margin: 0; }
.group-action {
  border: none;
  background: none;
  padding: 2px 4px;
  border-radius: 6px;
  color: var(--md-sys-color-on-surface-variant);
  font: 500 11px/16px var(--md-sys-typescale-plain-font);
  letter-spacing: 0.4px;
  text-transform: uppercase;
  cursor: pointer;
}
.group-action:hover { color: var(--md-sys-color-on-surface); background: var(--md-sys-color-surface-container); }
.group-action:focus-visible { outline: 2px solid var(--md-sys-color-on-surface); outline-offset: 1px; }

/* ---------- three answers, not a hundred ---------- */

.segmented {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 3px;
  margin: 8px 0 2px;
  padding: 3px;
  border-radius: 9px;
  background: var(--md-sys-color-surface-container);
}
.segment {
  padding: 6px 4px;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--md-sys-color-on-surface-variant);
  font: 500 12px/15px var(--md-sys-typescale-plain-font);
  cursor: pointer;
}
.segment:hover:not(:disabled) { color: var(--md-sys-color-on-surface); }
.segment[data-on="true"] {
  background: var(--md-sys-color-surface);
  color: var(--md-sys-color-on-surface);
  box-shadow: var(--app-hairline);
}
/* Disabled because a device dictates its own corner, so none of these is in
   force and claiming one would be a lie about what the picture is doing. */
.segment:disabled { opacity: 0.4; cursor: default; }
.segment:focus-visible { outline: 2px solid var(--md-sys-color-on-surface); outline-offset: -2px; }

/* ---------- snapping guides ---------- */

/* Laid over the canvas and sized to it by the render loop. Never inside it: an
   export is built from the canvas alone, so a guide cannot reach a saved file
   and there is nothing to remember to hide. */
.guides { position: absolute; pointer-events: none; z-index: 4; }

.guide {
  position: absolute;
  opacity: 0;
  background: var(--md-sys-color-on-surface);
  transition: opacity 90ms var(--md-sys-motion-standard);
}
.guide[data-on="true"] { opacity: 0.8; }
.guide--v { top: 0; bottom: 0; width: 1px; margin-left: -0.5px; }
.guide--h { left: 0; right: 0; height: 1px; margin-top: -0.5px; }

/* The middle is the one worth shouting about; a third or an edge is a weaker
   claim and says so, so that a glance at the guide tells you which of the three
   you landed on without reading anything. */
.guide[data-on="true"][data-kind="third"] { opacity: 0.42; }
.guide[data-on="true"][data-kind="edge"] { opacity: 0.55; }
/* Half out of frame lands on the frame's edge, the same line a flush card
   draws, so it is drawn at the same weight — the two are the same claim about
   the same place, made about different parts of the card. */
.guide[data-on="true"][data-kind="half"] { opacity: 0.55; }

@media (prefers-reduced-motion: reduce) { .guide { transition: none; } }

/* The cursor answers "is there anything here".
 *
 * A move cursor over the whole canvas was a small lie: most of a composition is
 * backdrop, and offering to move something where there is nothing to move
 * invites a drag that does something other than what the pointer promised. So
 * the plain arrow means empty, and the cursor changes only over a card — which
 * doubles as the hover feedback that says a card can be picked up at all.
 *
 * Set from a hit test on every move, so the boundary is the card's real edge
 * rather than its bounding box: over the outside corner of a turned card the
 * cursor stays an arrow, and a click there does what an arrow implies. */
.viewport canvas#stage { cursor: default; }
.viewport canvas#stage[data-over="card"] { cursor: move; }
.viewport canvas#stage.posing { cursor: grabbing; }
.viewport canvas#stage.sliding { cursor: move; }

/* ---------- what sits over the canvas ---------- */

/* Nothing at all, which is the point.
 *
 * The viewport used to carry a hint chip at one corner, a credit badge at the
 * other and a dock along the bottom, and all three competed with the
 * composition — which is the only thing in this column anybody is looking at.
 * The chip's text moved into the shortcuts list, where half of it was repeated
 * anyway; the dock's actions and the badge were taken out. What is left over
 * the canvas is the canvas.
 */

/* The canvas is now the only thing with an edge in this column, so it keeps the
   corner and the hairline the panel used to carry. */
.viewport canvas#stage {
  border-radius: var(--md-sys-shape-corner-l);
}

/* ---------- where the light is ---------- */

/* Twenty-five cells, square, so the grid is a picture of the ground the light
   is standing on rather than a row of options. It is sized to the panel and
   kept square by aspect-ratio, which means it stays a grid of squares at every
   panel width without any arithmetic. */
.light-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 3px;
  margin: 8px 0 4px;
  padding: 3px;
  border-radius: 9px;
  background: var(--md-sys-color-surface-container-high);
  /* Square and full width. Square because the grid is a picture of the ground
     the light stands on: a cell in the corner has to look like forty-five
     degrees, and it only does if a step across is the same size as a step down.
     Full width because it is the control this section is for, and at two thirds
     of the column it read as a diagram of something rather than a thing to
     press. */
  aspect-ratio: 1;
  width: 100%;
}

/* Every cell has a ground of its own, so the control reads as a grid of
   places to put the light rather than as a blank box with one mark in it. */
.light-cell {
  border: none;
  border-radius: 5px;
  background: var(--md-sys-color-surface);
  padding: 0;
  cursor: pointer;
  position: relative;
}
.light-cell:hover { background: var(--md-sys-color-surface-container-highest); }
.light-cell:focus-visible { outline: 2px solid var(--md-sys-color-on-surface); outline-offset: -2px; }
.light-cell[data-on="true"] {
  background: var(--md-sys-color-on-surface);
}

/* The sun sits in every cell and is shown in one of them, so moving the light
   needs no rebuilding and no cell can end up holding two marks. */
.light-sun {
  display: grid;
  place-items: center;
  position: absolute;
  inset: 0;
  opacity: 0;
  color: var(--md-sys-color-surface);
}
.light-sun svg { width: 20px; height: 20px; fill: currentColor; }
.light-cell[data-on="true"] .light-sun { opacity: 1; }

/* The middle cell is where the card is, not a place to put a light — so it is
   drawn as the card. Pressing it is still meaningful: it is the light directly
   behind the viewer, with the shadow squarely behind the picture. */
.light-cell[data-mid="true"]::after {
  content: "";
  position: absolute;
  /* Wider than tall, so it reads as the card rather than as one more square in
     a grid of squares. */
  inset: 30% 20%;
  border-radius: 2px;
  border: 1px solid var(--md-sys-color-on-surface-variant);
  opacity: 0.6;
}
/* Hidden when the light is standing on it, since the sun is there instead and
   two marks in one cell is a puzzle rather than a picture. */
.light-cell[data-mid="true"][data-on="true"]::after { display: none; }

/* ---------- the export button, and the chevron beside it ---------- */

/* One control split in two: the press you nearly always want, and the way to
   change what that press does. Joined into one shape by squaring the inner
   corners, so it reads as a single button with a handle rather than as two
   buttons that happen to be touching. */
.split { display: flex; align-items: stretch; }
.split > .md-button:first-child {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  padding-inline: 16px 14px;
}
.split-more {
  min-width: 0;
  padding: 0 8px;
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  /* A hairline of the bar showing through, which is what separates the two
     halves. A border would change the button's height. */
  box-shadow: inset 1px 0 0 var(--md-sys-color-surface);
}
.split-more svg { width: 18px; height: 18px; }

/* ---------- a caption under a control ---------- */

/* Used by the frame's export size and by the light grid. It had no rules at
   all, so it rendered at body size and full weight and read as a sentence
   somebody had left in the panel rather than as a note about the control above
   it. Same size and colour as a slider's readout, which is what it is. */
.preset-hint {
  margin: 2px 0 4px;
  color: var(--md-sys-color-on-surface-variant);
  font: 400 11px/16px var(--md-sys-typescale-plain-font);
}

/* ---------- the dialkit trial ---------- */

/* dialkit brings its own surface, radius and shadow, so the host gives it room
   and nothing else. Negative side margins let its panel run to the edge of the
   column the way our own controls do, since it carries its own padding. */
.dial-host {
  margin: 6px -2px 2px;
  min-height: 40px;
}
.dial-host[data-failed="true"] {
  color: var(--md-sys-color-error);
  font: 400 12px/16px var(--md-sys-typescale-plain-font);
}

/* Its panel is built to float over a page. Inline in a column it should not
   also be pretending to hover, so the drop shadow comes off — this tool has no
   shadows in its chrome, which is the one house rule worth keeping while the
   rest of the look is being tried out. */
.dial-host .dialkit-root {
  --dial-shadow: none;
  --dial-shadow-collapsed: none;
}

}

/* A single dialkit control standing on its own, for a panel that interleaves
   its sliders with pickers rather than listing them. It carries the root class
   itself, since that is what the stylesheet hangs its variables on, and none of
   the panel's own chrome — no card, no title, no padding of its own. */
.dial-row {
  margin: 0;
  background: none;
}
.dial-row[data-failed="true"] {
  color: var(--md-sys-color-error);
  font: 400 12px/16px var(--md-sys-typescale-plain-font);
}

/* dialkit's preset manager, and the clipboard button beside it.
 *
 * They are developer furniture: the dropdown saves named versions of the
 * panel's values, and the button copies a `createDialKit` snippet to paste back
 * into source. dialkit is a tuning panel for people building an interface, and
 * both make sense there — in a shipped tool they are two controls that do
 * nothing anybody came here to do, sitting above the ones that do.
 *
 * Hidden here rather than patched out of `vendor/dialkit/`, which would be
 * undone by the next `npm run vendor`, and there is no option for it. */
/* Two classes deep on purpose: dialkit's own sheet is injected into the head
   when the script loads, so it comes after this file, and a one-class selector
   loses the tie to the display it sets. */
.dialkit-root .dialkit-panel-toolbar,
.dialkit-root .dialkit-panel-section-toolbar { display: none; }
