/* ============================================================================
   Safelight — design system + app styles
   ============================================================================

   IDENTITY: "lightbox & darkroom".

   A safelight is the amber lamp a darkroom works under: light that lets you see
   without exposing the film. That is this product — you can look at your photos,
   nothing leaks. So the two colour schemes are not a theme chore, they are the two
   rooms photographers actually work in:

     light scheme  -> THE LIGHTBOX. Cool backlit paper, the way a slide table reads.
     dark scheme   -> THE DARKROOM. Warm near-black under an amber safelight.

   The accent is photographic orange in both, because that is the safelight itself.
   There is no blue-violet anywhere and no gradient: this is lab equipment, not a SaaS.

   VOICES: a humanist system sans carries prose. A mono carries every piece of data
   the user could check — filenames, byte counts, the wire tap. That split is the
   subject's own vernacular (IMG_1234.HEIC is already mono) and it is load-bearing:
   if it is in mono, you are meant to verify it.

   No webfonts on purpose. The product claims it makes no network calls after load;
   a font CDN would make that a lie, and self-hosting would cost first paint.

   REUSE: landing pages should import this file and use the tokens + .prose /
   .section / .card / .eyebrow primitives below. Everything app-specific starts at
   the "APP" banner.
   ============================================================================ */

/* ── Tokens ──────────────────────────────────────────────────────────────── */

:root {
  /* Type */
  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial,
    'Noto Sans', sans-serif;
  --font-mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas,
    'Liberation Mono', monospace;

  --step--1: clamp(0.78rem, 0.76rem + 0.1vw, 0.83rem);
  --step-0: clamp(0.95rem, 0.92rem + 0.15vw, 1.02rem);
  --step-1: clamp(1.1rem, 1.04rem + 0.3vw, 1.3rem);
  --step-2: clamp(1.35rem, 1.22rem + 0.6vw, 1.75rem);
  --step-3: clamp(1.75rem, 1.45rem + 1.4vw, 2.6rem);
  --step-4: clamp(2.3rem, 1.6rem + 3.2vw, 4.4rem);

  /* Space — 4px base */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 4.5rem;
  --s-9: 6.5rem;

  /* Geometry — lab equipment: crisp, barely rounded */
  --r-1: 2px;
  --r-2: 4px;
  --r-3: 8px;
  --measure: 68ch;
  --page: 1160px;
  --row-h: 60px;

  /* Reserved ad heights — set here so a filled slot shifts nothing (CLS) */
  --ad-h-below: 280px;
  --ad-h-content: 280px;

  --focus-w: 2px;

  /* LIGHTBOX (default / light scheme) */
  --paper: #eceef1;
  --surface: #ffffff;
  --surface-2: #f5f6f8;
  --sunken: #e3e6ea;
  --ink: #14161a;
  --ink-2: #414751;
  --muted: #5c636e;
  --rule: #d5d9df;
  --rule-2: #c2c8d0;
  --safelight: #b8430f;
  --safelight-ink: #ffffff;
  --safelight-wash: #fbf0ea;
  --verify: #1c6a56;
  --verify-wash: #e8f2ef;
  --warn: #7d5300;
  --warn-wash: #fbf2e0;
  --fail: #a3271a;
  --fail-wash: #fbebe8;
  --shadow: 0 1px 2px rgba(20, 22, 26, 0.06), 0 8px 24px -12px rgba(20, 22, 26, 0.18);
  --glow: none;
  color-scheme: light;
}

/* DARKROOM */
@media (prefers-color-scheme: dark) {
  :root:not([data-room='lightbox']) {
    --paper: #131010;
    --surface: #1c1817;
    --surface-2: #241f1d;
    --sunken: #0f0c0c;
    --ink: #f2ebe5;
    --ink-2: #cabfb6;
    --muted: #9b8e85;
    --rule: #322b28;
    --rule-2: #453b36;
    --safelight: #f2913f;
    --safelight-ink: #1a1210;
    --safelight-wash: #2a1d13;
    --verify: #58bfa3;
    --verify-wash: #14241f;
    --warn: #d9a441;
    --warn-wash: #251c0f;
    --fail: #f0806b;
    --fail-wash: #2a1614;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 12px 32px -14px rgba(0, 0, 0, 0.9);
    /* The safelight lamp itself: the one place light bleeds. */
    --glow: 0 0 0 1px rgba(242, 145, 63, 0.14), 0 0 42px -8px rgba(242, 145, 63, 0.28);
    color-scheme: dark;
  }
}

