/*
 * Flyagrammetry web app. One accent (the desktop app's teal, #0E6F74), neutral
 * greys leaning slightly towards it, system fonts, light and dark from the
 * operating system's preference. No web fonts, no framework.
 */

:root {
  color-scheme: light dark;
  --accent: #0e6f74;
  --accent-hover: #0b5d61;
  --accent-soft: #e4f1f1;
  --accent-ring: rgba(14, 111, 116, 0.35);
  --on-accent: #ffffff;
  --bg: #f5f7f7;
  --surface: #ffffff;
  --surface-2: #f8faf9;
  --surface-3: #eef2f1;
  --text: #16232b;
  --text-2: #35444c;
  --muted: #5d6b72;
  --faint: #8a979d;
  --border: #e1e6e5;
  --border-strong: #c9d2d0;
  --ok: #1f7a44;
  --ok-soft: #e7f4ec;
  --warn: #8a5a0b;
  --warn-soft: #fbf1dd;
  --bad: #a23b2a;
  --bad-soft: #fbeae6;
  --shadow-sm: 0 1px 2px rgba(16, 28, 32, 0.05);
  --shadow: 0 1px 2px rgba(16, 28, 32, 0.04), 0 6px 20px -8px rgba(16, 28, 32, 0.10);
  --shadow-lg: 0 20px 50px -12px rgba(16, 28, 32, 0.28);
  --radius: 14px;
  --radius-sm: 9px;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif,
    "Apple Color Emoji", "Segoe UI Emoji";
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  /* The 3D preview's camera poses (viewer.js reads these for its lines): where the flight's
     file put each photo in amber, where the reconstruction placed it in teal, the whisker
     between the two grey. The viewer's backdrop is dark in both themes and a model's surface
     can be anything from sky to soot, so one set of mid-tones serves both. */
  --pose-original: #e8a33a;
  --pose-estimated: #22b5aa;
  --pose-link: #aebbc0;
  /* Bridged surface (v45): the tint over the faces the reconstruction continued across
     featureless gaps (viewer.js reads it for its material, at 45 %), and its toggle when on:
     a redder orange than the original poses' amber, on the same dark backdrop. */
  --bridged: #ff6b1a;
}

@media (prefers-color-scheme: dark) {
  :root {
    --accent: #3fb4ba;
    --accent-hover: #5ec4c9;
    --accent-soft: rgba(63, 180, 186, 0.13);
    --accent-ring: rgba(63, 180, 186, 0.45);
    --on-accent: #04191b;
    --bg: #0c1113;
    --surface: #131a1d;
    --surface-2: #172024;
    --surface-3: #1d272b;
    --text: #e6edef;
    --text-2: #c5d0d4;
    --muted: #93a2a8;
    --faint: #6a7a81;
    --border: #232e33;
    --border-strong: #34434a;
    --ok: #52c98f;
    --ok-soft: rgba(82, 201, 143, 0.12);
    --warn: #e5b04f;
    --warn-soft: rgba(229, 176, 79, 0.12);
    --bad: #f28471;
    --bad-soft: rgba(242, 132, 113, 0.12);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 8px 24px -10px rgba(0, 0, 0, 0.5);
    --shadow-lg: 0 24px 60px -12px rgba(0, 0, 0, 0.7);
  }
}

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

/* the hidden attribute must win over every display rule below */
[hidden] { display: none !important; }

/* One-column grids whose items must shrink below their content: a long file
   name or job ID ellipsises instead of widening the page (a grid item's
   automatic minimum is its min-content width unless the track starts at 0). */
.zones, .job-list, .job-hero, .stage, .zone-progress, .viewer-message {
  grid-template-columns: minmax(0, 1fr);
}

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

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 { margin: 0; line-height: 1.25; letter-spacing: -0.01em; }
p { margin: 0; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }
code, pre, .mono { font-family: var(--mono); font-size: 0.92em; }
.muted { color: var(--muted); }
.small { font-size: 13px; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}
h1:focus, main:focus { outline: none; }

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

.skip-link {
  position: absolute;
  left: 12px; top: -48px;
  z-index: 100;
  padding: 8px 14px;
  background: var(--accent);
  color: var(--on-accent);
  border-radius: 8px;
  transition: top 0.15s var(--ease);
}
.skip-link:focus { top: 10px; text-decoration: none; }

.container {
  width: 100%;
  max-width: 920px;
  margin: 0 auto;
  padding-left: 24px;
  padding-right: 24px;
}

/* ---- top bar ------------------------------------------------------------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(1.6) blur(12px);
  -webkit-backdrop-filter: saturate(1.6) blur(12px);
  border-bottom: 1px solid var(--border);
}

.topbar-inner {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 24px;
  height: 60px;
  display: flex;
  align-items: center;
  gap: 28px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--text);
  font-weight: 650;
  font-size: 16px;
  letter-spacing: -0.015em;
  flex-shrink: 0;
}
.brand:hover { text-decoration: none; }
.logo { display: block; border-radius: 7px; flex-shrink: 0; }

.tabs {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 100%;
}

.tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 100%;
  padding: 0 12px;
  color: var(--muted);
  font-weight: 520;
  font-size: 14px;
  white-space: nowrap;
  transition: color 0.15s var(--ease);
}
.tab:hover { color: var(--text); text-decoration: none; }
.tab.is-active { color: var(--text); }
.tab.is-active::after {
  content: "";
  position: absolute;
  left: 12px; right: 12px; bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
}
.tab:focus-visible { outline-offset: -6px; }

.signed-out .tabs { visibility: hidden; }

.topbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

/* who is signed in (Google, through the proxy): a person, then the address */
.user-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  max-width: 280px;
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-size: 12.5px;
  white-space: nowrap;
}
.user-chip .icon { flex-shrink: 0; }
.user-email { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.user-chip[hidden], .upload-pill[hidden] { display: none; }

.upload-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.upload-pill:hover { text-decoration: none; filter: brightness(0.97); }

/* ---- page ------------------------------------------------------------------ */

main.container { flex: 1; padding-top: 36px; padding-bottom: 56px; }
main.container.container-wide { max-width: 1120px; }

.page-head { margin-bottom: 24px; }
.page-head-tight { margin-bottom: 18px; }
/* a heading with its tools on the right: Jobs' Everyone and Refresh */
.page-head-row { display: flex; align-items: flex-end; justify-content: space-between; flex-wrap: wrap; gap: 14px 20px; }
.page-tools { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.page-head h1 { font-size: 28px; font-weight: 700; letter-spacing: -0.025em; }
.lede { margin-top: 6px; color: var(--muted); font-size: 15.5px; max-width: 62ch; }
/* New reconstruction's line for first-timers, under the lede: there, and nothing more */
.page-pointer { margin-top: 6px; color: var(--muted); font-size: 13.5px; }

.footer {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 8px;
  padding-top: 20px;
  padding-bottom: 28px;
  color: var(--faint);
  font-size: 12.5px;
  border-top: 1px solid var(--border);
  max-width: 920px;
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 14px;
  color: var(--muted);
  font-size: 14px;
  font-weight: 520;
}
.back-link:hover { color: var(--text); text-decoration: none; }

/* ---- cards ----------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 22px 24px;
  margin-bottom: 18px;
}

.card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}
.card-title { font-size: 16px; font-weight: 650; letter-spacing: -0.01em; }
.title-tag { margin-left: 8px; vertical-align: 2px; font-variant-numeric: tabular-nums; }
.card-sub { margin-top: 4px; color: var(--muted); font-size: 13.5px; max-width: 60ch; }
.card-tools { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }

/* ---- buttons ----------------------------------------------------------------- */

.btn {
  --btn-bg: var(--surface);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 38px;
  padding: 0 15px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--btn-bg);
  color: var(--text);
  font: inherit;
  font-size: 14px;
  font-weight: 560;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease), color 0.15s var(--ease),
    box-shadow 0.15s var(--ease), transform 0.06s var(--ease);
}
.btn:hover { text-decoration: none; }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn .icon { flex-shrink: 0; }

