/* ==========================================================================
   DotRot — style.css
   Dark terminal brutalism. Hairline rules, no radii, mono for every label.
   One phosphor-amber accent. Bungee is kept for the wordmark and nothing else
   in the interface.
   ========================================================================== */

/* ---------------------------------------------------------------- tokens */
:root {
  /* Not pure black. #0a0a0a keeps the hairlines visible and stops the screen
     from looking like it is switched off. */
  --bg:          #0a0a0a;
  --bg-stage:    #060606;
  --panel:       #0e0e0e;
  --panel-2:     #131313;
  --panel-3:     #181818;

  --line:        #212121;
  --line-2:      #2e2e2e;
  --line-hot:    #4a3c1a;

  /* Warm off-white, not #fff. Reads as paper under a CRT. */
  --ink:         #e9e4da;
  --ink-2:       #9a938a;
  --ink-3:       #625d55;
  --ink-4:       #3d3934;

  --accent:      #ffffff;
  --accent-2:    #ffc94d;
  --accent-dim:  #6b4a08;
  --accent-ghost:rgba(255, 176, 0, 0.10);

  --danger:      #ff4d3d;

  --rail-w:      336px;
  --adrail-w:    0px;
  --bar-h:       52px;
  --status-h:    28px;

  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  /* Bungee is uppercase-only by design: lowercase codepoints map to caps, so
     "DotRot" sets as DOTROT. That is the intended look for a signage face. */
  --display: "Bungee", "Arial Black", Impact, sans-serif;

  --t: 90ms cubic-bezier(.4, 0, .2, 1);
}

body.ads-on { --adrail-w: 176px; }

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

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button, input, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; padding: 0; }

::selection { background: var(--accent); color: #000; }

:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 1px;
}

/* Very faint horizontal scan texture over the whole UI. Two percent opacity:
   you should feel it, not see it. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9999;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255, 255, 255, .022) 0 1px,
    transparent 1px 3px
  );
  mix-blend-mode: overlay;
}

/* ---------------------------------------------------------------- shell */
.app {
  display: grid;
  grid-template-rows: var(--bar-h) 1fr var(--status-h);
  height: 100dvh;
  overflow: hidden;
}

.layout {
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr) var(--adrail-w);
  min-height: 0;
  border-block: 1px solid var(--line);
  border-color: var(--line) transparent;
}

/* ---------------------------------------------------------------- topbar */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 0 14px 0 16px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}

.brand {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}

.brand__mark {
  width: 17px;
  height: 17px;
  color: var(--accent);
  flex: none;
}

/* The display face appears here and nowhere else. Bungee is already heavy and
   tightly fitted, so it needs a smaller size than a text face would and a
   little positive tracking to stop the caps jamming together. */
.brand__word {
  margin: 0;
  font-family: var(--display);
  font-size: 19px;
  font-weight: 400;
  letter-spacing: .01em;
  line-height: 1;
  white-space: nowrap;
  padding-bottom: 1px;
}
/* Bungee ships no italic, so the second half is split by colour alone. */
.brand__word em {
  font-style: normal;
  color: var(--accent);
}

.brand__rule {
  width: 1px;
  height: 18px;
  background: var(--line-2);
  flex: none;
}

.brand__tag {
  font-size: 9.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}

.topbar__actions { display: flex; gap: 6px; align-items: center; }

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 28px;
  padding: 0 11px;
  border: 1px solid var(--line-2);
  background: var(--panel-2);
  color: var(--ink-2);
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  transition: color var(--t), border-color var(--t), background var(--t);
}
.btn:hover { color: var(--ink); border-color: var(--ink-3); background: var(--panel-3); }
.btn:active { transform: translateY(1px); }

.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #120c00;
  font-weight: 700;
}
.btn--primary:hover { background: var(--accent-2); border-color: var(--accent-2); color: #120c00; }

.btn__key {
  display: grid;
  place-items: center;
  width: 14px;
  height: 14px;
  border: 1px solid currentColor;
  opacity: .45;
  font-size: 9px;
  line-height: 1;
}
.btn--primary .btn__key { opacity: .55; }

.btn:disabled { opacity: .35; pointer-events: none; }

.iconbtn {
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-2);
  background: var(--panel-2);
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1;
}
.iconbtn:hover { color: var(--accent); border-color: var(--line-hot); }