:root[data-room='darkroom'] {
  --paper: #131010;
  --surface: #1c1817;
  --surface-2: #241f1d;
  --sunken: #0f0c0c;
  --ink: #f2ebe5;
  --ink-2: #cabfb6;
  --muted: #9b8e85;
  --rule: #322b28;
  --rule-2: #453b36;
  --safelight: #f2913f;
  --safelight-ink: #1a1210;
  --safelight-wash: #2a1d13;
  --verify: #58bfa3;
  --verify-wash: #14241f;
  --warn: #d9a441;
  --warn-wash: #251c0f;
  --fail: #f0806b;
  --fail-wash: #2a1614;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 12px 32px -14px rgba(0, 0, 0, 0.9);
  --glow: 0 0 0 1px rgba(242, 145, 63, 0.14), 0 0 42px -8px rgba(242, 145, 63, 0.28);
  color-scheme: dark;
}

/* ── Reset ───────────────────────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
}

/* The UA's [hidden] rule is a bare attribute selector, so ANY class that sets `display`
   silently beats it — .btn{display:inline-flex} was enough to make hidden buttons
   visible. Every `hidden` toggle in js/main.js depends on this line. Don't remove it. */
[hidden] {
  display: none !important;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4,
p,
figure,
ul,
ol,
dl,
dd {
  margin: 0;
}

ul,
ol {
  padding: 0;
  list-style: none;
}

img,
svg {
  display: block;
  max-width: 100%;
}

button,
input,
select {
  font: inherit;
  color: inherit;
}

/* One focus treatment everywhere. Never removed, only styled. */
:focus-visible {
  outline: var(--focus-w) solid var(--safelight);
  outline-offset: 2px;
  border-radius: var(--r-1);
}

::selection {
  background: var(--safelight);
  color: var(--safelight-ink);
}

.skip {
  position: absolute;
  left: var(--s-3);
  top: -4rem;
  z-index: 50;
  padding: var(--s-2) var(--s-4);
  background: var(--safelight);
  color: var(--safelight-ink);
  border-radius: var(--r-2);
  text-decoration: none;
  transition: top 0.15s;
}

.skip:focus {
  top: var(--s-3);
}

.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ── Primitives ──────────────────────────────────────────────────────────── */

.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--s-4);
}

@media (min-width: 40em) {
  .wrap {
    padding-inline: var(--s-5);
  }
}

/* Mono is the "you can check this" voice. */
.mono {
  font-family: var(--font-mono);
  font-size: 0.92em;
  font-variant-numeric: tabular-nums;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 var(--s-3);
}

.card {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--r-3);
}

.section {
  padding-block: var(--s-8);
  border-top: 1px solid var(--rule);
}

.prose {
  max-width: var(--measure);
}

.prose p + p {
  margin-top: var(--s-4);
}

.prose h2 {
  font-size: var(--step-2);
  line-height: 1.15;
  letter-spacing: -0.02em;
  margin-bottom: var(--s-4);
}

.prose h3 {
  font-size: var(--step-1);
  line-height: 1.25;
  letter-spacing: -0.01em;
  margin: var(--s-6) 0 var(--s-2);
}

.prose a {
  color: var(--ink);
  text-decoration-color: var(--safelight);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

.prose strong {
  font-weight: 650;
}

.prose code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--surface-2);
  border: 1px solid var(--rule);
  border-radius: var(--r-1);
  padding: 0.1em 0.35em;
}