.btn-primary { --btn-bg: var(--accent); color: var(--on-accent); box-shadow: 0 1px 2px rgba(14, 111, 116, 0.25); }
.btn-primary:hover:not(:disabled) { --btn-bg: var(--accent-hover); }
.btn-secondary { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.btn-secondary:hover:not(:disabled) { --btn-bg: var(--surface-3); }
.btn-ghost { --btn-bg: transparent; color: var(--muted); }
.btn-ghost:hover:not(:disabled) { --btn-bg: var(--surface-3); color: var(--text); }
.btn-danger { --btn-bg: var(--bad); color: #fff; }
.btn-danger:hover:not(:disabled) { filter: brightness(0.93); }
.btn-danger-ghost { --btn-bg: transparent; color: var(--bad); border-color: color-mix(in srgb, var(--bad) 35%, transparent); }
.btn-danger-ghost:hover:not(:disabled) { --btn-bg: var(--bad-soft); }
.btn-sm { min-height: 32px; padding: 0 11px; font-size: 13px; gap: 6px; }
.btn-lg { min-height: 46px; padding: 0 20px; font-size: 15px; border-radius: 11px; }
.btn-icon { padding: 0; width: 32px; }
.btn-block { width: 100%; }
/* a button that stays down: Jobs' Everyone */
.toggle[aria-pressed="true"] {
  --btn-bg: var(--accent-soft);
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
}
.toggle[aria-pressed="true"]:hover:not(:disabled) { --btn-bg: var(--accent-soft); filter: brightness(0.97); }
.btn-danger-ghost[hidden] { display: none; }
/* waiting for the service (Download dataset): the spinner in full, the pointer saying so */
.btn[aria-busy="true"]:disabled, .link-button[aria-busy="true"]:disabled { opacity: 1; cursor: progress; }

.button-row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }

/* ---- form fields ----------------------------------------------------------- */

.label { display: block; margin-bottom: 6px; font-size: 13.5px; font-weight: 600; color: var(--text-2); }
.field-hint { margin-top: 6px; color: var(--muted); font-size: 12.5px; }
/* under Detail: what the depth maps take on the fusion machine (fusion.js);
   quiet while they fit, the error colour with its mark when they do not */
.fusion-line:empty { display: none; }
.fusion-line {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-top: 4px;
  color: var(--muted);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.fusion-line .icon { flex-shrink: 0; margin-top: 2px; }
.fusion-line.is-bad { color: var(--bad); font-weight: 560; }

.input, .select {
  width: 100%;
  min-height: 40px;
  padding: 8px 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 14.5px;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.input::placeholder { color: var(--faint); }
.input:focus, .select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.input:disabled, .select:disabled { opacity: 0.6; }
.input-lg { min-height: 46px; font-size: 15px; }
.select {
  appearance: none;
  padding-right: 34px;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  cursor: pointer;
  text-overflow: ellipsis;   /* Detail's "-1 (… large flights may not fit)" is wider than a phone's field */
}
.select-sm { width: auto; min-height: 32px; padding: 4px 30px 4px 10px; font-size: 13.5px; }

.input-row { display: flex; gap: 10px; }
.input-row .input { flex: 1; min-width: 0; }

.checkbox {
  width: 17px; height: 17px;
  margin: 0;
  accent-color: var(--accent);
  flex-shrink: 0;
  cursor: pointer;
}
.check-field { display: inline-flex; align-items: center; gap: 9px; font-size: 14px; color: var(--text-2); cursor: pointer; }
.check-field.is-disabled { color: var(--faint); cursor: default; }
.inline-field { display: inline-flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--muted); }

/* Machines and Detail (the job's name has a card of its own, at the top).
   Machines' default option, "Auto (recommended)", is 137 px of 14.5 px
   Segoe UI: half the card is room enough at any width above the phone one. */
.settings-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 18px;
}
/* Enclosed space, under both: its label runs to two or three lines, so the
   box stays by the first one and the hint lines up with the words */
.field-wide { grid-column: 1 / -1; }
.check-field-top { align-items: flex-start; }
.check-field-top .checkbox { margin-top: 2px; }
.check-hint { padding-left: 26px; }        /* the box, 17 px, and the gap, 9 px */

/* ---- drop zones ---------------------------------------------------------------- */

.zones { display: grid; gap: 12px; }

.zone {
  position: relative;
  min-width: 0;
  display: flex;
  gap: 16px;
  padding: 18px 18px 18px 16px;
  border: 1.5px dashed var(--border-strong);
  border-radius: 12px;
  background: var(--surface-2);
  transition: border-color 0.18s var(--ease), background-color 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
.zone-icon {
  display: grid;
  place-items: center;
  width: 42px; height: 42px;
  flex-shrink: 0;
  border-radius: 11px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--muted);
  transition: color 0.18s var(--ease), background-color 0.18s var(--ease), border-color 0.18s var(--ease);
}
.zone-main { flex: 1; min-width: 0; }
.zone-title { display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 620; }
.zone-body { margin-top: 4px; }
.zone-hint { color: var(--muted); font-size: 13.5px; display: flex; align-items: center; gap: 8px; }
.zone-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 12px; }
.zone-status:empty { display: none; }
.zone-status { margin-top: 12px; }
.zone-status > * + * { margin-top: 8px; }     /* the poses: the header's angles, then rows left out */
.zone-ok { display: flex; align-items: flex-start; gap: 6px; color: var(--ok); font-size: 13.5px; }
/* a line that wraps on a phone (the calibration's) keeps its mark whole, by the first line */
.zone-ok .icon { flex-shrink: 0; margin-top: 2px; }
.zone-progress { display: grid; gap: 6px; color: var(--muted); font-size: 13px; }

.zone.is-drag {
  border-color: var(--accent);
  border-style: solid;
  background: var(--accent-soft);
  box-shadow: 0 0 0 4px var(--accent-ring);
}
.zone.is-drag .zone-icon { color: var(--accent); border-color: var(--accent); }
.zone.is-filled { border-style: solid; background: var(--surface); }
.zone.is-ok { border-color: color-mix(in srgb, var(--ok) 45%, var(--border)); }
.zone.is-ok .zone-icon { color: var(--ok); background: var(--ok-soft); border-color: transparent; }
.zone.is-warn { border-color: color-mix(in srgb, var(--warn) 50%, var(--border)); }
.zone.is-warn .zone-icon { color: var(--warn); background: var(--warn-soft); border-color: transparent; }
.zone.is-bad { border-color: color-mix(in srgb, var(--bad) 55%, var(--border)); background: var(--surface); }
.zone.is-bad .zone-icon { color: var(--bad); background: var(--bad-soft); border-color: transparent; }
.zone.is-busy .zone-icon { color: var(--accent); }
/* Camera: the choice first, under the title, then its line (an Elios 3's
   factory values, or another camera's calibration file) */
