/* Image Reshaper
   The page is a neutral gray reference card -- the surface photographers use
   precisely because it doesn't bias how you read a color. Every saturated
   color you see belongs to the user's images, not to the interface. */

:root {
  --card:   #7c7c7c;  /* 18% gray reference -- the bench */
  --paper:  #e9e8e4;  /* panel stock */
  --paper-deep: #dcdad4;
  --mat:    #22242a;  /* the lightbox the result sits in */
  --ink:    #16171a;
  --ink-soft: #5c5e63;
  --rule:   #2f3034;
  --mark:   #1b44de;  /* registration blue -- interaction only */
  --mark-lit: #8ea6ff; /* the same blue, legible on the dark stage */
  --alert:  #a8301a;
  --amber:  #8a6a12;

  --sans: "Helvetica Neue", Arial, sans-serif;
  --display: "Arial Black", "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", Consolas, "SF Mono", monospace;

  --gap: 18px;
  --pad: clamp(14px, 4vw, 44px);
  --panel-pad: 14px;
}

* { box-sizing: border-box; }

/* Author styles beat the UA rule for [hidden], so restate it. */
[hidden] { display: none !important; }

body {
  margin: 0;
  padding: clamp(18px, 3.5vw, 28px) var(--pad) 44px;
  background: var(--card);
  color: var(--ink);
  font: 15px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;  /* the masthead strip bleeds past the padding */
}

h1, h2, h3 { margin: 0; }

/* ---------- masthead ---------- */

.masthead__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  padding-bottom: clamp(12px, 2vw, 18px);
}

.masthead h1 {
  font-family: var(--display);
  font-size: clamp(30px, 7.5vw, 64px);
  line-height: 0.9;
  letter-spacing: -0.04em;
}

.masthead__thesis {
  max-width: 46ch;
  margin: 10px 0 0;
  font-size: clamp(14px, 1.4vw, 15px);
  color: #232427;
}