/* Buttons ------------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 44px;
  padding: 0 var(--s-4);
  background: var(--surface);
  border: 1px solid var(--rule-2);
  border-radius: var(--r-2);
  font-size: var(--step-0);
  font-weight: 550;
  cursor: pointer;
  text-decoration: none;
  transition: background-color 0.12s, border-color 0.12s, transform 0.06s;
}

.btn:hover:not(:disabled) {
  background: var(--surface-2);
  border-color: var(--muted);
}

.btn:active:not(:disabled) {
  transform: translateY(1px);
}

.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn--primary {
  background: var(--safelight);
  border-color: var(--safelight);
  color: var(--safelight-ink);
}

.btn--primary:hover:not(:disabled) {
  background: var(--safelight);
  border-color: var(--safelight);
  filter: brightness(1.08);
}

.btn--quiet {
  background: transparent;
  border-color: transparent;
  color: var(--muted);
  font-weight: 500;
}

.btn--quiet:hover:not(:disabled) {
  background: var(--surface-2);
  border-color: var(--rule);
  color: var(--ink);
}

.btn--sm {
  min-height: 34px;
  padding: 0 var(--s-3);
  font-size: var(--step--1);
}

/* ── Header ──────────────────────────────────────────────────────────────── */

.head {
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
}

.head__in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  min-height: 60px;
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  font-weight: 650;
  letter-spacing: -0.02em;
  text-decoration: none;
  color: var(--ink);
}

/* The lamp. Small, and the only glowing thing on the page. */
.lamp {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--safelight);
  box-shadow: var(--glow);
  flex: none;
}

.brand__sub {
  color: var(--muted);
  font-weight: 400;
  font-size: var(--step--1);
  border-left: 1px solid var(--rule);
  padding-left: var(--s-3);
}

@media (max-width: 46em) {
  .brand__sub {
    display: none;
  }
}

.head__nav {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.head__link {
  padding: 0 var(--s-3);
  min-height: 36px;
  display: inline-flex;
  align-items: center;
  color: var(--ink-2);
  text-decoration: none;
  font-size: var(--step--1);
  border-radius: var(--r-2);
}

.head__link:hover {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--safelight);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

@media (max-width: 30em) {
  /* On a narrow phone the sibling-tool link steps back so the brand + theme toggle keep
     their room; the two tools are still cross-linked in the footer and by the SEO agent. */
  .head__link {
    display: none;
  }
}

.room-toggle {
  min-height: 36px;
  padding: 0 var(--s-3);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: var(--r-2);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: 0.06em;
  cursor: pointer;
}

.room-toggle:hover {
  color: var(--ink);
  border-color: var(--muted);
}

/* ── Hero ────────────────────────────────────────────────────────────────── */

/* One grid holds the claim, the wire tap and the tool, so their running order can
   change with the viewport without moving any markup.

     phone   : claim -> tool -> tap   (you came here to convert a photo)
     desktop : claim | tap
               tool  tool             (room to put the instrument beside the claim)

   The tap has no focusable controls, so re-ordering it can't strand a keyboard user. */
.stage {
  padding-block: var(--s-6) var(--s-7);
}

.stage__grid {
  display: grid;
  gap: var(--s-6);
  grid-template-areas: 'hero' 'tool' 'tap';
}

.hero {
  grid-area: hero;
}

.tap {
  grid-area: tap;
}

.tool {
  grid-area: tool;
}

@media (min-width: 62em) {
  .stage {
    padding-block: var(--s-7) var(--s-8);
  }

  .stage__grid {
    grid-template-columns: minmax(0, 1.35fr) minmax(320px, 0.65fr);
    grid-template-areas:
      'hero tap'
      'tool tool';
    column-gap: var(--s-7);
    row-gap: var(--s-6);
    align-items: end;
  }

  /* The tap is the taller of the two, so bottom-aligning the claim to it would leave a
     bank of dead space over the h1. Centre the claim against the instrument instead. */
  .hero {
    align-self: center;
  }
}

.hero h1 {
  font-size: var(--step-4);
  line-height: 0.98;
  letter-spacing: -0.038em;
  font-weight: 680;
  margin: 0;
  text-wrap: balance;
}

/* The keyword is the subject AND the ornament: it gets the safelight. */
.hero h1 em {
  font-style: normal;
  color: var(--safelight);
}

.hero__lede {
  max-width: 48ch;
  margin-top: var(--s-4);
  font-size: var(--step-0);
  line-height: 1.55;
  color: var(--ink-2);
  text-wrap: pretty;
}

@media (min-width: 62em) {
  .hero__lede {
    font-size: var(--step-1);
    line-height: 1.45;
  }
}

/* ── SIGNATURE: the wire tap ─────────────────────────────────────────────────
   The product's whole claim is "nothing leaves your device". Claims are cheap, so
   this panel instruments the page itself and reports what actually went over the
   wire, live, while you convert. It is meant to sit there reading zero.
   It invites you to prove it — DevTools is the check that can't be faked. ------ */

.tap {
  background: var(--sunken);
  border: 1px solid var(--rule);
  border-radius: var(--r-3);
  padding: var(--s-4);
  font-family: var(--font-mono);
}

.tap__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  font-size: var(--step--1);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--rule);
}