.chip {
  height: 22px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 9px;
  border: 1px solid var(--line-2);
  background: var(--panel-2);
  color: var(--ink-2);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  user-select: none;
}
.chip:hover { color: var(--ink); border-color: var(--ink-3); }
.chip.is-active { color: var(--accent); border-color: var(--line-hot); background: var(--accent-ghost); }
.chip--check { cursor: pointer; }
.chip--check input { margin: 0; accent-color: var(--accent); width: 11px; height: 11px; }

/* Dimmed, not removed. The control still tells you it exists, and its title
   says which condition is missing. */
.chip.is-disabled,
.chip.is-disabled:hover {
  opacity: .38;
  cursor: not-allowed;
  color: var(--ink-3);
  border-color: var(--line);
}
.chip.is-disabled input { cursor: not-allowed; }

.linkbtn {
  color: var(--accent);
  border-bottom: 1px solid var(--accent-dim);
  padding-bottom: 1px;
}
.linkbtn:hover { border-bottom-color: var(--accent); }

/* ---------------------------------------------------------------- rail */
.rail {
  border-right: 1px solid var(--line);
  background: var(--panel);
  overflow-y: auto;
  overscroll-behavior: contain;
  min-height: 0;
}

.rail::-webkit-scrollbar { width: 9px; }
.rail::-webkit-scrollbar-track { background: var(--panel); }
.rail::-webkit-scrollbar-thumb { background: var(--line-2); border: 3px solid var(--panel); }
.rail::-webkit-scrollbar-thumb:hover { background: var(--ink-4); }

/* ---- rail header ----
   Pinned above the panels: both the look button and the tier switch act on
   every panel at once, so neither belongs inside one. */
.railhead {
  position: sticky;
  top: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  background: var(--panel-2);
}

.lookbtn {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 28px;
  padding: 0 9px;
  border: 1px solid var(--line-2);
  background: var(--panel-3);
  transition: border-color var(--t);
}
.lookbtn:hover { border-color: var(--ink-3); }

.lookbtn__key {
  font-size: 9.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-4);
  flex: none;
}
.lookbtn__name {
  flex: 1;
  min-width: 0;
  text-align: left;
  font-size: 11.5px;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lookbtn__caret { font-size: 9px; color: var(--ink-3); flex: none; }

/* Two-state segmented switch. */
.tierswitch { display: flex; flex: none; border: 1px solid var(--line-2); }
.tierswitch__btn {
  height: 26px;
  padding: 0 8px;
  font-size: 9.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-4);
  background: var(--panel-2);
  transition: color var(--t), background var(--t);
}
.tierswitch__btn + .tierswitch__btn { border-left: 1px solid var(--line-2); }
.tierswitch__btn:hover { color: var(--ink-2); }
.tierswitch__btn.is-on { color: #120c00; background: var(--accent); font-weight: 700; }

/* ---- effect row ---- */
.field--effecthead { padding: 0; border-top: 1px solid #161616; }
.field--effecthead > .field__top {
  min-height: 32px;
  padding: 4px 0;
  cursor: pointer;
}
.field--effecthead > .field__top:hover .field__label { color: var(--ink); }
.field--effecthead.is-on > .field__top .field__label {
  color: var(--accent);
  letter-spacing: .1em;
}

/* Indented and rule-marked so the parameters read as belonging to the
   effect above them rather than as more top-level controls. */
.field__effectbody {
  padding: 2px 0 8px 10px;
  margin-left: 2px;
  border-left: 1px solid var(--line-hot);
}
.field__effectbody .field { padding-top: 4px; }
.field__effectbody .field + .field { border-top: none; }

.field[data-field] .field__effectbody .field__label { color: var(--ink-3); }

/* Dependent controls declared with `child: true`. */
.field.is-child {
  padding-left: 10px;
  margin-left: 2px;
  border-left: 1px solid var(--line-hot);
  border-top: none;
}

/* ---- palette grid ---- */
.palgrid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px;
  margin-top: 8px;
  max-height: 268px;
  overflow-y: auto;
  padding-right: 3px;
}
.palgrid::-webkit-scrollbar { width: 7px; }
.palgrid::-webkit-scrollbar-track { background: transparent; }
.palgrid::-webkit-scrollbar-thumb { background: var(--line-2); }

.palgrid__group {
  grid-column: 1 / -1;
  font-size: 9px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding: 7px 0 2px;
}

.palgrid__item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 3px;
  border: 1px solid transparent;
  text-align: left;
  transition: border-color var(--t), background var(--t);
}
.palgrid__item:hover { border-color: var(--line-2); background: var(--panel-2); }
.palgrid__item.is-on { border-color: var(--accent); background: var(--accent-ghost); }

