/* ============================================================
   clunuc — iPOD
   The world around the device is clunuc; the inside of the screen
   is a genuine iPod (palette lives in main.js, §7 of BUILD).
   ============================================================ */

:root {
  --bg: #12060c;

  /* pink / salmon / orange / reddish — the site palette, used by
     the wall and the grid only; the screen keeps its own */
  --c-pink:    #ff6fa5;
  --c-salmon:  #ff8a6b;
  --c-orange:  #ff9d2e;
  --c-red:     #e8384f;

  --lcd-grid:  3px;   /* LCD 3x block size */
  --lcd-line:  rgba(0, 0, 0, 0.42);

  /* The body, at rest: 420 x 702 keeps the real 103.5 : 61.8 ratio
     of an iPod classic (rounded to whole 3px cells where it could).
     Everything inside is positioned in these same units, so the
     whole device can be scaled by one number on small viewports. */
  --ipod-w: 420px;
  --ipod-h: 702px;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--bg);
  color: #fff;
  font-family: "Press Start 2P", "Courier New", ui-monospace, monospace;
  overflow: hidden;
  -webkit-font-smoothing: none;
}

/* ------------------------------------------------------------
   Background wall of CLUNUC
   ------------------------------------------------------------ */

.wall {
  position: fixed;
  inset: 0;
  z-index: 0;

  background:
    radial-gradient(circle at 50% 42%, #3b1222 0%, #240c17 44%, var(--bg) 80%),
    var(--bg);
}

/* ------------------------------------------------------------
   Stage + fit + float

   .stage centres, .fit scales the device down when the viewport
   cannot hold it (one number, so the body keeps its proportions),
   .float bobs. The bob is its own element because its keyframes
   own `transform` — the tilt lives one level deeper.
   ------------------------------------------------------------ */

.stage {
  position: fixed;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.fit {
  --fit: 1;
  transform: scale(var(--fit));

  /* the rig's scale slider lands in jumps: geometry never glides */
  transition: transform 240ms steps(6);
}

@media (max-height: 740px) { .fit { --fit: 0.9; } }
@media (max-height: 660px) { .fit { --fit: 0.8; } }
@media (max-height: 580px) { .fit { --fit: 0.7; } }
@media (max-width: 440px)  { .fit { --fit: 0.82; } }
@media (max-width: 380px)  { .fit { --fit: 0.72; } }

/* Six seconds up and back, four jumps per direction: 12px of travel
   in 3px steps, so even the float lands on LCD cells. The stops are
   spelled out rather than left to steps(4, jump-none) — that parses
   fine but this engine resolves it to 4px jumps, which walk straight
   off the grid. steps(1) holds each stop and snaps to the next:
   same choreography, no ambiguity.

   Travel comes from --bob-px (the rig's Bob amount slider) and tempo
   from --bob-dur. The slider moves in 6px jumps so the two half-stops
   stay whole cells: 6px halves are 3px, 9px halves are 4.5 and that
   is how the float walks off the grid. */
@keyframes ipod-bob {
  0%   { transform: translateY(calc(var(--bob-px) * -1)); }
  25%  { transform: translateY(calc(var(--bob-px) * -0.5)); }
  50%  { transform: translateY(0); }
  75%  { transform: translateY(calc(var(--bob-px) * 0.5)); }
  100% { transform: translateY(var(--bob-px)); }
}

.float {
  perspective: 1400px;
  --bob-px: 6px;
  --bob-dur: 3s;
  animation: ipod-bob var(--bob-dur) steps(1) infinite alternate;
}

/* ------------------------------------------------------------
   The device
   ------------------------------------------------------------ */

.ipod {
  position: relative;
  width: var(--ipod-w);
  height: var(--ipod-h);

  /* the JS tilt is written here, in whole degrees */
  transform-style: preserve-3d;
  transform: rotateX(0deg) rotateY(0deg);

  box-shadow: 0 27px 45px rgba(0, 0, 0, 0.55);
  user-select: none;
  -webkit-user-select: none;
}

/* the back: polished chrome, barely visible. A touch LARGER than the
   face so its rim peeks past the silhouette when the body tilts —
   a hint of catching light, not a model of a back */
.ipod__back {
  position: absolute;
  inset: -3px;
  border-radius: 33px;
  transform: translateZ(-9px);
  background: linear-gradient(
    118deg,
    #f4f5f7 0%, #c9ccd1 22%, #9ba0a7 44%,
    #eceef1 62%, #aeb3ba 82%, #dfe2e6 100%
  );
  box-shadow: inset 0 0 0 3px rgba(255, 255, 255, 0.35);
}

/* ------------------------------------------------------------
   Faceplate — space grey anodised metal (was silver; the user's
   original device was space gray)

   Light vertical gradient (real metal catches light top to
   bottom), a stepped specular band down the left edge in hard 3px
   stops, and a darker lip along the bottom. No blur anywhere:
   the highlight is chunky on purpose, like everything else here.

   Three more layers of "this is metal", all on the 3px pitch so
   the texture sits in phase with the LCD grid instead of beating
   against it:
     · brushed grain — 1px light / 1px dark striations every 3px.
       Low contrast on purpose: turn it up and it stops being grain
       and starts being corduroy.
     · chamfer — 1px light on the top/left, 1px dark on the
       bottom/right, so the slab reads as milled rather than cut
       from paper.
     · a narrow bright core in the specular, with the same grain
       running through it, so the highlight looks like light
       crossing brushed metal instead of a painted stripe.
   ------------------------------------------------------------ */

.ipod__front {
  position: absolute;
  inset: 0;
  border-radius: 30px;
  overflow: hidden;
  transform: translateZ(9px);

  background:
    repeating-linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.045) 0 1px,
      rgba(0, 0, 0, 0.055)        1px 2px,
      rgba(255, 255, 255, 0)      2px 3px
    ),
    linear-gradient(
      180deg,
      #4c4c4e 0%, #464648 26%, #3e3e40 62%, #343436 100%
    );

  /* chamfer first: box-shadows paint top-down, and the bevel has to
     sit above the softer inner ring to read as an edge */
  box-shadow:
    inset 1px 1px 0 rgba(255, 255, 255, 0.34),
    inset -1px -1px 0 rgba(0, 0, 0, 0.62),
    inset 0 0 0 3px rgba(255, 255, 255, 0.10),
    inset 0 -3px 0 #262628;
}