.tap__live {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  letter-spacing: 0.08em;
}

.tap__pulse {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--verify);
  animation: pulse 2.6s ease-in-out infinite;
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.25;
  }
}

.tap__rows {
  display: grid;
  gap: var(--s-2);
  padding-block: var(--s-3);
}

.tap__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  font-size: var(--step--1);
}

.tap__label {
  color: var(--muted);
}

/* The zeroes are the headline. Let them be big. */
.tap__val {
  font-size: var(--step-1);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  color: var(--verify);
}

.tap__val[data-dirty='true'] {
  color: var(--fail);
}

/* Two short paragraphs, not one grey wall: the first is the invitation to verify —
   the most important sentence on the page — so it gets the reading colour. */
.tap__foot {
  border-top: 1px solid var(--rule);
  padding-top: var(--s-3);
  font-size: var(--step--1);
  line-height: 1.5;
  font-family: var(--font-sans);
  display: grid;
  gap: var(--s-2);
}

.tap__foot p:first-child {
  color: var(--ink-2);
}

.tap__foot p:last-child {
  color: var(--muted);
}

.tap__foot kbd {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--surface);
  border: 1px solid var(--rule-2);
  border-bottom-width: 2px;
  border-radius: var(--r-1);
  padding: 0.05em 0.35em;
  color: var(--ink-2);
}

/* ── APP ═══════════════════════════════════════════════════════════════════ */

/* Drop zone ---------------------------------------------------------------- */

.drop {
  position: relative;
  display: grid;
  place-items: center;
  gap: var(--s-3);
  padding: var(--s-5) var(--s-4);
  cursor: pointer;
  text-align: center;
  background: var(--surface);
  border: 1px dashed var(--rule-2);
  border-radius: var(--r-3);
  transition: border-color 0.15s, background-color 0.15s;
}

.drop[data-drag='true'] {
  border-color: var(--safelight);
  border-style: solid;
  background: var(--safelight-wash);
}

.drop__mounts {
  width: 108px;
  height: 64px;
  color: var(--rule-2);
  margin-bottom: var(--s-1);
  transition: color 0.15s, transform 0.2s;
}

.drop[data-drag='true'] .drop__mounts {
  color: var(--safelight);
  transform: translateY(-3px);
}

.drop__hint {
  color: var(--muted);
  font-size: var(--step--1);
  max-width: 56ch;
  text-wrap: pretty;
}

.drop__title {
  font-size: var(--step-2);
  font-weight: 620;
  letter-spacing: -0.02em;
}

/* The whole zone is clickable, but the button is the real, focusable control. */
.drop__input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Controls ----------------------------------------------------------------- */

.controls {
  margin-top: var(--s-4);
  padding: var(--s-4);
  display: grid;
  gap: var(--s-5);
}

@media (min-width: 54em) {
  .controls {
    grid-template-columns: auto 1fr auto;
    gap: var(--s-6);
    align-items: start;
  }
}

.field > .eyebrow {
  margin-bottom: var(--s-2);
}

.field__hint {
  margin-top: var(--s-2);
  font-size: var(--step--1);
  color: var(--muted);
  min-height: 1.4em;
}

/* Segmented format picker: a radiogroup, styled. */
.seg {
  display: inline-flex;
  padding: 3px;
  background: var(--sunken);
  border: 1px solid var(--rule);
  border-radius: var(--r-2);
  gap: 2px;
}

.seg__opt {
  position: relative;
}

.seg__opt input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}

.seg__opt span {
  display: block;
  padding: var(--s-2) var(--s-4);
  border-radius: var(--r-1);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--muted);
  transition: background-color 0.12s, color 0.12s;
}

.seg__opt input:hover + span {
  color: var(--ink);
}

.seg__opt input:checked + span {
  background: var(--safelight);
  color: var(--safelight-ink);
}