.stamp {
  flex: none;
  margin: 4px 0 0;
  padding: 7px 11px;
  border: 1.5px solid var(--rule);
  font: 600 10px/1.35 var(--mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-align: right;
  color: var(--rule);
}

/* The rule under the masthead is not a rule: it is the source image's own
   pixels, sorted by lightness. The page's structural line is made of the
   material the page is about, and it changes when you pick a new source. */
.masthead__strip {
  display: block;
  width: 100vw;
  margin-inline: calc(50% - 50vw);
  height: clamp(10px, 1.6vw, 16px);
  margin-bottom: var(--gap);
  background: var(--rule);
  image-rendering: pixelated;
  transform-origin: left center;
  animation: strip-in 700ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes strip-in { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* ---------- bench layout ---------- */

.bench {
  display: grid;
  grid-template-columns: minmax(230px, 1fr) minmax(0, 2.3fr);
  gap: var(--gap);
  align-items: start;
}

/* Grid items floor at min-content by default, so the JS-sized stage could prop
   its own column open and never shrink back. Let them go narrower. */
.bench > * { min-width: 0; }

/* Both pickers are intake: they sit together, opposite the result. */
.intake {
  display: grid;
  gap: var(--gap);
}

.station, .stage {
  background: var(--paper);
  border: 1.5px solid var(--rule);
  padding: var(--panel-pad);
}

/* ---------- the stage is a dark viewing station ----------
   The two intake panels are worksheets you fill in; this one is where you look
   at something. Making it a lit box instead of a third identical card gives the
   page the one clear focal point it was missing, and pixels in flight glow
   against it rather than dissolving into paper. */

.stage {
  background: var(--mat);
  border-color: #14151a;
  color: var(--paper);
}

.stage .station__head { border-bottom-color: rgba(233, 232, 228, 0.22); }
.stage .station__head h2 { color: var(--paper); }
.stage .station__role,
.stage .readout,
.stage .controls__role { color: #a9adb6; }
.stage .readout b { color: var(--paper); }
.stage .deck__label { color: #8c9099; }

.stage .controls,
.stage .deck { border-top-color: rgba(233, 232, 228, 0.22); }

.stage .option { color: #c5c8ce; }
.stage .option em { color: #8c9099; }
.stage .option input,
.stage .quality input[type="range"] { accent-color: var(--mark-lit); }

.stage .spectrum canvas { border-color: rgba(233, 232, 228, 0.3); background: #16171b; }
.stage .spectrum__track { background: rgba(233, 232, 228, 0.18); }
.stage .spectrum__fill { background: var(--mark-lit); }

/* Buttons invert: the primary action becomes the bright object on the dark
   panel, the rest are outlines. */
.stage .button { color: var(--paper); border-color: rgba(233, 232, 228, 0.45); }
.stage .button:hover:not(:disabled) { background: var(--paper); color: var(--ink); }
.stage .button--go {
  background: var(--paper);
  color: var(--ink);
  border-color: var(--paper);
}
.stage .button--go:hover:not(:disabled) {
  background: var(--mark-lit);
  border-color: var(--mark-lit);
  color: var(--ink);
}
.stage .button--get { color: var(--mark-lit); border-color: var(--mark-lit); }
.stage .button--get:hover:not(:disabled) { background: var(--mark-lit); color: var(--ink); }
.stage .button:focus-visible { outline-color: var(--mark-lit); }
.stage .option input:focus-visible,
.stage .quality input:focus-visible { outline-color: var(--mark-lit); }

.station__head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  padding-bottom: 10px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--rule);
}

.station__head--split { justify-content: space-between; }

.station__head h2 {
  font: 600 11px/1 var(--mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.station__role {
  margin: 0;
  font: 12px/1 var(--mono);
  color: var(--ink-soft);
}

/* ---------- intake thumbnails ---------- */

.thumb {
  aspect-ratio: 4 / 3;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--paper-deep);
  border: 1px solid #b8b6b0;
}

.thumb img {
  max-width: 100%;
  max-height: 100%;
  display: block;
}

.picker { display: block; margin-top: 12px; }
.picker input { position: absolute; width: 1px; height: 1px; opacity: 0; }

.picker__button {
  display: block;
  padding: 11px 12px;
  border: 1.5px solid var(--rule);
  background: transparent;
  font: 600 11px/1 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  cursor: pointer;
}

.picker__button:hover { background: var(--rule); color: var(--paper); }
.picker input:focus-visible + .picker__button { outline: 3px solid var(--mark); outline-offset: 2px; }

.readout {
  margin: 10px 0 0;
  font: 11px/1.45 var(--mono);
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

.readout b { color: var(--ink); font-weight: 600; }
.readout__note { color: var(--mark); }

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

/* The stage is sized in JS: the well takes the width the result's aspect ratio
   earns at the available height, so the frame is exactly the shape of the
   image with no letterbox, and the spectrum below lines up with it. */
.stage__slot { display: flow-root; }

.stage__well { margin-inline: auto; max-width: 100%; }

/* A dark mat, not paper: the result reads as a lit object rather than another
   panel, and pixels in flight glow against it instead of dissolving into the
   page. GIF_BACKGROUND in reshaper.py is this same color so exports match. */
.stage__frame {
  position: relative;
  display: grid;
  place-items: center;
  background: #16171b;
  border: 1px solid rgba(233, 232, 228, 0.16);
}

.stage__frame canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.stage__empty {
  position: absolute;
  margin: 0;
  font: 11px/1 var(--mono);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #75787f;
}

/* ---------- the inventory strip: the conserved quantity ---------- */

.spectrum { margin: 14px 0 0; }

.spectrum canvas {
  display: block;
  width: 100%;
  height: 26px;
  border: 1px solid var(--rule);
  image-rendering: pixelated;
  background: var(--paper-deep);
}

.spectrum__track {
  height: 3px;
  margin-top: 3px;
  background: #c9c7c1;
}

.spectrum__fill {
  height: 100%;
  width: 0;
  background: var(--mark);
}

.spectrum figcaption { max-width: 62ch; }

/* ---------- setup: what the next run will do ---------- */

.controls {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--rule);
}

.controls__head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}

.controls__role {
  margin: 0 0 7px;
  font: 12px/1 var(--mono);
  color: var(--ink-soft);
}

.controls__options {
  display: flex;
  flex-wrap: wrap;
  gap: 9px 26px;
  margin-top: 12px;
}

.controls__options .option + .option { margin-top: 0; }

.quality {
  display: flex;
  align-items: center;
  gap: 14px;
}

.quality__label {
  flex: none;
  font: 600 11px/1 var(--mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.quality input[type="range"] {
  flex: 1 1 160px;
  min-width: 0;
  accent-color: var(--mark);
  margin: 0;
}

.quality input:focus-visible { outline: 3px solid var(--mark); outline-offset: 4px; }

.quality .readout { flex: none; margin: 0; }

/* ---------- deck: what you can do, grouped by when you do it ---------- */

.deck {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 30px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--rule);
}

.deck__label {
  margin: 0 0 7px;
  font: 600 10px/1 var(--mono);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.deck__row { display: flex; flex-wrap: wrap; gap: 8px; }

.option {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font: 12px/1.35 var(--mono);
  cursor: pointer;
}

.option input { accent-color: var(--mark); margin: 0; flex: none; }
.option em { color: var(--ink-soft); font-style: normal; }
.option input:focus-visible { outline: 3px solid var(--mark); outline-offset: 2px; }
.option + .option { margin-top: 9px; }

.button {
  display: inline-block;
  padding: 12px 20px;
  border: 1.5px solid var(--rule);
  font: 600 12px/1 var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  background: transparent;
  cursor: pointer;
}

.button:focus-visible { outline: 3px solid var(--mark); outline-offset: 2px; }
.button:hover:not(:disabled) { background: var(--rule); color: var(--paper); }
.button:disabled { opacity: 0.4; cursor: not-allowed; }

.button--go { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.button--go:hover:not(:disabled) { background: var(--mark); border-color: var(--mark); }
.button--go:disabled { cursor: progress; }

.button--get { border-color: var(--mark); color: var(--mark); }
.button--get:hover:not(:disabled) { background: var(--mark); color: var(--paper); }
.button--get:disabled { cursor: progress; }

/* ---------- messages ---------- */

.notice {
  margin: var(--gap) 0 0;
  padding: 11px 14px;
  border: 1.5px solid;
  background: var(--paper);
  font: 12px/1.5 var(--mono);
}

.notice--info { border-color: var(--rule); color: var(--ink-soft); }
.notice--warn { border-color: var(--amber); color: var(--amber); }
.notice--error { border-color: var(--alert); color: var(--alert); }

.colophon {
  margin-top: 22px;
  padding-top: 12px;
  border-top: 1px solid var(--rule);
}

.colophon .readout { color: #46474b; max-width: 70ch; }

/* ---------- tablets: one column, result first, pickers side by side ------- */

@media (max-width: 1039px) {
  .bench { grid-template-columns: 1fr; }
  .stage { grid-row: 1; }
  .intake { grid-template-columns: 1fr 1fr; }
}

/* ---------- phones ---------- */

@media (max-width: 640px) {
  :root { --gap: 12px; --panel-pad: 12px; }

  .masthead__top { flex-direction: column; gap: 12px; }
  .stamp { align-self: flex-start; text-align: left; }
  .masthead__thesis { max-width: none; }

  /* Two thumbnails still fit and beat scrolling past two tall cards. */
  .intake { grid-template-columns: 1fr 1fr; gap: var(--gap); }
  .station__head { flex-direction: column; align-items: flex-start; gap: 2px; }

  .quality { flex-wrap: wrap; }
  .quality input[type="range"] { flex: 1 1 100%; order: 3; }
  .quality .readout { margin-left: auto; }

  .controls__options { gap: 12px 18px; }
  .option { flex: 1 1 100%; }

  .deck { flex-direction: column; gap: 12px; }
  .deck__row { display: grid; grid-template-columns: 1fr 1fr; }
  /* Comfortable targets by width as well as by pointer type: a viewport this
     narrow is a phone whether or not the browser reports a coarse pointer. */
  .deck__row .button,
  .picker__button { text-align: center; min-height: 46px; padding: 13px 16px; }
  /* The third download sits on its own line rather than squeezing to a third. */
  .deck__row .button:nth-child(3) { grid-column: 1 / -1; }
}

@media (max-width: 400px) {
  .intake { grid-template-columns: 1fr; }
}

/* ---------- touch ---------- */

/* Coarse pointers need real targets, and a slider you can actually grab. */
@media (pointer: coarse) {
  .button, .picker__button { padding: 14px 18px; min-height: 46px; }
  .option { padding: 3px 0; }
  .option input[type="checkbox"] { width: 20px; height: 20px; }
  .quality input[type="range"] { height: 30px; }
}

@media (prefers-reduced-motion: reduce) {
  .masthead__strip { animation: none; }
}

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