.palgrid__strip { display: flex; height: 14px; border: 1px solid #000; }
.palgrid__strip i { flex: 1 1 0; min-width: 1px; }

.palgrid__name {
  font-size: 9.5px;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.palgrid__item.is-on .palgrid__name { color: var(--accent); }

/* ---- export popover ---- */
.exportgroup { position: relative; display: inline-flex; }
.btn--chev { padding: 0 6px; border-left: 1px solid rgba(0, 0, 0, .28); }

.popover {
  position: absolute;
  top: calc(100% + 5px);
  right: 0;
  z-index: 60;
  width: 236px;
  padding: 10px 12px 12px;
  border: 1px solid var(--line-2);
  background: var(--panel);
  box-shadow: 0 18px 40px -12px rgba(0, 0, 0, .85);
  text-align: left;
}
.popover__title {
  font-size: 9.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 2px;
}

/* ---- panel (accordion) ---- */
.panel { border-bottom: 1px solid var(--line); }

.panel__head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 9px;
  height: 34px;
  padding: 0 12px;
  text-align: left;
  color: var(--ink-2);
  transition: color var(--t), background var(--t);
}
.panel__head:hover { color: var(--ink); background: var(--panel-2); }

.panel__caret {
  font-size: 9px;
  width: 8px;
  color: var(--ink-3);
  transition: transform var(--t);
}
.panel.is-open .panel__caret { transform: rotate(90deg); color: var(--accent); }

.panel__label {
  font-size: 10.5px;
  letter-spacing: .15em;
  text-transform: uppercase;
  font-weight: 500;
}
.panel.is-open .panel__label { color: var(--ink); }

/* Amber pip appears when anything inside the panel is off its default, so
   you can see what you have touched without opening every section. */
.panel__dot {
  margin-left: auto;
  width: 4px;
  height: 4px;
  background: var(--accent);
  opacity: 0;
  transition: opacity var(--t);
}
.panel.is-dirty .panel__dot { opacity: 1; }

/* A panel with nothing visible left in it is a header for an empty room.
   In Basic mode that is most of them. */
.panel.is-empty { display: none; }

.panel__body {
  display: none;
  padding: 4px 12px 14px;
  border-top: 1px solid var(--line);
  background: #0c0c0c;
}
.panel.is-open .panel__body { display: block; }

.panel__hint {
  font-size: 10px;
  color: var(--ink-4);
  letter-spacing: .03em;
  margin: 8px 0 10px;
  line-height: 1.5;
}

/* ---- field ---- */
.field { padding: 7px 0; }
.field + .field { border-top: 1px solid #161616; }
.field.is-hidden { display: none; }

.field__top {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 20px;
}

.field__label {
  font-size: 10.5px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-2);
  flex: 1;
  min-width: 0;
  cursor: default;
}
.field.is-dirty .field__label { color: var(--ink); }

/* Small ? that reveals the explanatory line. Help stays out of the way
   until asked for. A dense panel shouldn't be 50% prose. */
.field__help {
  width: 13px;
  height: 13px;
  flex: none;
  display: grid;
  place-items: center;
  border: 1px solid var(--line-2);
  color: var(--ink-4);
  font-size: 9px;
  line-height: 1;
}
.field__help:hover, .field__help.is-on { color: var(--accent); border-color: var(--line-hot); }

.field__note {
  display: none;
  font-size: 10px;
  line-height: 1.55;
  color: var(--ink-3);
  letter-spacing: .02em;
  margin-top: 7px;
  padding-left: 9px;
  border-left: 1px solid var(--accent-dim);
}
.field__note.is-on { display: block; }

/* ---- numeric readout / editable value ---- */
.field__num {
  width: 58px;
  flex: none;
  height: 20px;
  padding: 0 5px;
  text-align: right;
  background: var(--panel-2);
  border: 1px solid transparent;
  color: var(--ink);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
}
.field__num::-webkit-outer-spin-button,
.field__num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.field__num:hover { border-color: var(--line-2); }
.field__num:focus { border-color: var(--accent); background: #000; outline: none; }

.field__unit {
  font-size: 10px;
  color: var(--ink-4);
  width: 13px;
  flex: none;
}

/* ---- range ---- */
.field__range {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: 18px;
  margin: 5px 0 1px;
  background: transparent;
  cursor: ew-resize;
}

/* Track is painted as a gradient so the filled portion needs no extra
   element; --fill is written by ui.js on input. */
.field__range::-webkit-slider-runnable-track {
  height: 2px;
  background:
    linear-gradient(to right, var(--accent) 0 var(--fill, 50%), var(--line-2) var(--fill, 50%) 100%);
}
.field__range::-moz-range-track {
  height: 2px;
  background:
    linear-gradient(to right, var(--accent) 0 var(--fill, 50%), var(--line-2) var(--fill, 50%) 100%);
}

.field__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 3px;
  height: 13px;
  margin-top: -5.5px;
  background: var(--ink);
  border: none;
  border-radius: 0;
  box-shadow: 0 0 0 3px var(--bg);
}
.field__range::-moz-range-thumb {
  width: 3px;
  height: 13px;
  background: var(--ink);
  border: none;
  border-radius: 0;
  box-shadow: 0 0 0 3px var(--bg);
}
.field__range:hover::-webkit-slider-thumb { background: var(--accent); }
.field__range:hover::-moz-range-thumb { background: var(--accent); }

/* Ticks under the slider give the eye a reference for centre/extremes. */
.field__ticks {
  display: flex;
  justify-content: space-between;
  font-size: 9px;
  color: var(--ink-4);
  letter-spacing: .04em;
  margin-top: -1px;
}

/* ---- select ---- */
.field__select {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 26px;
  margin-top: 6px;
  padding: 0 24px 0 8px;
  background: var(--panel-2);
  border: 1px solid var(--line-2);
  color: var(--ink);
  font-size: 11.5px;
  letter-spacing: .02em;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
    linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: calc(100% - 13px) 11px, calc(100% - 9px) 11px;
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
}
.field__select:hover { border-color: var(--ink-3); }
.field__select:focus { border-color: var(--accent); outline: none; }
.field__select optgroup {
  background: var(--panel);
  color: var(--ink-3);
  font-style: normal;
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.field__select option { background: var(--panel-2); color: var(--ink); }

/* ---- toggle ---- */
.field--toggle .field__top { cursor: pointer; }
.field--toggle .field__top:hover .field__label { color: var(--ink); }

.field__switch {
  width: 26px;
  height: 14px;
  flex: none;
  border: 1px solid var(--line-2);
  background: var(--panel-2);
  position: relative;
  transition: border-color var(--t), background var(--t);
}
.field__switch::after {
  content: "";
  position: absolute;
  inset: 2px auto 2px 2px;
  width: 8px;
  background: var(--ink-4);
  transition: transform var(--t), background var(--t);
}
.field__switch.is-on { border-color: var(--line-hot); background: var(--accent-ghost); }
.field__switch.is-on::after { transform: translateX(12px); background: var(--accent); }

/* ---- colour ---- */
.field__color { display: flex; align-items: center; gap: 6px; flex: none; }

.field__color input[type="color"] {
  -webkit-appearance: none;
  appearance: none;
  width: 22px;
  height: 20px;
  padding: 0;
  border: 1px solid var(--line-2);
  background: none;
  cursor: pointer;
}
.field__color input[type="color"]::-webkit-color-swatch-wrapper { padding: 2px; }
.field__color input[type="color"]::-webkit-color-swatch { border: none; }
.field__color input[type="color"]::-moz-color-swatch { border: none; }
.field__color input[type="color"]:hover { border-color: var(--ink-3); }

.field__hex {
  width: 74px;
  height: 20px;
  padding: 0 5px;
  background: var(--panel-2);
  border: 1px solid transparent;
  color: var(--ink-2);
  font-size: 11px;
  text-transform: uppercase;
}
.field__hex:hover { border-color: var(--line-2); }
.field__hex:focus { border-color: var(--accent); background: #000; color: var(--ink); outline: none; }

/* ---- custom swatch editor ---- */
.swatches { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; }

.swatch {
  position: relative;
  width: 30px;
  height: 30px;
  border: 1px solid var(--line-2);
  padding: 0;
  cursor: pointer;
  overflow: hidden;
}
.swatch input[type="color"] {
  position: absolute;
  inset: -4px;
  width: calc(100% + 8px);
  height: calc(100% + 8px);
  border: none;
  padding: 0;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  background: none;
}
.swatch__kill {
  position: absolute;
  top: 0; right: 0;
  width: 12px; height: 12px;
  display: grid;
  place-items: center;
  background: #000;
  color: var(--ink-2);
  font-size: 10px;
  line-height: 1;
  opacity: 0;
  transition: opacity var(--t);
}
.swatch:hover .swatch__kill { opacity: 1; }
.swatch__kill:hover { color: var(--danger); }

.swatch--add {
  display: grid;
  place-items: center;
  border-style: dashed;
  color: var(--ink-3);
  font-size: 15px;
  background: none;
}
.swatch--add:hover { color: var(--accent); border-color: var(--line-hot); }

/* ---- active palette strip ---- */
.palstrip { margin-top: 12px; }
.palstrip__head {
  display: flex;
  justify-content: space-between;
  font-size: 9.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-4);
  margin-bottom: 5px;
}
.palstrip__bar {
  display: flex;
  height: 22px;
  border: 1px solid var(--line-2);
  overflow: hidden;
}
.palstrip__bar i { flex: 1 1 0; min-width: 2px; }
.palstrip__bar.is-empty { border-style: dashed; border-color: var(--line); }

/* ---------------------------------------------------------------- stage */
.stage {
  display: grid;
  grid-template-rows: 33px minmax(0, 1fr) auto;
  min-width: 0;
  min-height: 0;
  background: var(--bg-stage);
}

.stage__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 0 10px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}
.stage__group { display: flex; align-items: center; gap: 5px; }

.stage__zoom {
  min-width: 50px;
  height: 22px;
  padding: 0 6px;
  border: 1px solid transparent;
  color: var(--ink-2);
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
}
.stage__zoom:hover { color: var(--accent); border-color: var(--line-2); }

.stage__viewport {
  position: relative;
  overflow: auto;
  display: grid;
  place-items: center;
  padding: 28px;
  min-height: 0;
  /* Faint dot grid so the void reads as a workspace, not a dead area. */
  background-image: radial-gradient(circle, #161616 1px, transparent 1px);
  background-size: 22px 22px;
}
.stage__viewport::-webkit-scrollbar { width: 9px; height: 9px; }
.stage__viewport::-webkit-scrollbar-track { background: var(--bg-stage); }
.stage__viewport::-webkit-scrollbar-thumb { background: var(--line-2); border: 3px solid var(--bg-stage); }

.stage__canvas-wrap {
  position: relative;
  line-height: 0;
  border: 1px solid var(--line-2);
  box-shadow: 0 0 0 1px #000, 0 24px 60px -20px rgba(0, 0, 0, .9);
  background: #000;
}
.stage__canvas-wrap.is-checker {
  background-color: #171717;
  background-image:
    linear-gradient(45deg, #0e0e0e 25%, transparent 25% 75%, #0e0e0e 75%),
    linear-gradient(45deg, #0e0e0e 25%, transparent 25% 75%, #0e0e0e 75%);
  background-size: 14px 14px;
  background-position: 0 0, 7px 7px;
}
.stage.is-empty .stage__canvas-wrap { display: none; }

#canvas {
  display: block;
  /* Never let the browser smooth a dithered image; the pixel structure is
     the content. */
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

.stage__div {
  width: 1px; height: 14px; margin: 0 4px;
  background: var(--line-2); flex: none;
}

.histgroup { display: inline-flex; gap: 3px; margin-right: 3px; }
.iconbtn:disabled { opacity: .28; pointer-events: none; }

/* ---------------------------------------------------------------- crop ----
   Covers the canvas exactly, so a crop rect is just a percentage of this
   element. Everything outside the box is dimmed by four shadows rather than
   a cut-out, which keeps it to one element. */
.crop {
  position: absolute;
  inset: 0;
  z-index: 5;
  cursor: crosshair;
  touch-action: none;
}
.crop[hidden] { display: none; }

.crop__box {
  position: absolute;
  cursor: move;
  outline: 1px solid var(--accent);
  box-shadow: 0 0 0 4000px rgba(0, 0, 0, .68);
}

/* Thirds, for composition. */
.crop__grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(to right, transparent 33.33%, rgba(255,255,255,.22) 33.33% calc(33.33% + 1px), transparent calc(33.33% + 1px)),
    linear-gradient(to right, transparent 66.66%, rgba(255,255,255,.22) 66.66% calc(66.66% + 1px), transparent calc(66.66% + 1px)),
    linear-gradient(to bottom, transparent 33.33%, rgba(255,255,255,.22) 33.33% calc(33.33% + 1px), transparent calc(33.33% + 1px)),
    linear-gradient(to bottom, transparent 66.66%, rgba(255,255,255,.22) 66.66% calc(66.66% + 1px), transparent calc(66.66% + 1px));
}

.crop__h {
  position: absolute;
  width: 14px; height: 14px;
  background: var(--accent);
  border: 1px solid #000;
}
.crop__h--nw { left: -7px;  top: -7px;    cursor: nwse-resize; }
.crop__h--ne { right: -7px; top: -7px;    cursor: nesw-resize; }
.crop__h--sw { left: -7px;  bottom: -7px; cursor: nesw-resize; }
.crop__h--se { right: -7px; bottom: -7px; cursor: nwse-resize; }
.crop__h--n  { left: 50%; top: -7px;    margin-left: -7px; cursor: ns-resize; }
.crop__h--s  { left: 50%; bottom: -7px; margin-left: -7px; cursor: ns-resize; }
.crop__h--w  { top: 50%;  left: -7px;   margin-top: -7px;  cursor: ew-resize; }
.crop__h--e  { top: 50%;  right: -7px;  margin-top: -7px;  cursor: ew-resize; }

.crop__size {
  position: absolute;
  left: 0; bottom: -22px;
  padding: 1px 6px;
  background: #000;
  border: 1px solid var(--line-2);
  font-size: 10px;
  color: var(--ink-2);
  white-space: nowrap;
  pointer-events: none;
}

/* ---- crop toolbar ---- */
.cropbar {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 9px 12px;
  border-top: 1px solid var(--line-hot);
  background: var(--panel);
}
.cropbar[hidden] { display: none; }

.cropbar__aspects { display: flex; gap: 4px; flex-wrap: wrap; }

.cropbar__straighten {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: 1;
  min-width: 220px;
}
.cropbar__straighten > span {
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-3);
  flex: none;
}
.cropbar__straighten .field__range { margin: 0; flex: 1; }

.cropbar__deg {
  width: 46px;
  text-align: right;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  flex: none;
}

.cropbar__actions { display: flex; gap: 5px; margin-left: auto; }

.chip--go {
  background: var(--accent);
  border-color: var(--accent);
  color: #120c00;
  font-weight: 700;
}
.chip--go:hover { background: var(--accent-2); border-color: var(--accent-2); color: #120c00; }

/* Hide the compare and checker affordances while cropping; neither means
   anything against an uncropped preview. */
body.is-cropping .stage__group--right { opacity: .3; pointer-events: none; }

.stage__busy {
  position: absolute;
  bottom: 12px;
  left: 12px;
  padding: 4px 9px;
  background: var(--panel);
  border: 1px solid var(--line-hot);
  color: var(--accent);
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
}

/* ---- dropzone / empty state ---- */
.dropzone {
  position: absolute;
  inset: 0;
  display: none;
  place-items: center;
  text-align: center;
  padding: 24px;
}
.stage.is-empty .dropzone { display: grid; }

.stage.is-dragging .dropzone {
  display: grid;
  background: rgba(6, 6, 6, .92);
  outline: 1px dashed var(--accent);
  outline-offset: -12px;
}

.dropzone__inner { max-width: 400px; }

/* A little 4x4 Bayer-looking cluster, because of course it is. */
.dropzone__glyph {
  display: grid;
  grid-template-columns: repeat(4, 11px);
  gap: 3px;
  justify-content: center;
  margin: 0 auto 20px;
}
.dropzone__glyph span {
  width: 11px;
  height: 11px;
  background: var(--ink-4);
  animation: drpulse 2.8s infinite ease-in-out;
}
.dropzone__glyph span:nth-child(1)  { animation-delay: 0s;    }
.dropzone__glyph span:nth-child(2)  { animation-delay: .50s;  }
.dropzone__glyph span:nth-child(3)  { animation-delay: .13s;  }
.dropzone__glyph span:nth-child(4)  { animation-delay: .63s;  }
.dropzone__glyph span:nth-child(5)  { animation-delay: .75s;  }
.dropzone__glyph span:nth-child(6)  { animation-delay: .25s;  }
.dropzone__glyph span:nth-child(7)  { animation-delay: .88s;  }
.dropzone__glyph span:nth-child(8)  { animation-delay: .38s;  }
.dropzone__glyph span:nth-child(9)  { animation-delay: .19s;  }
.dropzone__glyph span:nth-child(10) { animation-delay: .69s;  }
.dropzone__glyph span:nth-child(11) { animation-delay: .06s;  }
.dropzone__glyph span:nth-child(12) { animation-delay: .56s;  }
.dropzone__glyph span:nth-child(13) { animation-delay: .94s;  }
.dropzone__glyph span:nth-child(14) { animation-delay: .44s;  }
.dropzone__glyph span:nth-child(15) { animation-delay: .81s;  }
.dropzone__glyph span:nth-child(16) { animation-delay: .31s;  }

@keyframes drpulse {
  0%, 100% { background: #1c1c1c; }
  50%      { background: var(--accent); }
}
@media (prefers-reduced-motion: reduce) {
  .dropzone__glyph span { animation: none; background: #1c1c1c; }
  .dropzone__glyph span:nth-child(3n) { background: var(--accent-dim); }
}

.dropzone__title {
  font-family: var(--display);
  font-size: 22px;
  margin: 0 0 10px;
  letter-spacing: .01em;
}
.dropzone__sub { margin: 0 0 22px; font-size: 12px; color: var(--ink-2); }
/* The escape hatch for anyone who arrived without a picture to hand. Quieter
   than a primary action, louder than the browse link above it. */
.samplebtn {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 16px;
  margin-bottom: 22px;
  border: 1px solid var(--line-hot);
  background: var(--accent-ghost);
  color: var(--accent);
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  transition: background var(--t), border-color var(--t), color var(--t);
}
.samplebtn:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #120c00;
}
.samplebtn:disabled {
  opacity: .4;
  cursor: not-allowed;
  background: none;
  border-color: var(--line-2);
  color: var(--ink-3);
}

.dropzone__note {
  margin: 0;
  font-size: 10px;
  letter-spacing: .07em;
  color: var(--ink-4);
  text-transform: uppercase;
}

/* ---------------------------------------------------------------- gallery
   The front door. Choosing by eye means never having to open the rail. */
.gallery {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: 26px;
  background: rgba(4, 4, 4, .82);
}
.gallery[hidden] { display: none; }

.gallery__panel {
  width: min(1180px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border: 1px solid var(--line-2);
  background: var(--panel);
  box-shadow: 0 40px 90px -24px #000;
}

.gallery__bar {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 13px 15px;
  border-bottom: 1px solid var(--line);
  flex: none;
}
.gallery__title {
  margin: 0;
  font-family: var(--display);
  font-size: 15px;
  font-weight: 400;
  letter-spacing: .01em;
}
.gallery__sub {
  margin: 0;
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.gallery__close { margin-left: auto; font-size: 15px; }

.gallery__grid {
  overflow-y: auto;
  padding: 6px 15px 18px;
  min-height: 0;
}
.gallery__grid::-webkit-scrollbar { width: 9px; }
.gallery__grid::-webkit-scrollbar-track { background: var(--panel); }
.gallery__grid::-webkit-scrollbar-thumb { background: var(--line-2); border: 3px solid var(--panel); }

.gallery__group {
  margin: 16px 0 8px;
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-4);
}

.gallery__row {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 9px;
}

.gcell {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 4px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  transition: border-color var(--t), background var(--t);
}
.gcell:hover { border-color: var(--ink-3); background: var(--panel-3); }
.gcell.is-current { border-color: var(--accent); background: var(--accent-ghost); }

.gcell__thumb {
  display: block;
  width: 100%;
  height: auto;
  background: #000;
  image-rendering: pixelated;
}

.gcell__name {
  font-size: 9.5px;
  letter-spacing: .06em;
  color: var(--ink-2);
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.gcell:hover .gcell__name { color: var(--ink); }
.gcell.is-current .gcell__name { color: var(--accent); }

/* ---- saved slots ---- */
.slotbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 4px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--line);
}
.slotbar__title { margin: 16px 0 0; }
.slotbar__tools { display: flex; align-items: center; gap: 6px; margin-left: auto; }

.slotbar__name {
  width: 190px;
  height: 22px;
  padding: 0 7px;
  background: var(--panel-2);
  border: 1px solid var(--line-2);
  color: var(--ink);
  font-size: 11px;
}
.slotbar__name::placeholder { color: var(--ink-4); }
.slotbar__name:focus { border-color: var(--accent); background: #000; outline: none; }

.slotbar__save { border-color: var(--line-hot); color: var(--accent); }
.slotbar__save:hover { background: var(--accent-ghost); }
.chip.is-bad { color: var(--danger); border-color: var(--danger); }
.chip:disabled { opacity: .35; pointer-events: none; }

.slotbar__empty {
  margin: 10px 0 2px;
  grid-column: 1 / -1;
  font-size: 10.5px;
  color: var(--ink-4);
  letter-spacing: .04em;
}

.gcell--slot { position: relative; }

/* Per-slot actions, revealed on hover so the grid stays quiet at rest. */
.gcell__tools {
  position: absolute;
  top: 5px;
  right: 5px;
  display: flex;
  gap: 2px;
  opacity: 0;
  transition: opacity var(--t);
}
.gcell--slot:hover .gcell__tools,
.gcell--slot:focus-within .gcell__tools { opacity: 1; }

.gcell__tool {
  width: 17px;
  height: 17px;
  display: grid;
  place-items: center;
  background: rgba(0, 0, 0, .82);
  border: 1px solid var(--line-2);
  color: var(--ink-2);
  font-size: 10px;
  line-height: 1;
  cursor: pointer;
}
.gcell__tool:hover { color: var(--accent); border-color: var(--accent); }
.gcell__tool--kill:hover { color: var(--danger); border-color: var(--danger); }

body.is-modal { overflow: hidden; }

/* ---------------------------------------------------------------- status */
.statusbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  border-top: 1px solid var(--line);
  background: var(--panel);
  font-size: 10px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
  overflow: hidden;
  white-space: nowrap;
}
.status { flex: none; }
.status b { color: var(--ink-2); font-weight: 400; }
/* Flags a preview running below export resolution, so the grain on screen is
   finer in the saved file than it looks here. */
.status.is-approx { color: var(--accent); }
.status--right { margin-left: auto; color: var(--ink-4); }

/* Licence and policy links. Quiet by default: they need to be present and
   findable, not competing with the readout beside them. */
.statusbar__links {
  display: flex;
  gap: 10px;
  flex: none;
  padding-left: 12px;
  border-left: 1px solid var(--line-2);
}
.statusbar__links a {
  color: var(--ink-4);
  text-decoration: none;
  font-size: 10px;
  letter-spacing: .07em;
  text-transform: uppercase;
}
.statusbar__links a:hover { color: var(--accent); }
.status__sep { width: 1px; height: 11px; background: var(--line-2); flex: none; }

/* ---------------------------------------------------------------- ads ----
   Slots are laid out and sized here even while hidden, so enabling them
   later reveals a space that already exists. Nothing shifts. */
.adslot, .adrail {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  background: var(--panel);
}
body.ads-on .adslot:not([hidden]),
body.ads-on .adrail:not([hidden]) { display: flex; }

.adslot--footer {
  border-top: 1px solid var(--line);
  padding: 8px 0;
  min-height: 106px;
}
.adslot--footer .adslot__mount { width: 728px; max-width: 100%; height: 90px; }

.adrail {
  border-left: 1px solid var(--line);
  padding: 10px 8px;
  justify-content: flex-start;
  overflow: hidden;
}
.adrail .adslot__mount { width: 160px; height: 600px; }

.adslot__label {
  font-size: 8.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-4);
}
.adslot__mount { background: #0c0c0c; border: 1px solid var(--line); }

/* ---------------------------------------------------------------- narrow */
@media (max-width: 1080px) {
  :root { --rail-w: 300px; }
  .brand__tag, .brand__rule { display: none; }
}

@media (max-width: 880px) {
  .app {
    /* Rows must be auto here: the top bar wraps onto a second line at this
       width, and a fixed-height row would clip the action buttons. */
    grid-template-rows: auto 1fr auto;
    height: auto;
    min-height: 100dvh;
    overflow: visible;
    /* Room for the pinned status bar below. */
    padding-bottom: var(--status-h);
  }
  .layout {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(340px, 60vh) auto auto;
  }
  .stage { order: 1; }
  .rail {
    order: 2;
    border-right: none;
    border-top: 1px solid var(--line);
    overflow: visible;
    max-height: none;
  }
  .adrail { order: 3; border-left: none; border-top: 1px solid var(--line); }
  body.ads-on { --adrail-w: 0px; }
  .adrail .adslot__mount { width: 300px; height: 250px; }

  .topbar { height: auto; min-height: var(--bar-h); padding: 8px 10px; flex-wrap: wrap; }
  .btn__key { display: none; }

  /* Pinned, not sticky. The page scrolls as one document at this width, and
     a sticky bar rides up over the control rail partway down. */
  .statusbar {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    height: var(--status-h);
    z-index: 50;
    background: var(--panel);
  }
}

@media (max-width: 520px) {
  .topbar__actions { width: 100%; }
  .topbar__actions .btn { flex: 1; justify-content: center; padding: 0 6px; }
  .stage__viewport { padding: 12px; }

  /* Drop the algorithm name first, since the Dither panel right below
     already names it. Each status is hidden together with the separator
     before it, so no orphan divider is left behind. */
  #status-algo,
  #status-palette + .status__sep { display: none; }
}

@media (max-width: 400px) {
  #status-palette,
  #status-dims + .status__sep { display: none; }
}
