/* ============================================================================
   Social Utils — a small instrument.

   The product is a tool you open for ten seconds to fix one thing, so the UI
   aims for "precise" rather than "expressive": warm-tinted neutrals, a single
   amber accent borrowed from level-meter hardware, and one clear focal point
   per screen. Colour is spent almost entirely on the control that matters.
   ========================================================================= */

/* --- tokens --------------------------------------------------------------
   OKLCH throughout: equal lightness steps look equal, which HSL cannot do.
   Neutrals carry a trace of the accent hue (~70) so surfaces and brand feel
   related rather than merely adjacent. Chroma drops as lightness rises —
   high chroma at extreme lightness looks cheap.                            */
:root {
  color-scheme: light dark;

  --bg:            oklch(0.975 0.006 78);
  --surface:       oklch(0.995 0.003 78);
  --surface-sunk:  oklch(0.955 0.008 78);
  --text:          oklch(0.24 0.014 62);
  --text-dim:      oklch(0.50 0.013 66);
  /* 0.65 measured 2.85:1 on the sunk surface — far too light for the small
     labels that use it. Held at 0.53, which clears AA against the sunk
     surface (the darkest background this token ever sits on), not just
     against white. */
  --text-faint:    oklch(0.53 0.012 68);
  --line:          oklch(0.90 0.009 72);
  --line-strong:   oklch(0.80 0.012 72);

  --accent:        oklch(0.62 0.135 62);
  --accent-hover:  oklch(0.56 0.140 62);
  /* Amber is a light hue: white on it measured 3.64:1. Ink reads far better
     and matches how the accent is treated in dark mode. */
  --on-accent:     oklch(0.22 0.030 62);
  --accent-ghost:  oklch(0.62 0.135 62 / 0.10);

  --ok:            oklch(0.52 0.115 148);
  --warn:          oklch(0.60 0.130 72);
  /* 0.55 landed on exactly 4.5:1 against the tinted error panel — passing,
     but with no margin. Darkened for headroom. */
  --danger:        oklch(0.51 0.175 27);

  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 22px;

  /* 4pt rhythm, named by role so intent survives refactors */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px; --s-7: 48px;

  --font: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-num: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --shadow-card: 0 1px 2px oklch(0.24 0.014 62 / 0.05),
                 0 8px 24px -12px oklch(0.24 0.014 62 / 0.14);
  --shadow-pop:  0 2px 6px oklch(0.24 0.014 62 / 0.10);

  --ease: cubic-bezier(0.22, 0.68, 0.32, 1);
  --dur: 200ms;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:           oklch(0.165 0.008 66);
    --surface:      oklch(0.205 0.010 68);
    --surface-sunk: oklch(0.145 0.008 66);
    --text:         oklch(0.965 0.006 78);
    --text-dim:     oklch(0.735 0.011 74);
    /* 0.595 measured 4.47:1 for the small uppercase labels — a hair under AA */
    --text-faint:   oklch(0.615 0.011 72);
    --line:         oklch(0.295 0.011 68);
    --line-strong:  oklch(0.395 0.014 68);

    /* lifted and slightly desaturated for dark — not the light value inverted */
    --accent:       oklch(0.775 0.125 70);
    --accent-hover: oklch(0.825 0.120 72);
    --on-accent:    oklch(0.18 0.012 66);
    --accent-ghost: oklch(0.775 0.125 70 / 0.14);

    --ok:           oklch(0.76 0.130 150);
    --warn:         oklch(0.80 0.120 76);
    --danger:       oklch(0.72 0.140 25);

    --shadow-card: 0 1px 2px oklch(0 0 0 / 0.30),
                   0 12px 32px -16px oklch(0 0 0 / 0.60);
    --shadow-pop:  0 2px 8px oklch(0 0 0 / 0.40);
  }
}