.zone-actions.camera-choice { margin-top: 8px; }
.camera-line { margin-top: 10px; }

.tag {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 560;
  letter-spacing: 0.01em;
}

.file-line { display: flex; align-items: center; gap: 10px; min-width: 0; }
.file-name {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.file-meta { color: var(--muted); font-size: 13px; white-space: nowrap; }
.file-line .btn-icon { margin-left: auto; flex-shrink: 0; }

/* ---- notices, the name check ------------------------------------------------------- */

.notice {
  display: flex;
  gap: 10px;
  padding: 11px 13px;
  border-radius: 10px;
  font-size: 13.5px;
  line-height: 1.5;
  border: 1px solid transparent;
}
.notice-icon { margin-top: 1px; flex-shrink: 0; }
.notice-body { min-width: 0; overflow-wrap: anywhere; }
.notice-sub { display: block; margin-top: 2px; opacity: 0.85; }
.notice-ok { background: var(--ok-soft); color: var(--ok); border-color: color-mix(in srgb, var(--ok) 20%, transparent); }
.notice-warn { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
.notice-bad { background: var(--bad-soft); color: var(--bad); border-color: color-mix(in srgb, var(--bad) 22%, transparent); }
.notice-info { background: var(--accent-soft); color: var(--accent); }
.notice strong { font-weight: 650; }
.notice .plain-list { margin: 4px 0 0; padding-left: 18px; }

.check {
  margin-top: 16px;
  padding: 14px 16px;
  border-radius: 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.check-empty { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 13.5px; }
.check-head { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; }
.check-head strong { font-weight: 650; }
.check-size { margin-left: auto; color: var(--muted); font-size: 13px; font-weight: 520; }
.check-list { margin: 8px 0 0; padding-left: 28px; color: var(--text-2); font-size: 13.5px; }
.check-list li + li { margin-top: 2px; }
.check-ok { background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 25%, transparent); }
.check-ok .check-head { color: var(--ok); }
.check-warn { background: var(--warn-soft); border-color: color-mix(in srgb, var(--warn) 25%, transparent); }
.check-warn .check-head { color: var(--warn); }
.check-bad { background: var(--bad-soft); border-color: color-mix(in srgb, var(--bad) 25%, transparent); }
.check-bad .check-head { color: var(--bad); }

/* ---- start and upload ---------------------------------------------------------------- */

.start { margin: 6px 0 18px; }
.start-row { display: flex; align-items: center; flex-wrap: wrap; gap: 14px 18px; }
.start-hint { color: var(--muted); font-size: 13.5px; max-width: 46ch; }
.problems:empty { display: none; }
.problems { margin-top: 14px; }
.notice-link { display: inline-block; margin-top: 6px; color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }

/* a dataset already uploaded, to start again; and the budget, quietly */
.reuse-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; margin-top: 14px; }
.reuse-row .select-sm { max-width: 100%; min-width: 0; }
.reuse-note:empty { display: none; }
.reuse-note { margin-bottom: 12px; }
.budget-line { margin-top: 14px; color: var(--faint); font-size: 12.5px; font-variant-numeric: tabular-nums; }
.budget-line:empty { display: none; }
.budget-line a { color: var(--muted); }
.budget-sep { margin: 0 6px; color: var(--faint); }

.upload-card { border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }
.upload-card[hidden] { display: none; }
.upload-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.upload-pct { font-size: 26px; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.upload-stats {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px 16px;
  margin: 14px 0 8px;
  color: var(--text-2);
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
}

.progress {
  position: relative;
  height: 8px;
  border-radius: 999px;
  background: var(--surface-3);
  overflow: hidden;
}
.progress-bar {
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 70%, #7fd6d9));
  transition: width 0.35s var(--ease);
}
.progress.is-indeterminate .progress-bar {
  width: 35%;
  animation: indeterminate 1.3s var(--ease) infinite;
}
@keyframes indeterminate {
  from { transform: translateX(-110%); }
  to { transform: translateX(310%); }
}
.progress[hidden] { display: none; }

.spinner {
  display: inline-block;
  width: 15px; height: 15px;
  border: 2px solid color-mix(in srgb, currentColor 25%, transparent);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  flex-shrink: 0;
}
.spinner-sm { width: 12px; height: 12px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---- status pills ------------------------------------------------------------------ */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 620;
  white-space: nowrap;
  background: var(--surface-3);
  color: var(--muted);
}
.pill-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.pill-queued { background: color-mix(in srgb, #6b7fd6 14%, transparent); color: #4c5fb8; }
.pill-running { background: var(--accent-soft); color: var(--accent); }
.pill-running .pill-dot { animation: pulse 1.6s ease-in-out infinite; }
.pill-succeeded { background: var(--ok-soft); color: var(--ok); }
.pill-failed { background: var(--bad-soft); color: var(--bad); }
.pill-cancelled, .pill-unknown { background: var(--surface-3); color: var(--muted); }
.pill-expired { background: var(--warn-soft); color: var(--warn); }
@media (prefers-color-scheme: dark) {
  .pill-queued { color: #9fb0f5; }
}
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.35; transform: scale(0.8); }
}

/* ---- before the app: checking the sign-in, on the way to it, refused ---------------- */

.gate-page { display: grid; place-items: center; min-height: calc(100vh - 260px); }
.gate-card { width: 100%; max-width: 460px; padding: 32px; box-shadow: var(--shadow-lg); }
.gate-brand .logo { width: 44px; height: 44px; border-radius: 11px; margin-bottom: 18px; }
.gate-card h1 { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; }
.gate-card .lede { font-size: 14.5px; }
.gate-card > .muted { margin-top: 12px; }
.gate-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 22px; }
.gate-wait { display: flex; align-items: center; gap: 10px; margin-top: 10px; color: var(--muted); font-size: 14.5px; }

/* ---- jobs list ---------------------------------------------------------------------- */

.open-form .input-row { margin-top: 2px; }
.open-form [role="alert"]:not(:empty) { margin-top: 12px; }

.job-list { display: grid; }
.jobs-note { margin: -6px 0 18px; }
.jobs-note:empty { display: none; }
/* A row is the job's name first — renamable, so outside the link, which may
   hold no button or field — with its owner under it when the job is someone
   else's, then the link to the job: status, ID, machines, time; and last,
   outside the link too, Download dataset, in a slot every row keeps, so that
   rows with and without it line up. A click on the name opens the job as
   well (main.js). The name gets 35 % of what the slot leaves: the ID then
   keeps its first 8 characters, the ones people quote, down to about 780 px
   (narrower, a job on ten machines may show 7 until the 760 px breakpoint). */
.job-row {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 13fr) 32px;
  align-items: center;
  gap: 16px;
  padding: 0 10px;
  margin: 0 -10px;
  border-radius: 10px;
  color: var(--text);
  transition: background-color 0.12s var(--ease);
}
.job-row + .job-row { border-top: 1px solid var(--border); }
.job-row:hover { background: var(--surface-2); }
.job-row:hover + .job-row { border-top-color: transparent; }
.job-row-link {
  display: grid;
  grid-template-columns: 112px minmax(0, 1fr) auto 18px;
  align-items: center;
  gap: 16px;
  min-width: 0;
  padding: 12px 0;
  color: var(--text);
}
.job-row-link:hover { text-decoration: none; }
.job-row-title { display: grid; grid-template-columns: minmax(0, 1fr); align-content: center; min-width: 0; padding: 8px 0; }
.job-row-owner {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: 12.5px;
}
.job-row-name .name-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
  cursor: pointer;
}
.job-row-name .name-rename { min-height: 28px; padding: 0 8px; font-size: 12.5px; }
.job-row-id { color: var(--muted); font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.job-row-meta { display: flex; gap: 14px; color: var(--muted); font-size: 13px; white-space: nowrap; }
.job-row-go { color: var(--faint); transition: transform 0.15s var(--ease), color 0.15s var(--ease); }
.job-row:hover .job-row-go { transform: translateX(2px); color: var(--accent); }
.job-row-end { display: flex; justify-content: center; }
.empty { color: var(--muted); font-size: 14px; padding: 6px 0; }

/* A job's name with its Rename button, and the field that takes their place
   while it is renamed: in a Jobs row, and as the job page's heading. */
.name-edit { display: flex; align-items: center; gap: 6px; min-width: 0; }
.name-text.is-empty { color: var(--faint); font-weight: 400; }
.name-rename { flex-shrink: 0; }
.name-input { min-height: 34px; padding: 5px 10px; font-size: 14px; }
.name-edit-heading { flex-wrap: wrap; gap: 6px 12px; }
.name-edit-heading .name-text { min-width: 0; overflow-wrap: anywhere; }
.name-edit-heading .name-input { flex: 1 1 280px; max-width: 560px; min-height: 44px; font-size: 20px; font-weight: 650; }

/* ---- one job ------------------------------------------------------------------------------ */

.job-hero { display: grid; gap: 10px; }
.job-hero > .notice { margin-bottom: 6px; }
.job-hero-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.job-hero-top .label { margin: 0; text-transform: uppercase; letter-spacing: 0.06em; font-size: 11.5px; color: var(--muted); }
.job-id-row { display: flex; align-items: center; flex-wrap: wrap; gap: 12px 16px; }
.job-id {
  font-size: clamp(16px, 3.2vw, 24px);
  font-weight: 600;
  letter-spacing: -0.01em;
  overflow-wrap: anywhere;
  user-select: all;
}
.job-id-actions { display: flex; gap: 8px; }
.job-keep { font-size: 13.5px; max-width: 70ch; }
.job-headline { margin-top: 6px; font-size: 16px; font-weight: 650; }
.job-headline:empty { display: none; }
.job-detail { font-size: 14px; }

.stepper {
  list-style: none;
  margin: 4px 0 20px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
}
.step {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-align: center;
  min-width: 0;
}
.step::before {
  content: "";
  position: absolute;
  top: 10px;
  right: 50%;
  width: 100%;
  height: 2px;
  background: var(--border);
  z-index: 0;
}
.step:first-child::before { display: none; }
.step-done::before, .step-current::before, .step-failed::before, .step-stopped::before { background: var(--accent); }
.step-dot {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--border-strong);
  color: var(--on-accent);
  transition: background-color 0.3s var(--ease), border-color 0.3s var(--ease);
}
.step-label { font-size: 11.5px; line-height: 1.3; color: var(--faint); font-weight: 520; padding: 0 2px; overflow-wrap: anywhere; }
.step-done .step-dot { background: var(--accent); border-color: var(--accent); }
.step-done .step-label { color: var(--muted); }
.step-current .step-dot { border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-ring); }
.step-current .step-dot::after {
  content: "";
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse 1.6s ease-in-out infinite;
}
.step-current .step-label { color: var(--text); font-weight: 650; }
.step-failed .step-dot { background: var(--bad); border-color: var(--bad); color: #fff; }
.step-failed .step-label { color: var(--bad); font-weight: 650; }
.step-stopped .step-dot { background: var(--faint); border-color: var(--faint); }
.step-stopped .step-label { color: var(--text-2); font-weight: 600; }

.stage { display: grid; gap: 10px; }
.stage-text { font-weight: 560; color: var(--text-2); }
.progress-line {
  display: block;
  padding: 10px 12px;
  border-radius: 9px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.5;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}
.progress-line[hidden] { display: none; }
.poll-line { color: var(--faint); font-size: 12.5px; font-variant-numeric: tabular-nums; white-space: nowrap; }

.facts {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 10px 28px;
  margin: 0;
  font-size: 14px;
}
.facts dt { color: var(--muted); }
.facts dd { margin: 0; overflow-wrap: anywhere; }

.result-row { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; }
.error-text {
  margin: 0 0 12px;
  padding: 14px 16px;
  max-height: 360px;
  overflow: auto;
  border-radius: 10px;
  background: var(--bad-soft);
  border: 1px solid color-mix(in srgb, var(--bad) 25%, transparent);
  color: var(--text);
  font-size: 12.5px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  user-select: text;
}

/* ---- whose a job is, and sharing it -------------------------------------------------------- */

.job-access { display: grid; gap: 6px; margin-top: 6px; }
.job-access .lede, .job-access .share-line { margin-top: 0; }
.job-owner { display: flex; align-items: center; gap: 7px; }
.job-owner .icon { flex-shrink: 0; }
.job-owner strong { color: var(--text-2); font-weight: 600; overflow-wrap: anywhere; }
.share-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; }
.share-line { display: inline-flex; align-items: center; gap: 7px; color: var(--muted); font-size: 14.5px; }
.share-line .icon { flex-shrink: 0; }