.seg__opt input:focus-visible + span {
  outline: var(--focus-w) solid var(--safelight);
  outline-offset: 2px;
}

/* Quality slider */
.slider {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}

.slider input[type='range'] {
  flex: 1;
  min-width: 8rem;
  accent-color: var(--safelight);
  height: 30px;
}

.slider output {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  min-width: 3.4ch;
  text-align: right;
}

.select {
  min-height: 40px;
  padding: 0 var(--s-3);
  background: var(--surface);
  border: 1px solid var(--rule-2);
  border-radius: var(--r-2);
  font-size: var(--step--1);
  cursor: pointer;
}

/* Queue -------------------------------------------------------------------- */

.queue {
  margin-top: var(--s-4);
  overflow: hidden;
}

.queue[hidden] {
  display: none;
}

.queue__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3) var(--s-4);
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--rule);
  background: var(--surface-2);
}

.queue__count {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.queue__spacer {
  flex: 1;
}

/* Progress: a film-advance bar, not a candy stripe. */
.meter {
  position: relative;
  flex: 1 1 10rem;
  height: 6px;
  min-width: 6rem;
  background: var(--sunken);
  border-radius: 99px;
  overflow: hidden;
}

.meter__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--safelight);
  border-radius: 99px;
  transition: width 0.25s ease-out;
}

/* Size ledger: the honest bit. Input vs output, always visible, never spun. */
.ledger {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-2) var(--s-4);
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--rule);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  color: var(--muted);
}

.ledger b {
  color: var(--ink);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.ledger__delta[data-dir='up'] {
  color: var(--warn);
}

.ledger__delta[data-dir='down'] {
  color: var(--verify);
}

.ledger__why {
  background: none;
  border: 0;
  padding: 0;
  color: var(--muted);
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.ledger__why:hover {
  color: var(--ink);
}

/* The mismatch notice. Deliberately part of the queue's own furniture — the same weight
   as the size ledger, not a warning and not a toast. It states a fact about the rows
   below it: they are what they say they are, and they are staying that way. */
.mismatch {
  display: flex;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--rule);
  background: var(--safelight-wash);
  color: var(--ink-2);
  font-size: var(--step--1);
  line-height: 1.5;
}

.mismatch::before {
  content: '';
  flex: none;
  width: 3px;
  border-radius: 2px;
  background: var(--safelight);
  align-self: stretch;
}

/* Windowed list: only the visible rows exist in the DOM. */
.queue__scroll {
  overflow-y: auto;
  overscroll-behavior: contain;
}

.queue__scroll[data-virtual='true'] {
  height: min(60vh, 560px);
}

.queue__spacerbox {
  position: relative;
  width: 100%;
}

.row {
  position: absolute;
  left: 0;
  right: 0;
  height: var(--row-h);
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding-inline: var(--s-4);
  border-bottom: 1px solid var(--rule);
}

/* A slide mount, holding the preview. Fixed size, always present, so a row never reflows
   when its thumbnail lands. The status dot rides in the corner like a frame marker. */
.row__thumb {
  position: relative;
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: var(--r-1);
  background: var(--sunken);
  border: 1px solid var(--rule);
  overflow: hidden;
}

.row__thumb-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.row__dot {
  position: absolute;
  left: 3px;
  bottom: 3px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--rule-2);
  /* Legible whether it sits on the empty mount or on top of a photo. */
  box-shadow: 0 0 0 1.5px var(--surface);
}

.row[data-status='running'] .row__dot {
  background: var(--safelight);
  animation: pulse 1.1s ease-in-out infinite;
}

.row[data-status='done'] .row__dot {
  background: var(--verify);
}

.row[data-status='error'] .row__dot {
  background: var(--fail);
}

.row[data-status='cancelled'] .row__dot {
  background: var(--muted);
}

.row__main {
  min-width: 0;
  flex: 1;
}