/* specular highlight: a narrow bright core plus its shadow bands,
   all on 3px stops, with the brushed grain cut through the whole
   stack so the light travels along the metal */
.ipod__front::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 30px;
  pointer-events: none;
  background:
    repeating-linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.10) 0 1px,
      rgba(0, 0, 0, 0.09)        1px 2px,
      rgba(255, 255, 255, 0)     2px 3px
    ),
    linear-gradient(
      90deg,
      #57575a 0 3px,
      rgba(255, 255, 255, 0) 3px 6px,
      #909094 6px 9px,
      #6a6a6e 9px 12px,
      rgba(255, 255, 255, 0) 12px 21px,
      #555558 21px 24px,
      #262628 24px 30px
    );
}

/* the far edge gets a thinner anisotropic sliver — real metal
   catches a second, weaker light on the opposite rim */
.ipod__front::after {
  content: "";
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 12px;
  pointer-events: none;
  background:
    repeating-linear-gradient(
      180deg,
      rgba(255, 255, 255, 0.07) 0 1px,
      rgba(0, 0, 0, 0.07)        1px 2px,
      rgba(255, 255, 255, 0)     2px 3px
    ),
    linear-gradient(
      270deg,
      #626266 0 3px,
      rgba(255, 255, 255, 0) 3px 6px,
      #4a4a4d 6px 9px,
      rgba(255, 255, 255, 0) 9px 12px
    );
}

/* ------------------------------------------------------------
   Screen — glossy black bezel, LCD recessed into it
   ------------------------------------------------------------ */