/* --- base ---------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

button, label, .drop-zone, .fc-remove, .btn, .seg-opt {
  user-select: none; -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* keep content clear of the notch and the home indicator */
  padding:
    calc(var(--s-6) + env(safe-area-inset-top))
    calc(var(--s-4) + env(safe-area-inset-right))
    calc(var(--s-7) + env(safe-area-inset-bottom))
    calc(var(--s-4) + env(safe-area-inset-left));
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

.wiz { width: 100%; max-width: 460px; }

/* --- stepper -------------------------------------------------------------
   Reads as a progress rail rather than three loose dots: the active step is a
   filled bar so position is legible at a glance without counting.          */
.progress-bar {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-bottom: var(--s-5);
  padding-inline: var(--s-1);
}
.step-dot {
  width: 6px; height: 6px;
  border-radius: 99px;
  background: var(--line-strong);
  transition: width var(--dur) var(--ease), background var(--dur) var(--ease);
  flex-shrink: 0;
}
.step-dot.done   { background: var(--accent); }
.step-dot.active { width: 26px; background: var(--accent); }
.step-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-dim);
  margin-left: var(--s-1);
  letter-spacing: 0.01em;
}

/* --- card ---------------------------------------------------------------- */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  padding: var(--s-5);
  display: none;
  box-shadow: var(--shadow-card);
  animation: rise 260ms var(--ease);
}
.card.active { display: block; }

@keyframes rise {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

.card-title {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin-bottom: var(--s-1);
}
.card-sub {
  font-size: 14px;
  color: var(--text-dim);
  margin-bottom: var(--s-5);
  text-wrap: pretty;
}

/* --- drop zone ----------------------------------------------------------- */
.drop-zone {
  position: relative;
  border: 1.5px dashed var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--surface-sunk);
  padding: var(--s-7) var(--s-4);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.drop-zone:hover, .drop-zone:focus-within {
  border-color: var(--accent);
  background: var(--accent-ghost);
}
.drop-zone input[type=file] {
  position: absolute; inset: 0;
  opacity: 0; cursor: pointer;
  width: 100%; height: 100%;
}
.drop-zone > i {
  font-size: 30px;
  color: var(--accent);
  display: block;
  margin-bottom: var(--s-2);
}
.dz-title { font-size: 15px; font-weight: 550; }
.dz-sub   { font-size: 13px; color: var(--text-faint); margin-top: 2px; }

/* --- file chip ----------------------------------------------------------- */
.file-chip {
  display: none;
  align-items: center;
  gap: var(--s-3);
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s-3);
}
.file-chip > i {
  font-size: 18px;
  color: var(--accent);
  flex-shrink: 0;
  width: 38px; height: 38px;
  display: grid; place-items: center;
  background: var(--accent-ghost);
  border-radius: var(--r-md);
}
.fc-meta { flex: 1; min-width: 0; }
.fc-name {
  font-size: 14px; font-weight: 550;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fc-size {
  font-size: 12px; color: var(--text-faint);
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
}
.fc-remove {
  background: none; border: none; cursor: pointer;
  color: var(--text-faint);
  font-size: 18px; line-height: 1;
  flex-shrink: 0;
  /* 44pt target without disturbing the chip's height */
  width: 44px; height: 44px; margin: -8px -10px -8px 0;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.fc-remove:hover { color: var(--danger); background: var(--surface); }

/* --- operation block -----------------------------------------------------
   Deliberately not a card: it already sits inside one, and nesting cards adds
   a frame that carries no information.                                     */
.op-card { margin-bottom: var(--s-2); }
.op-info { margin-bottom: var(--s-4); }
.op-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.op-param { display: none; }
.op-param.visible { display: block; }

/* --- the loudness dial ---------------------------------------------------
   The one thing worth looking at on this screen, so it gets the size budget:
   an oversized tabular readout above a track whose filled portion is driven
   by --pct (set from render()). Tabular figures stop the number jittering as
   it changes, which on a live-dragging control is very visible.            */
.dial {
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: var(--s-5) var(--s-4) var(--s-4);
}
.dial-readout {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: var(--s-2);
  margin-bottom: var(--s-4);
}
.dial-value {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-size: 46px;
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--text);
  /* "−6" is a character shorter than "−24"; reserving the wider case stops the
     number and its unit shuffling sideways while the slider is being dragged */
  min-width: 3.1ch;
  text-align: center;
}
.dial-unit {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--text-faint);
}
.dial-scale {
  display: flex;
  justify-content: space-between;
  margin-top: var(--s-3);
  font-family: var(--font-num);
  font-size: 11px;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.dial-scale em {
  font-family: var(--font);
  font-style: normal;
  letter-spacing: 0.04em;
}

input[type=range] {
  --pct: 50%;
  -webkit-appearance: none; appearance: none;
  width: 100%;
  height: 26px;             /* generous hit area; the track is drawn smaller */
  background: transparent;
  cursor: pointer;
  display: block;
}
input[type=range]::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 99px;
  background: linear-gradient(to right,
    var(--accent) 0 var(--pct), var(--line-strong) var(--pct) 100%);
}
input[type=range]::-moz-range-track {
  height: 6px; border-radius: 99px; background: var(--line-strong);
}
input[type=range]::-moz-range-progress {
  height: 6px; border-radius: 99px; background: var(--accent);
}
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 24px; height: 24px;
  margin-top: -9px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--accent);
  box-shadow: var(--shadow-pop);
  transition: transform 120ms var(--ease);
}
input[type=range]::-moz-range-thumb {
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--accent);
  box-shadow: var(--shadow-pop);
}
input[type=range]:active::-webkit-slider-thumb { transform: scale(1.12); }