.modal-wide { width: min(560px, calc(100vw - 32px)); }
.share-label { margin-top: 18px; }

/* addresses as chips, the field to type the next one in after them */
.chip-field {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 6px 8px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: text;
  transition: border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.chip-field:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.chips { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; margin: 0; padding: 0; list-style: none; }
.chips:empty { display: none; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  max-width: 100%;
  min-width: 0;
  padding: 3px 3px 3px 10px;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--text);
  font-size: 13px;
}
.chip-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chip-remove {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 22px; height: 22px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.chip-remove:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); color: var(--text); }
.chip-input {
  flex: 1 1 180px;
  min-width: 120px;
  min-height: 30px;
  padding: 2px 4px;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 14.5px;
}
.chip-input::placeholder { color: var(--faint); }
.share-said { margin-top: 10px; }
.share-said:empty { display: none; }

/* a checkbox drawn as a switch; the real one stays, for the keyboard and screen readers */
.switch-field { position: relative; display: flex; align-items: flex-start; gap: 12px; margin-top: 18px; cursor: pointer; }
.switch-input { position: absolute; left: 0; top: 0; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none; }
.switch {
  position: relative;
  flex-shrink: 0;
  width: 38px; height: 22px;
  margin-top: 1px;
  border-radius: 999px;
  background: var(--border-strong);
  transition: background-color 0.15s var(--ease);
}
.switch::after {
  content: "";
  position: absolute;
  top: 3px; left: 3px;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s var(--ease);
}
.switch-input:checked + .switch { background: var(--accent); }
.switch-input:checked + .switch::after { transform: translateX(16px); }
.switch-input:focus-visible + .switch { outline: 2px solid var(--accent); outline-offset: 2px; }
.switch-text { display: grid; gap: 2px; font-size: 14px; }
.switch-sub { color: var(--muted); font-size: 13px; }

/* ---- the Account page: the budget as a bar, what fills it as tables --------------------- */