.ipod__screen-frame {
  position: absolute;
  left: 33px;
  top: 78px;
  width: 354px;
  height: 268px;
  border-radius: 6px;
  background: #0a0a0c;
  box-shadow:
    inset 0 3px 6px rgba(0, 0, 0, 0.85),
    0 0 0 3px rgba(0, 0, 0, 0.3);

  /* the backlight glow is atmosphere, not geometry, so it is allowed
     to be smooth — Bright gets it, Dim does not */
  transition: box-shadow 120ms steps(2);
}

.ipod__screen-frame.is-bright {
  box-shadow:
    inset 0 3px 6px rgba(0, 0, 0, 0.85),
    0 0 0 3px rgba(0, 0, 0, 0.3),
    0 0 18px rgba(150, 180, 255, 0.35);
}

.ipod__screen {
  position: absolute;
  left: 5px;
  top: 5px;
  display: block;
  width: 344px;
  height: 258px;

  /* the screen's own low-res buffer is blown up here. It is a NESTED
     scale: deliberately independent of — and chunkier than — the
     page's 3px grid drawn on top of it */
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

/* ------------------------------------------------------------
   Click wheel
   ------------------------------------------------------------ */

.ipod__wheel {
  position: absolute;
  left: 81px;
  top: 405px;
  width: 258px;
  height: 258px;
  border-radius: 50%;

  /* matte grey, clearly separate from the darker body around it,
     with a dark ring cutting it out of the faceplate */
  background: radial-gradient(circle at 50% 32%, #5b5b5d 0%, #555557 62%, #4e4e50 100%);
  box-shadow:
    0 0 0 3px #2e2e30,
    inset 0 3px 0 rgba(255, 255, 255, 0.12),
    inset 0 -3px 0 rgba(0, 0, 0, 0.35);

  touch-action: none;   /* a rotational drag must not scroll the page */
  cursor: pointer;
}

/* the labels are one canvas at 1/3 scale, so the glyphs land on the
   same 3px cells as everything else on the page */
.wheel__labels {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.wheel__labels canvas {
  display: block;
  width: 258px;
  height: 258px;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

/* the centre button is drawn by CSS but does not take the pointer:
   the wheel element decides "centre" by radius, so there is exactly
   one hit target and the two can never disagree */
.wheel__center {
  position: absolute;
  left: 84px;
  top: 84px;
  width: 90px;
  height: 90px;
  border-radius: 50%;
  pointer-events: none;

  background: linear-gradient(180deg, #66666a 0%, #606062 100%);
  box-shadow:
    inset 0 -3px 0 rgba(0, 0, 0, 0.30),
    0 3px 0 rgba(0, 0, 0, 0.30);

  transition: transform 60ms steps(2), box-shadow 60ms steps(2);
}

.wheel__center.is-down {
  transform: translateY(3px);
  box-shadow: inset 0 3px 0 rgba(0, 0, 0, 0.45);
}

/* ------------------------------------------------------------
   LCD 3x grid overlay
   ------------------------------------------------------------ */

.lcd {
  position: fixed;
  inset: 0;
  z-index: 10;
  pointer-events: none;

  /* vertical + horizontal gridlines every 3px */
  background-image:
    repeating-linear-gradient(to right,  var(--lcd-line) 0 1px, transparent 1px var(--lcd-grid)),
    repeating-linear-gradient(to bottom, var(--lcd-line) 0 1px, transparent 1px var(--lcd-grid));

  /* subtle scanline darkening + corner vignette */
  box-shadow: inset 0 0 180px rgba(0, 0, 0, 0.75);
}

.lcd::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.14) 0 1px,
    transparent 1px calc(var(--lcd-grid) * 3)
  );
}

/* ------------------------------------------------------------
   Tilt rig — the controls live out here, on the wall, never in
   the device: the LCD is a replica of an iPod OS and that OS has
   no forms in it. Same palette, same pixel type, so the panel
   reads as part of the page rather than as furniture from
   another site. Sits under .lcd like everything else.
   ------------------------------------------------------------ */

.panel {
  position: fixed;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 5;

  width: 174px;
  padding: 12px 12px 9px;
  background: rgba(18, 6, 12, 0.92);
  border: 1px solid var(--c-pink);
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.6);

  font-size: 8px;
  line-height: 1.7;
}

.panel__title {
  margin: 0 0 9px;
  color: var(--c-pink);
  font-size: 8px;
  font-weight: normal;
  letter-spacing: 1px;
}

.panel__row {
  display: flex;
  justify-content: space-between;
  margin-top: 6px;
}

.panel__row label { color: var(--c-salmon); }
.panel__row output { color: var(--c-orange); }

.panel input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: 15px;
  margin: 0;
  background: transparent;
  cursor: pointer;
}