/* --- segmented control (output format) ----------------------------------- */
.fmt-pills {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: var(--s-1);
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s-1);
}
.fmt-pill {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font);
  font-size: 14px;
  font-weight: 550;
  letter-spacing: 0.02em;
  min-height: 40px;
  border-radius: calc(var(--r-md) - 5px);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.fmt-pill:hover:not(.active) { color: var(--text); }
.fmt-pill.active {
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--shadow-pop);
}

/* --- buttons -------------------------------------------------------------
   One primary per screen; everything else is quiet so the primary reads
   without needing to shout.                                                */
.btn {
  width: 100%;
  min-height: 50px;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid var(--line-strong);
  background: transparent;
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  font-weight: 550;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  gap: var(--s-2);
  margin-top: var(--s-5);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              opacity var(--dur) var(--ease), transform 100ms var(--ease);
}
.btn:hover  { background: var(--surface-sunk); border-color: var(--text-faint); }
.btn:active { transform: scale(0.985); }
.btn.primary {
  background: var(--accent);
  color: var(--on-accent);
  border-color: transparent;
  box-shadow: var(--shadow-pop);
}
.btn.primary:hover:not(:disabled) { background: var(--accent-hover); border-color: transparent; }

/* Disabled must not merely be a faded version of enabled: an accent fill at
   40% opacity still reads as a filled, tappable button (and drags its label
   down to unreadable contrast). Drop the fill entirely instead. */
.btn:disabled,
.btn.primary:disabled {
  cursor: not-allowed;
  transform: none;
  background: transparent;
  border-color: var(--line);
  color: var(--text-faint);
  box-shadow: none;
}
.btn i { font-size: 17px; }

.btn-row { display: flex; gap: var(--s-2); margin-top: var(--s-5); }
.btn-row .btn { margin-top: 0; }
.btn-row .btn:first-child { flex: 0 0 40%; }
.btn-row .btn:last-child  { flex: 1; }

/* --- status --------------------------------------------------------------- */
.status-row {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  background: var(--surface-sunk);
  border: 1px solid var(--line);
  margin-bottom: var(--s-4);
  font-size: 14px;
  font-weight: 500;
  color: var(--text-dim);
}
.status-row i { font-size: 19px; flex-shrink: 0; }
.st-msg { flex: 1; text-wrap: pretty; }
.status-row.done-ok   { color: var(--ok);     border-color: color-mix(in oklab, var(--ok) 34%, var(--line)); }
.status-row.done-fail { color: var(--warn);   border-color: color-mix(in oklab, var(--warn) 34%, var(--line)); }
.status-row.done-err  { color: var(--danger); border-color: color-mix(in oklab, var(--danger) 34%, var(--line)); }