.row__name {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.row__meta {
  font-size: var(--step--1);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* An error is one row's problem, not the batch's. Stated, not shouted. */
.row[data-status='error'] .row__meta {
  color: var(--fail);
}

.row__sizes {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  text-align: right;
  flex: none;
  white-space: nowrap;
}

.row__sizes b {
  color: var(--ink);
  font-weight: 500;
}

@media (max-width: 40em) {
  .row__sizes {
    display: none;
  }
}

.row__acts {
  display: flex;
  gap: var(--s-1);
  flex: none;
}

.queue__more {
  padding: var(--s-3) var(--s-4);
  font-size: var(--step--1);
  color: var(--muted);
  text-align: center;
}

/* Live region for screen readers — batch state without spamming every row. */
.queue__status {
  padding: var(--s-3) var(--s-4);
  border-top: 1px solid var(--rule);
  background: var(--surface-2);
  font-size: var(--step--1);
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
}

/* Notes ------------------------------------------------------------------- */

.note {
  display: flex;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-2);
  font-size: var(--step--1);
  line-height: 1.5;
  border: 1px solid var(--rule);
  background: var(--surface-2);
}

.note--warn {
  border-color: color-mix(in srgb, var(--warn) 40%, transparent);
  background: var(--warn-wash);
  color: var(--ink-2);
}

.note--fail {
  border-color: color-mix(in srgb, var(--fail) 40%, transparent);
  background: var(--fail-wash);
  color: var(--ink-2);
}

.note[hidden] {
  display: none;
}

/* Ads --------------------------------------------------------------------- */

/* Reserved, sized, and labelled. Height is committed up front so a filled slot
   cannot push content around. Empty until the owner adds a publisher ID. */
.ad {
  margin-block: var(--s-6);
}

.ad__label {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
  margin-bottom: var(--s-2);
}

.ad__box {
  display: grid;
  place-items: center;
  border: 1px dashed var(--rule);
  border-radius: var(--r-2);
  background: var(--surface-2);
}

#ad-below-tool .ad__box {
  min-height: var(--ad-h-below);
}

#ad-in-content .ad__box {
  min-height: var(--ad-h-content);
}

/* Content ------------------------------------------------------------------ */

.grid-2 {
  display: grid;
  gap: var(--s-6);
}

@media (min-width: 54em) {
  .grid-2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s-7);
  }
}

/* A comparison that only exists because the honesty requires it. */
.compare {
  border: 1px solid var(--rule);
  border-radius: var(--r-3);
  overflow: hidden;
  margin-top: var(--s-5);
  font-family: var(--font-mono);
  font-size: var(--step--1);
}

.compare__row {
  display: grid;
  grid-template-columns: 5.5rem 1fr 5.5rem;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
}

.compare__row:last-child {
  border-bottom: 0;
}

.compare__row--head {
  background: var(--surface-2);
  color: var(--muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-size: 0.68rem;
}

.compare__bar {
  height: 12px;
  border-radius: var(--r-1);
  background: var(--rule-2);
  min-width: 2px;
}

.compare__row[data-self='true'] .compare__bar {
  background: var(--safelight);
}

/* PNG is ~12x and would flatten every other bar to a sliver. The bar runs off the
   scale and says so, rather than being quietly rescaled into a lie. */
.compare__bar--over {
  background: repeating-linear-gradient(
    90deg,
    var(--rule-2) 0 6px,
    transparent 6px 10px
  );
}

.compare__note {
  margin-top: var(--s-3);
  color: var(--muted);
  font-size: var(--step--1);
}

.compare__note a {
  color: var(--muted);
  text-underline-offset: 3px;
}

.compare__size {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

.faq dt {
  font-weight: 620;
  margin-top: var(--s-5);
}

.faq dd {
  margin-top: var(--s-2);
  color: var(--ink-2);
  max-width: var(--measure);
}

.foot {
  border-top: 1px solid var(--rule);
  padding-block: var(--s-6);
  color: var(--muted);
  font-size: var(--step--1);
}

.foot__in {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-5);
  align-items: center;
  justify-content: space-between;
}

/* Footer section nav. Lives here (not pages.css) so the two tool pages — which load
   only app.css — pick it up. A discreet row of muted links, safelight underline on hover. */
.foot__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  align-items: center;
}

.foot__nav a {
  color: var(--muted);
  text-decoration-color: var(--rule-2);
  text-underline-offset: 3px;
}

.foot__nav a:hover {
  color: var(--ink);
  text-decoration-color: var(--safelight);
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  /* The pulses carry state (live / working), so keep them legible when still. */
  .tap__pulse,
  .row[data-status='running'] .row__dot {
    opacity: 1;
  }
}