/* square thumb on a 3px track — a rounded pill would be the only
   smooth geometry on the page */
.panel input[type="range"]::-webkit-slider-runnable-track {
  height: 3px;
  background: #4d1a30;
}

.panel input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 9px;
  height: 15px;
  margin-top: -6px;
  border: 1px solid var(--bg);
  border-radius: 0;
  background: var(--c-pink);
}

.panel input[type="range"]::-moz-range-track {
  height: 3px;
  background: #4d1a30;
}

.panel input[type="range"]::-moz-range-thumb {
  width: 9px;
  height: 15px;
  border: 1px solid var(--bg);
  border-radius: 0;
  background: var(--c-pink);
}

.panel__btns {
  display: flex;
  gap: 6px;
  margin-top: 9px;
}

.panel button {
  flex: 1;
  padding: 6px 3px;
  border: 1px solid var(--c-salmon);
  background: #240c17;
  color: #fff;
  font-family: inherit;
  font-size: 8px;
  cursor: pointer;

  transition: background 60ms steps(2), color 60ms steps(2);
}

.panel button:hover,
.panel button:focus-visible {
  background: var(--c-pink);
  color: var(--bg);
}

/* the easter egg's resting state: the rig is off screen at boot
   until three clicks in the bottom-right corner bring it back */
.panel[hidden] { display: none; }

/* the rig would sit on top of the device on a phone-width viewport,
   and the site gave up on phones long before this panel existed */
@media (max-width: 700px) {
  .panel { display: none; }
}

/* ------------------------------------------------------------
   SUBMIT MY MUSIC — the form panel

   The rig's opposite number: the rig is pinned to the left edge,
   this sits to the right, so the device stays clear between them.
   It borrows the root site's SETTINGS console idiom — stepped rings,
   the stepped press, orange focus, a local LCD — but in its own
   .submit__ classes, because ipod.html must not depend on root
   style.css. Same family, different control.

   It sits at z-index 20, ABOVE the global .lcd (10), so it paints
   its own grid, and it paints it as BACKGROUND layers rather than a
   ::before overlay: the panel scrolls, and a pseudo overlay would
   drag along with the content while the global grid stays put.
   Backgrounds stay glued to the padding box instead.

   There is no border anywhere on the panel, so JS can snap it onto
   the global grid (a multiple of 3 from the viewport corner): its
   lines then coincide with the global ones and the grid runs on,
   uninterrupted, from the page into the panel. Every padding,
   margin and line-height below is a multiple of 3 so that nothing
   inside the panel drifts off that grid either.
   ------------------------------------------------------------ */

.submit {
  position: fixed;
  right: 12px;
  top: 50%;
  /* The centre here is a transform; JS nudges it back onto the grid
     with the standalone `translate` property, which composes with
     this instead of overwriting it. */
  transform: translateY(-50%);
  z-index: 20;

  width: 249px;
}

/* The SETTINGS toggle's recipe: 6px rings, a drop shadow that
   collapses when the button sinks into its own bevel, grid-only
   background (no scanline pass — too busy at this size). */
.submit__toggle {
  display: block;
  width: 100%;
  padding: 9px 12px;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  text-align: left;

  background-color: #2b2b33;
  background-image:
    repeating-linear-gradient(to right,  var(--lcd-line) 0 1px, transparent 1px var(--lcd-grid)),
    repeating-linear-gradient(to bottom, var(--lcd-line) 0 1px, transparent 1px var(--lcd-grid));

  color: #fff;
  font-family: inherit;
  font-size: 9px;
  line-height: 12px;
  letter-spacing: 3px;
  text-transform: uppercase;

  box-shadow:
    0 0 0 3px #0d0d10,
    0 0 0 6px #6d6d7a,
    6px 6px 0 6px rgba(0, 0, 0, 0.55);

  image-rendering: pixelated;
  transition: transform 60ms steps(2), box-shadow 60ms steps(2);
}