.spinner {
  width: 17px; height: 17px;
  border: 2px solid var(--line-strong);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 700ms linear infinite;
  flex-shrink: 0;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --- applied-operation tags ---------------------------------------------- */
.ops-summary { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-bottom: var(--s-4); }
.ops-tag {
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  padding: 5px 10px;
  border-radius: var(--r-sm);
  background: var(--accent-ghost);
  color: var(--accent);
  border: 1px solid color-mix(in oklab, var(--accent) 26%, transparent);
}
@media (prefers-color-scheme: dark) {
  .ops-tag { color: var(--accent); }
}

/* --- result preview ------------------------------------------------------- */
.preview-wrap {
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface-sunk);
  min-height: 170px;
  display: flex; align-items: center; justify-content: center;
  margin-bottom: var(--s-4);
}
.preview-wrap video, .preview-wrap img { width: 100%; display: block; }
.preview-ph { text-align: center; color: var(--text-faint); padding: var(--s-6) var(--s-4); }
.preview-ph i { font-size: 30px; display: block; margin-bottom: var(--s-2); opacity: 0.7; }
.preview-ph p { font-size: 13px; }

/* --- login ---------------------------------------------------------------
   Served from the same stylesheet as the app so the palette cannot drift:
   /style.css is public, so the login page can link it before signing in.   */
.login-shell {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--s-5);
}
.login-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-card);
  padding: var(--s-6) var(--s-5);
  width: 100%;
  max-width: 380px;
  animation: rise 260ms var(--ease);
}
.login-mark {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--accent-ghost);
  color: var(--accent);
  font-size: 22px;
  margin-bottom: var(--s-4);
}
.login-title {
  font-size: 22px; font-weight: 600;
  letter-spacing: -0.015em;
  margin-bottom: var(--s-1);
}
.login-sub {
  font-size: 14px; color: var(--text-dim);
  margin-bottom: var(--s-5);
}
.field { margin-bottom: var(--s-4); }
.field label {
  display: block;
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: var(--s-2);
}
.field-wrap { position: relative; display: flex; }
input[type=password], input[type=text].pw {
  width: 100%;
  min-height: 50px;
  padding: var(--s-3) 52px var(--s-3) var(--s-4);
  /* 16px keeps iOS from zooming the viewport when the field takes focus */
  font-size: 16px;
  font-family: var(--font);
  color: var(--text);
  background: var(--surface-sunk);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  outline: none;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
input[type=password]:focus, input[type=text].pw:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ghost);
}
.pw-toggle {
  position: absolute;
  right: 4px; top: 50%;
  transform: translateY(-50%);
  width: 44px; height: 44px;      /* full-size target over a small glyph */
  display: grid; place-items: center;
  background: none; border: none;
  color: var(--text-faint);
  font-size: 18px;
  cursor: pointer;
  border-radius: var(--r-sm);
  transition: color var(--dur) var(--ease);
}
.pw-toggle:hover { color: var(--text); }
.login-error {
  display: flex; align-items: center; gap: var(--s-2);
  margin-top: var(--s-4);
  padding: var(--s-3);
  font-size: 13px;
  color: var(--danger);
  background: color-mix(in oklab, var(--danger) 10%, transparent);
  border: 1px solid color-mix(in oklab, var(--danger) 30%, transparent);
  border-radius: var(--r-md);
}
.login-error i { font-size: 16px; flex-shrink: 0; }

/* --- utilities ------------------------------------------------------------ */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}

/* --- motion preferences ---------------------------------------------------
   Motion here is small and functional, but a vestibular trigger is a
   vestibular trigger — honour the request rather than merely shortening it. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .spinner { animation: spin 900ms linear infinite !important; }
}