.usage-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 4px; margin-bottom: 10px; font-variant-numeric: tabular-nums; }
.usage-big { font-size: 24px; font-weight: 700; letter-spacing: -0.02em; }
.usage { position: relative; height: 10px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.usage-fill { height: 100%; min-width: 2px; border-radius: inherit; background: var(--accent); transition: width 0.35s var(--ease); }
.usage.is-warn .usage-fill { background: var(--warn); }
.usage.is-full .usage-fill { background: var(--bad); }
.usage-line {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 16px;
  margin-top: 10px;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.storage > .notice { margin-top: 14px; }
.storage-seats { display: flex; align-items: center; gap: 7px; margin-top: 14px; color: var(--muted); font-size: 13.5px; }
.storage-seats .budget-sep { margin: 0; }

.table-said:empty { display: none; }
.table-said { margin-bottom: 12px; }
/* positioned, so the visually hidden header text (absolute) scrolls inside it
   instead of widening the page on a phone */
.table-wrap { position: relative; overflow-x: auto; margin: 0 -6px; padding: 0 6px; }
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th {
  padding: 0 10px 8px;
  border-bottom: 1px solid var(--border);
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 600;
  text-align: left;
  white-space: nowrap;
}
.table td { padding: 9px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.table th:first-child, .table td:first-child { padding-left: 0; }
.table th:last-child, .table td:last-child { padding-right: 0; }
.table tbody tr:hover { background: var(--surface-2); }
.table tfoot td { border-bottom: 0; padding-top: 10px; color: var(--muted); font-weight: 600; font-size: 13px; }
.table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cell-name { font-weight: 560; }
.cell-name > span, .cell-name > a { display: block; max-width: min(300px, 42vw); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cell-time { white-space: nowrap; color: var(--text-2); }
.row-actions { display: flex; justify-content: flex-end; gap: 6px; }
.fact-link { white-space: nowrap; }
/* a button that reads as a link: Download dataset in a job's Details, beside New job from it */
.link-button {
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font: inherit;
  cursor: pointer;
}
.link-button:hover:not(:disabled) { text-decoration: underline; text-underline-offset: 2px; }
.link-button:disabled { color: var(--muted); }
.link-button .spinner { margin-right: 6px; vertical-align: -1px; }

/* ---- the Admin page: one row per account, the budget edited in place ------------------ */

.admin-table td { vertical-align: middle; }
.admin-table tr.is-disabled td { color: var(--muted); }
.cell-account { min-width: 200px; }
.cell-email { display: block; max-width: min(280px, 46vw); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.cell-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; }
.cell-tags:empty { display: none; }
.tag-accent { background: var(--accent-soft); color: var(--accent); }
.tag-bad { background: var(--bad-soft); color: var(--bad); }
.cell-usage { min-width: 110px; }
.cell-holds { display: grid; color: var(--text-2); font-size: 13px; white-space: nowrap; }
.cell-used { display: block; margin-bottom: 5px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.usage-sm { height: 6px; }
.quota-edit { display: flex; align-items: center; gap: 6px; }
.quota-input { width: 76px; min-height: 32px; padding: 4px 8px; font-size: 14px; text-align: right; font-variant-numeric: tabular-nums; }
.row-said td { padding-top: 0; }
.row-said .notice { margin-bottom: 4px; }

/* ---- the Admin page's RunPod costs: a strip of months, the month picked, all time ---------- */

/* One bar per month, newest right, its figure over it and its month under it.
   The strip scrolls in its own box when the months outgrow the card (a
   phone); the page never does. */
.cost-strip {
  display: flex;
  gap: 4px;
  margin: 0 -4px 20px;
  padding: 2px 4px 6px;
  overflow-x: auto;
  scrollbar-width: thin;
}
.cost-bar {
  flex: 1 0 56px;
  max-width: 96px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  padding: 8px 4px 6px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
  transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease);
}
.cost-bar:hover { background: var(--surface-2); }
.cost-bar[aria-pressed="true"] {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--text);
}
.cost-bar-value { font-size: 11.5px; font-weight: 600; line-height: 1.2; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cost-bar-track {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100%;
  height: 72px;
  border-bottom: 2px solid var(--border-strong);
}
.cost-bar-fill {
  width: 24px;
  max-width: 100%;
  border-radius: 5px 5px 0 0;
  background: color-mix(in srgb, var(--accent) 38%, transparent);
  transition: height 0.35s var(--ease), background-color 0.15s var(--ease);
}
.cost-bar:hover .cost-bar-fill { background: color-mix(in srgb, var(--accent) 60%, transparent); }
.cost-bar[aria-pressed="true"] .cost-bar-fill { background: var(--accent); }
.cost-bar-label { font-size: 12.5px; font-weight: 560; line-height: 1.2; white-space: nowrap; }
.cost-bar-year { min-height: 13px; color: var(--faint); font-size: 11px; line-height: 1.2; font-variant-numeric: tabular-nums; }
/* this month: its name in the accent colour */
.cost-bar.is-current .cost-bar-label { color: var(--accent); font-weight: 700; }

.cost-month-head { display: flex; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; gap: 10px 16px; margin-bottom: 14px; }
.cost-month-main { min-width: 0; }
.cost-month-title { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; color: var(--text-2); font-size: 14px; font-weight: 650; }
.cost-total { margin-top: 2px; font-size: 24px; font-weight: 700; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.cost-line { margin-top: 6px; max-width: 78ch; color: var(--muted); font-size: 13.5px; font-variant-numeric: tabular-nums; }
.cost-note { display: flex; align-items: flex-start; gap: 6px; color: var(--warn); }
.cost-note .icon { flex-shrink: 0; margin-top: 2px; }
.cost-part { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--border); }
.cost-part-title { font-size: 15px; font-weight: 650; }
.cost-part-sub { margin-bottom: 12px; }
.cost-table .cell-email { max-width: min(300px, 52vw); }
/* the month's jobs: nine columns, a size smaller and closer together, so that
   they fit a 1,024 px screen; narrower, they scroll in their box */
.cost-jobs { font-size: 13.5px; }
.cost-jobs th, .cost-jobs td { padding-left: 7px; padding-right: 7px; }
.cost-job { min-width: 160px; }
.cost-job-name { display: block; max-width: min(230px, 46vw); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 560; }
.cost-owner { display: block; max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-2); }
.cost-rates-table { max-width: 460px; }
.cost-again { margin-top: 8px; }

/* a disclosure: a quiet summary with a chevron that turns, its body under it */
.disclosure { margin-top: 16px; }
.disclosure > summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 2px;
  color: var(--text-2);
  font-size: 14px;
  font-weight: 600;
  list-style: none;
  cursor: pointer;
  user-select: none;
}
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary::before {
  content: "";
  width: 7px;
  height: 7px;
  margin: 0 2px 0 1px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.15s var(--ease);
}
.disclosure[open] > summary::before { transform: rotate(45deg); }
.disclosure > summary:hover { color: var(--text); }
.disclosure-body { margin-top: 10px; }
.disclosure-body > .cost-line:first-child { margin-top: 0; margin-bottom: 10px; }

/* ---- the Instructions page: six steps, the contents, controls as keys ----------------------- */

/* The router owns the hash, so the contents scroll to a step themselves
   (guide.js); the margin keeps the step's heading clear of the sticky bar. */
.guide-step { scroll-margin-top: 76px; }
.guide-toc { padding-top: 18px; padding-bottom: 14px; }
.guide-toc-title { margin-bottom: 6px; color: var(--muted); font-size: 13px; font-weight: 600; }
.guide-toc-list { margin: 0; padding: 0; list-style: none; columns: 2 240px; column-gap: 28px; }
.guide-toc-list li { break-inside: avoid; }
.guide-toc-list a { display: flex; align-items: center; gap: 10px; padding: 5px 0; color: var(--text); font-size: 14.5px; font-weight: 520; }
.guide-toc-list a:hover { color: var(--accent); text-decoration: none; }
.guide-num, .guide-toc-num {
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.guide-toc-num { width: 22px; height: 22px; font-size: 12px; }
.guide-head { align-items: center; flex-wrap: wrap; gap: 8px 16px; margin-bottom: 10px; }
.guide-title { position: relative; display: flex; align-items: center; gap: 10px; font-size: 17px; }
/* where the step happens: a page of the app is a link */
.guide-where {
  flex-shrink: 0;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 560;
  white-space: nowrap;
}
a.guide-where { background: var(--accent-soft); color: var(--accent); }
a.guide-where:hover { text-decoration: none; filter: brightness(0.97); }
.guide-lede { max-width: 70ch; margin-bottom: 12px; color: var(--text-2); font-size: 14.5px; }
.guide-sub { margin: 16px 0 6px; color: var(--text-2); font-size: 13.5px; font-weight: 650; }
.guide-list { max-width: 72ch; margin: 0; padding-left: 20px; font-size: 14.5px; }
.guide-list li + li { margin-top: 7px; }
.guide-list li::marker { color: var(--faint); }
/* a control or a label named as the page shows it: a key in the text */
.ui-name {
  padding: 0 5px;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text);
  font-size: 0.93em;
  font-weight: 600;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.guide-code {
  padding: 1px 3px;
  border-radius: 5px;
  background: var(--surface-3);
  color: var(--text-2);
  overflow-wrap: anywhere;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* ---- viewer ---------------------------------------------------------------------------------- */

.viewer-card { padding-bottom: 24px; }
.viewer-slot { min-height: 120px; }
.viewer-empty {
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 40px 16px;
  border-radius: 12px;
  background: var(--surface-2);
  border: 1px dashed var(--border-strong);
  color: var(--muted);
  text-align: center;
  font-size: 14px;
}

/* The preview and, once a click asks for one, the photo beside it (v43, photopanel.js): the box
   the preview used to be, now shared by the two along a divider; full screen takes both. */
.viewer-split {
  position: relative;
  display: flex;
  width: 100%;
  aspect-ratio: 16 / 10;
  min-height: 280px;
  max-height: 72vh;
  border-radius: 12px;
  overflow: hidden;
  background: #121819;
}
.viewer-split.is-stacked { flex-direction: column; }
/* below the preview, the photo needs height of its own: the box grows while it is open (within
   the 72vh cap), so a phone's photo is not a strip */
.viewer-split.is-stacked.has-photo { aspect-ratio: 5 / 8; }
.viewer-split.is-fullscreen { max-height: none; border-radius: 0; aspect-ratio: auto; }
.viewer {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: radial-gradient(120% 90% at 50% 20%, #33434a 0%, #1c2529 55%, #121819 100%);
  color: #e8eff1;
  touch-action: none;
  user-select: none;
}
/* the overlays share the viewer by its own width (a phone, a narrow window, full screen): the
   container queries after the toolbar's rules */
.viewer { container-type: inline-size; }
.viewer-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; outline: none; }
.viewer.is-measuring .viewer-canvas { cursor: crosshair; }
/* The viewer takes the focus (a click, or Tab) for F and the fly mode's keys: a ring when the
   keyboard brought it there, none for a click. */
.viewer:focus { outline: none; }
.viewer:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Flying (flycontrols.js): the cursor aims until a click hands the view the mouse, which the
   browser then hides. */
.viewer.is-flying .viewer-canvas, .viewer.is-flying.is-over-pose .viewer-canvas { cursor: crosshair; }
.viewer.is-locked .viewer-canvas { cursor: none; }
/* While the view holds the mouse, a small reticle at its centre: what a click aims at (v43). A
   white ring and dot on a dark halo, so it reads on any surface; nothing to click. */
.viewer-reticle {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 3;
  display: none;
  width: 18px;
  height: 18px;
  transform: translate(-50%, -50%);
  border: 1.5px solid rgba(255, 255, 255, 0.92);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(10, 16, 18, 0.55), inset 0 0 0 1px rgba(10, 16, 18, 0.55);
  pointer-events: none;
}
.viewer-reticle::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 3px;
  height: 3px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: #ffffff;
  box-shadow: 0 0 0 1px rgba(10, 16, 18, 0.55);
}
.viewer.is-locked .viewer-reticle { display: block; }

.viewer-overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 24px;
  z-index: 2;
}
.viewer-overlay[hidden] { display: none; }
.viewer-message { display: grid; justify-items: center; gap: 10px; width: min(420px, 100%); text-align: center; font-size: 14px; }
.viewer-message .muted { color: #a9b8be; }
.viewer-message .progress { width: 100%; background: rgba(255, 255, 255, 0.12); }
.viewer-status { font-variant-numeric: tabular-nums; color: #cfdadd; }

.viewer-toolbar {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 3;
  display: flex;
  gap: 4px;
  padding: 4px;
  border-radius: 11px;
  background: rgba(14, 20, 22, 0.62);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.viewer-toolbar[hidden] { display: none; }
.viewer-tool {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: #d9e4e7;
  cursor: pointer;
  transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
}
.viewer-tool:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
.viewer-tool.is-on { background: #ffd23f; color: #12181a; }
.viewer-tool[hidden] { display: none; }
/* the chosen view mode reads as selected, not as a tool that is switched on */
.viewer-view.is-on { background: rgba(255, 255, 255, 0.2); color: #fff; }
/* a mode this model cannot show (Photo on a preview without texture): marked
   with aria-disabled rather than disabled, so it still hovers and its title
   can say why */
.viewer-tool[aria-disabled="true"] { opacity: 0.38; cursor: not-allowed; }
.viewer-tool[aria-disabled="true"]:hover { background: transparent; color: #d9e4e7; }
/* between the view modes and the tools */
.viewer-toolbar-sep {
  align-self: stretch;
  width: 1px;
  margin: 6px 3px;
  background: rgba(255, 255, 255, 0.16);
}
/* between the view modes and the pose toggles: a thin gap, no line */
.viewer-toolbar-gap { flex: 0 0 4px; }
/* A pose toggle that is on wears its set's colour, so the two buttons are the legend of the
   lines they show; it pulses while the file is on its way. */
.viewer-pose.is-on { background: color-mix(in srgb, currentColor 20%, transparent); }
.viewer-pose.is-on:hover { background: color-mix(in srgb, currentColor 30%, transparent); }
.viewer-pose-original.is-on, .viewer-pose-original.is-on:hover { color: var(--pose-original); }
.viewer-pose-estimated.is-on, .viewer-pose-estimated.is-on:hover { color: var(--pose-estimated); }
.viewer-pose[aria-busy="true"] .icon { animation: pose-busy 0.8s var(--ease) infinite alternate; }
/* Bridged surface, on: it wears the tint's colour, the legend of what it shows, as a pose toggle does. */
.viewer-bridged.is-on, .viewer-bridged.is-on:hover { color: var(--bridged); }
.viewer-bridged.is-on { background: color-mix(in srgb, currentColor 20%, transparent); }
.viewer-bridged.is-on:hover { background: color-mix(in srgb, currentColor 30%, transparent); }
@keyframes pose-busy {
  from { opacity: 1; }
  to { opacity: 0.35; }
}

.viewer-info, .viewer-hint {
  position: absolute;
  left: 12px;
  z-index: 3;
  padding: 5px 10px;
  border-radius: 8px;
  background: rgba(14, 20, 22, 0.55);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  font-size: 12px;
  color: #dbe5e8;
  pointer-events: none;
}
.viewer-info { top: 12px; font-variant-numeric: tabular-nums; }
.viewer-info:empty { display: none; }
/* the mesh's figures, then the poses' (or "loading poses…", or why they could not be read) */
.viewer-info-line { display: block; }
.viewer-info-poses { color: #b9c7cc; }
/* one line (v43: the mouse, the keys and their speed, mouse look), cut short with an ellipsis where
   the view is too narrow for it, and gone with the narrow layouts below */
.viewer-hint {
  bottom: 12px;
  right: 12px;
  left: auto;
  color: #b9c7cc;
  max-width: calc(100% - 24px);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The fly mode's strip, while flying: the keys, the speed, what Esc does next (and once, why
   dragging looks instead of the mouse). In the page's own surface and text, light or dark, near
   opaque so it reads over any model. */
.viewer-fly-hint {
  position: absolute;
  left: 50%;
  bottom: 12px;
  z-index: 3;
  transform: translateX(-50%);
  width: max-content;
  max-width: calc(100% - 24px);
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  box-shadow: var(--shadow);
  color: var(--text-2);
  font-size: 12px;
  line-height: 1.75;
  text-align: center;
  pointer-events: none;
}
.viewer-fly-hint kbd {
  padding: 0 5px;
  border: 1px solid var(--border-strong);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--text);
  font: 600 11px/1.5 var(--font);
}
.viewer-fly-note { display: block; color: var(--warn); line-height: 1.5; }

/* a camera's photo and its offset, over the camera; the edge says which set it is in */
.viewer-pose-tip {
  position: absolute;
  left: 0; top: 0;
  z-index: 4;
  display: grid;
  gap: 1px;
  max-width: min(340px, calc(100% - 16px));
  padding: 6px 10px 6px 9px;
  border-left: 3px solid var(--pose-estimated);
  border-radius: 7px;
  background: rgba(14, 20, 22, 0.86);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: #e8eff1;
  font-size: 12px;
  line-height: 1.4;
  pointer-events: none;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
}
.viewer-pose-tip[data-set="original"] { border-left-color: var(--pose-original); }
.viewer-pose-tip-name { font-weight: 650; overflow-wrap: anywhere; }
.viewer-pose-tip-detail { color: #b9c7cc; font-variant-numeric: tabular-nums; }
.viewer.is-over-pose .viewer-canvas { cursor: pointer; }
/* a narrow view breaks the figures between their " · " parts, never inside "6 cm" */
.viewer-figure { white-space: nowrap; }

/* Too narrow for the figures beside the toolbar (405 px with the pose toggles and Fly, room for
   370 px of figures at 800): the figures go to the bottom edge, where the hint was. */
@container (max-width: 800px) {
  .viewer-info { top: auto; bottom: 12px; max-width: calc(100% - 24px); }
  .viewer-hint { display: none; }
  /* flying, the strip takes the bottom edge and the figures go under the toolbar */
  .viewer.is-flying .viewer-info { top: 64px; bottom: auto; }
}
/* A phone: the toolbar spans the top edge and its buttons share the width — ten of them in
   the 309 px of a 375 px screen, eight without the pose toggles (a touch screen has no Fly). */
@container (max-width: 440px) {
  .viewer-toolbar { left: 8px; right: 8px; top: 8px; gap: 0; justify-content: space-between; }
  .viewer-tool { flex: 1 1 0; width: auto; min-width: 0; max-width: 48px; }
  .viewer-toolbar-sep { margin: 6px 2px; }
  .viewer-toolbar-gap { flex-basis: 2px; }
  .viewer-info { left: 8px; bottom: 8px; max-width: calc(100% - 16px); }
  .viewer.is-flying .viewer-info { top: 60px; }
  .viewer-fly-hint { bottom: 8px; max-width: calc(100% - 16px); }
}
/* Fly is for a mouse and a keyboard: a screen with nothing but touch shows no button for it. */
@media not all and (any-pointer: fine) {
  .viewer-tool.viewer-fly { display: none; }
}

.viewer-measure {
  position: absolute;
  left: 0; top: 0;
  z-index: 4;
  padding: 4px 9px;
  border-radius: 7px;
  background: #ffd23f;
  color: #12181a;
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  pointer-events: none;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
}
.viewer-measure[hidden] { display: none; }

/* ---- the photo beside the preview (v43, photopanel.js) ------------------------------------------ */

/* The divider: a line in the page's border colour with a grip, wider to the pointer than to the
   eye; the accent while it is hovered, focused or dragged. Beside the preview it moves sideways,
   below it up and down; the arrow keys move it too. */
.photo-divider {
  position: relative;
  z-index: 5;
  flex: 0 0 10px;
  margin: 0 -3px;
  cursor: col-resize;
  touch-action: none;
  outline: none;
}
.photo-divider::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  transform: translateX(-50%);
  background: var(--border-strong);
}
.photo-divider::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 6px;
  height: 34px;
  transform: translate(-50%, -50%);
  border: 1px solid var(--border-strong);
  border-radius: 4px;
  background: var(--surface);
}
.photo-divider:hover::before, .photo-divider:focus-visible::before, .viewer-split.is-resizing .photo-divider::before {
  background: var(--accent);
}
.photo-divider:hover::after, .photo-divider:focus-visible::after, .viewer-split.is-resizing .photo-divider::after {
  border-color: var(--accent);
}
.viewer-split.is-stacked .photo-divider { margin: -3px 0; cursor: row-resize; }
.viewer-split.is-stacked .photo-divider::before { top: 50%; bottom: auto; left: 0; right: 0; width: auto; height: 2px; transform: translateY(-50%); }
.viewer-split.is-stacked .photo-divider::after { width: 34px; height: 6px; }
.viewer-split.is-resizing { cursor: col-resize; user-select: none; }
.viewer-split.is-stacked.is-resizing { cursor: row-resize; }

/* The panel, in the page's own surface and text, light or dark; its share of the split is set by
   photopanel.js (flex-basis). The photo sits on the page's third surface. */
.photo-panel {
  flex: 0 0 40%;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  min-width: 0;
  min-height: 0;
  background: var(--surface);
  color: var(--text);
}
.photo-head {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 5px 5px 5px 12px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  font-weight: 650;
}
.photo-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.photo-tool {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
}
.photo-tool:hover:not(:disabled) { background: var(--surface-3); color: var(--text); }
.photo-tool:disabled { opacity: 0.35; cursor: default; }
.photo-tool:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.photo-view {
  position: relative;
  overflow: hidden;
  background: var(--surface-3);
  touch-action: none;
  user-select: none;
}
.photo-view.is-zoomed { cursor: grab; }
.photo-view.is-panning { cursor: grabbing; }
.photo-sheet { position: absolute; inset: 0; transform-origin: 0 0; }
/* the photo's own shape, placed and turned about its centre by photopanel.js (Rotate photo, R):
   the picture and its crosshair turn together */
.photo-frame { position: absolute; transform-origin: 50% 50%; }
/* the pixels as stored, never turned by an EXIF tag: the picture must match its frustum (the
   panel turns the frame instead, for the eye) */
.photo-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-orientation: none;
  -webkit-user-drag: none;
}
/* The point's crosshair: a ring and a cross open at its centre, the 3D marker's yellow on a
   dark halo, the same size whatever the zoom. photopanel.js puts its centre on the pixel, inside
   the photo's frame (left and top as fractions, translate(-50%, -50%)), and undoes the zoom. */
.photo-crosshair {
  position: absolute;
  left: 0;
  top: 0;
  width: 26px;
  height: 26px;
  border: 2px solid #ffd23f;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(10, 16, 18, 0.7), inset 0 0 0 1px rgba(10, 16, 18, 0.7);
  pointer-events: none;
}
.photo-crosshair::before, .photo-crosshair::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  box-shadow: 0 0 0 1px rgba(10, 16, 18, 0.55);
}
.photo-crosshair::before {
  width: 2px;
  height: 44px;
  background: linear-gradient(#ffd23f 0 36%, transparent 36% 64%, #ffd23f 64% 100%);
}
.photo-crosshair::after {
  width: 44px;
  height: 2px;
  background: linear-gradient(90deg, #ffd23f 0 36%, transparent 36% 64%, #ffd23f 64% 100%);
}
.photo-message {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 10px;
  padding: 16px;
  color: var(--muted);
  font-size: 13.5px;
  text-align: center;
}
.photo-foot { padding: 4px 5px; border-top: 1px solid var(--border); }
.photo-steps { display: flex; align-items: center; gap: 4px; }
.photo-figures {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 0;
  color: var(--text-2);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  text-align: center;
  position: relative;
}
.photo-line { min-width: 0; }
/* the turn just chosen ("180°"), for a moment over the line, which keeps its place: the footer
   keeps its height and the photo its size */
.photo-turn { position: absolute; inset: 0; display: grid; place-items: center; color: var(--text); font-weight: 650; }
.photo-figures.is-turned > .photo-line, .photo-figures.is-turned > .photo-busy { visibility: hidden; }
.photo-note { margin: 2px 6px 3px; color: var(--warn); font-size: 12px; line-height: 1.4; }
/* photos given with no clear line of sight to the point: one line, as the note */
.photo-blocked { margin: 2px 6px 3px; color: var(--warn); font-size: 12px; line-height: 1.4; text-align: center; }
/* A phone, or a narrow window: the photo below the preview, its chrome tighter. */
.viewer-split.is-stacked .photo-head { padding: 3px 3px 3px 10px; font-size: 12.5px; }
.viewer-split.is-stacked .photo-foot { padding: 2px 3px; }
.viewer-split.is-stacked .photo-tool { width: 28px; height: 28px; }
.viewer-split.is-stacked .photo-figures { font-size: 12px; }

/* ---- dialogs and toasts ------------------------------------------------------------------------ */

.modal {
  width: min(460px, calc(100vw - 32px));
  padding: 24px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-lg);
}
.modal::backdrop { background: rgba(8, 14, 16, 0.45); backdrop-filter: blur(2px); }
.modal[open] { animation: rise 0.18s var(--ease); }
.modal-title { font-size: 18px; font-weight: 700; margin-bottom: 10px; }
.modal-text { color: var(--text-2); font-size: 14.5px; }
.modal-text + .modal-text { margin-top: 8px; }
.modal-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 10px; margin-top: 22px; }
@keyframes rise {
  from { opacity: 0; transform: translateY(6px) scale(0.99); }
  to { opacity: 1; transform: none; }
}

.toasts {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 50;
  display: grid;
  gap: 8px;
  justify-items: end;
  pointer-events: none;
}
.toast {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: min(420px, calc(100vw - 40px));
  padding: 10px 14px;
  border-radius: 10px;
  background: #16232b;
  color: #f1f6f7;
  font-size: 13.5px;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.2s var(--ease), transform 0.2s var(--ease);
}
.toast.is-in { opacity: 1; transform: none; }
.toast .icon { flex-shrink: 0; }     /* a note runs to two or three lines */
.toast-ok .icon { color: #6fdca4; }
.toast-bad .icon { color: #ff9b87; }
@media (prefers-color-scheme: dark) {
  .toast { background: #e8eff1; color: #10181b; }
  .toast-ok .icon { color: #1f7a44; }
  .toast-bad .icon { color: #a23b2a; }
}

/* ---- small screens ----------------------------------------------------------------------------------- */

@media (max-width: 760px) {
  .settings-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

  .stepper { grid-template-columns: minmax(0, 1fr); gap: 0; margin-left: 2px; }
  .step { flex-direction: row; align-items: center; text-align: left; gap: 12px; min-height: 34px; }
  .step::before { top: auto; bottom: 50%; right: auto; left: 10px; width: 2px; height: 100%; }
  .step-label { font-size: 13.5px; }

  /* the name on a line of its own, then status and ID, then machines and
     time, with Download dataset's slot at their end */
  .job-row { grid-template-columns: minmax(0, 1fr) 32px; gap: 0 8px; }
  .job-row-title { grid-column: 1 / -1; padding: 10px 0 0; }
  .job-row-link { grid-template-columns: auto minmax(0, 1fr) 18px; gap: 4px 12px; padding: 6px 0 12px; }
  .job-row-status { grid-column: 1; grid-row: 1; }
  .job-row-id { grid-column: 2; grid-row: 1; }
  .job-row-meta { grid-column: 1 / span 2; grid-row: 2; }
  .job-row-go { grid-column: 3; grid-row: 1 / span 2; }
}

@media (max-width: 640px) {
  .container { padding-left: 16px; padding-right: 16px; }
  .topbar-inner { padding: 0 16px; gap: 12px; height: auto; min-height: 56px; flex-wrap: wrap; }
  .brand { height: 56px; }
  .tabs {
    order: 3; width: calc(100% + 32px); height: 42px; margin: 0 -16px; padding: 0 6px; border-top: 1px solid var(--border);
    overflow-x: auto; scrollbar-width: none; gap: 0;
  }
  .signed-out .tabs { display: none; }
  /* four tabs fit a 360 px phone (an admin's fifth scrolls into view) */
  .tab { padding: 0 8px; }
  .tab.is-active::after { left: 8px; right: 8px; }
  .user-chip .user-email { display: none; }
  main.container { padding-top: 24px; }
  .page-head h1 { font-size: 24px; }
  .card { padding: 18px 16px; border-radius: 12px; }
  .zone { padding: 14px; gap: 12px; }
  .zone-icon { width: 36px; height: 36px; border-radius: 10px; }
  .file-line { flex-wrap: wrap; row-gap: 0; }
  .file-name { flex: 1 1 0; }
  .file-meta { order: 3; flex-basis: 100%; white-space: normal; }
  .settings-grid { grid-template-columns: minmax(0, 1fr); }
  .start-row .btn-lg { width: 100%; }
  .input-row { flex-direction: column; }
  .card-head { flex-wrap: wrap; }
  .facts { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .facts dd + dt { margin-top: 10px; }
  .viewer-split { aspect-ratio: 4 / 5; }
  .viewer-hint { display: none; }
  .gate-card { padding: 24px 20px; }
  .toasts { left: 16px; right: 16px; justify-items: stretch; }
  .toast { max-width: none; }
  /* the bar is two rows here, 111 px: the brand, then the tabs */
  .guide-step { scroll-margin-top: 124px; }
  .cost-bar { flex-basis: 50px; }
  .cost-total { font-size: 21px; }
}

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