/* background-COLOR, never the shorthand: the shorthand would wipe
   the local LCD grid painted above */
.submit__toggle:hover { background-color: #37373f; }

.submit__toggle:active,
.submit__toggle[aria-expanded="true"] {
  transform: translate(6px, 6px);
  box-shadow:
    0 0 0 3px #0d0d10,
    0 0 0 6px #6d6d7a,
    0 0 0 6px rgba(0, 0, 0, 0.55);
}

.submit__toggle:focus-visible {
  outline: 3px solid var(--c-orange);
  outline-offset: 9px;
}

/* keeps the label crisp when the button under it is translated —
   same reason as the root site's .settings__toggle-label */
.submit__toggle-label {
  display: block;
  transform: translateZ(0);
}

/* The panel proper: the local LCD with the scanline pass every 3rd
   cell, the full stepped border, no border property anywhere. The
   24px gap under the toggle is for the toggle's bevel — pressed, it
   travels 6px and its rings reach 6px further, and they must not
   land on the panel's own rings. */
.submit__panel {
  margin-top: 24px;
  padding: 15px 12px 12px;
  max-height: calc(100vh - 96px);
  overflow-y: auto;

  background-color: #1b1b21;
  background-image:
    repeating-linear-gradient(to right,  var(--lcd-line) 0 1px, transparent 1px var(--lcd-grid)),
    repeating-linear-gradient(to bottom, var(--lcd-line) 0 1px, transparent 1px var(--lcd-grid)),
    repeating-linear-gradient(
      to bottom,
      rgba(0, 0, 0, 0.14) 0 1px,
      transparent 1px calc(var(--lcd-grid) * 3)
    );

  box-shadow:
    0 0 0 3px #0d0d10,
    0 0 0 6px #6d6d7a,
    6px 6px 0 6px rgba(0, 0, 0, 0.55);
}

/* `hidden` has to win over the block layout above */
.submit__panel[hidden] { display: none; }

.submit__head {
  margin: 0 0 12px;
  font-size: 9px;
  line-height: 12px;
  letter-spacing: 0;
  text-transform: uppercase;
  color: var(--c-orange);
}

.submit__row { margin-bottom: 12px; }

/* label above value — the .settings__row-top pattern, minus the
   readout: the file input already prints its own filename */
.submit__label {
  display: block;
  margin: 0 0 6px;
  font-size: 6px;
  line-height: 12px;
  letter-spacing: 0;
  color: #a9a9b6;
}

/* A real <input type="file">, not an opacity-0 ghost over a fake
   button: the ghost would take the focus ring and the screen reader
   with it. The face is the text-input face; the button inside it is
   dressed with the reset recipe via ::file-selector-button. */
.submit__file {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  padding: 9px;
  border: 0;
  border-radius: 0;

  background: #2b2b33;
  /* the filename readout, in readout pink */
  color: var(--c-pink);
  font-family: inherit;
  font-size: 6px;
  line-height: 12px;
  letter-spacing: 0;

  box-shadow: 0 0 0 3px #0d0d10;
}

.submit__file:focus-visible {
  outline: 3px solid var(--c-orange);
  outline-offset: 9px;
}

/* Both spellings: the unprefixed one is the standard (Chrome,
   Firefox), the webkit one is what Safari still wants. Shared so
   the button recipe exists exactly once. */
.submit__file::file-selector-button,
.submit__file::-webkit-file-selector-button {
  border: 0;
  border-radius: 0;
  margin: 0 9px 0 0;
  padding: 6px 9px;

  background-color: #2b2b33;
  background-image:
    repeating-linear-gradient(to right,  var(--lcd-line) 0 1px, transparent 1px var(--lcd-grid)),
    repeating-linear-gradient(to bottom, var(--lcd-line) 0 1px, transparent 1px var(--lcd-grid));

  color: #fff;
  font-family: inherit;
  font-size: 6px;
  line-height: 12px;
  letter-spacing: 3px;
  text-transform: uppercase;

  /* the reset recipe: two rings, a 3px press, no drop shadow */
  box-shadow: 0 0 0 3px #0d0d10, 0 0 0 6px #6d6d7a;
  cursor: pointer;
  transition: transform 60ms steps(2), box-shadow 60ms steps(2);
}

.submit__file::file-selector-button:hover,
.submit__file::-webkit-file-selector-button:hover {
  background-color: #37373f;
}

.submit__file::file-selector-button:active,
.submit__file::-webkit-file-selector-button:active {
  transform: translate(3px, 3px);
}

/* the only raster in the panel: the chosen cover, blown up in hard
   pixels so it beats against the grid like everything else */
.submit__thumb {
  display: block;
  width: 72px;
  height: 72px;
  margin-top: 6px;
  object-fit: cover;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  box-shadow: 0 0 0 3px #0d0d10, 0 0 0 6px #6d6d7a;
}

.submit__thumb[hidden] { display: none; }

/* a clunuc text input: face, one dark ring, no border, no radius,
   value in readout pink, focus past the bevel */
.submit__text {
  display: block;
  width: 100%;
  padding: 9px 6px;
  border: 0;
  border-radius: 0;

  background: #2b2b33;
  color: var(--c-pink);
  caret-color: var(--c-orange);
  font-family: inherit;
  font-size: 6px;
  line-height: 12px;
  letter-spacing: 0;

  box-shadow: 0 0 0 3px #0d0d10;
}

.submit__text:focus-visible {
  outline: 3px solid var(--c-orange);
  outline-offset: 9px;
}

/* One red line under the offender, and nothing else on the page
   moves. No toast, no icon, no exclamation mark. */
.submit__err {
  margin: 6px 0 0;
  font-size: 6px;
  line-height: 12px;
  letter-spacing: 0;
  color: var(--c-red);
}

.submit__err[hidden] { display: none; }

/* the honest outcome of a submit that passed every check */
.submit__status {
  margin: 6px 0 0;
  font-size: 6px;
  line-height: 12px;
  letter-spacing: 0;
  color: var(--c-pink);
}

.submit__status[hidden] { display: none; }

/* the reset recipe, full width: two rings, presses 3px into them */
.submit__go {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 9px;
  border: 0;
  border-radius: 0;
  cursor: pointer;

  background-color: #2b2b33;
  background-image:
    repeating-linear-gradient(to right,  var(--lcd-line) 0 1px, transparent 1px var(--lcd-grid)),
    repeating-linear-gradient(to bottom, var(--lcd-line) 0 1px, transparent 1px var(--lcd-grid));

  color: #fff;
  font-family: inherit;
  font-size: 9px;
  line-height: 12px;
  letter-spacing: 3px;
  text-transform: uppercase;

  box-shadow: 0 0 0 3px #0d0d10, 0 0 0 6px #6d6d7a;
  transition: transform 60ms steps(2), box-shadow 60ms steps(2);
}

.submit__go:hover { background-color: #37373f; }

.submit__go:active { transform: translate(3px, 3px); }

.submit__go:focus-visible {
  outline: 3px solid var(--c-orange);
  outline-offset: 9px;
}

/* Two breakpoints, on purpose. The rig gives up at 700 — keep this
   panel on the same one so a phone never sees either. And this panel
   is wider than the rig and sits further from the centre, so at 960
   its own ring would still be reaching the device's chrome; the rig
   is 174px and clears the device on its own, this one is 249px and
   does not. Hiding early beats covering the device. */
@media (max-width: 700px) {
  .submit { display: none; }
}

@media (max-width: 960px) {
  .submit { display: none; }
}

/* ------------------------------------------------------------
   Screen reader text — carries what the canvas shows, never
   instructions, so it is also what a sighted user does NOT see
   ------------------------------------------------------------ */

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
