@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');

:root {
  --bg: #f7f7fb;
  --bg-grad: radial-gradient(1100px 420px at 12% -12%, rgba(124,58,237,0.06) 0%, rgba(124,58,237,0) 62%),
             radial-gradient(900px 380px at 100% 0%, rgba(236,72,153,0.05) 0%, rgba(236,72,153,0) 58%);
  --panel: #ffffff;
  --panel-soft: #fbfbfe;
  --ink: #14151f;
  --muted: #6f7080;
  --muted-2: #9498a6;
  --border: #e6e6f0;
  --border-soft: #ececf5;

  --accent: #7C3AED;
  --accent-2: #ec4899;
  --accent-3: #06b6d4;
  --accent-ink: #ffffff;
  --accent-soft: #efedff;
  --accent-3-soft: #e0f8fc;

  --good: #10b981;
  --good-soft: #dcfce9;
  --warn: #f59e0b;
  --warn-soft: #fef3e0;
  --bad: #ef4444;
  --bad-soft: #fde8e8;

  --radius: 16px;
  --radius-sm: 10px;
  --shadow-sm: 0 1px 2px rgba(20,22,31,0.05), 0 1px 1px rgba(20,22,31,0.03);
  --shadow-md: 0 8px 24px -8px rgba(20,22,31,0.14), 0 2px 6px -2px rgba(20,22,31,0.07);
  --shadow-lg: 0 20px 45px -12px rgba(20,22,31,0.2), 0 6px 16px -6px rgba(20,22,31,0.1);
}

:root[data-theme="dark"] {
  --bg: #09090B;
  --bg-grad: radial-gradient(1100px 420px at 12% -12%, rgba(167,139,250,0.10) 0%, rgba(167,139,250,0) 62%),
             radial-gradient(900px 380px at 100% 0%, rgba(236,72,153,0.07) 0%, rgba(236,72,153,0) 58%);
  --panel: #111117;
  --panel-soft: #16161d;
  --ink: #f0f0f5;
  --muted: #8b8b96;
  --muted-2: #6f7080;
  --border: #24242e;
  --border-soft: #1b1b23;

  --accent: #A78BFA;
  --accent-2: #EC4899;
  --accent-3: #22d3ee;
  --accent-ink: #ffffff;
  --accent-soft: rgba(167,139,250,0.16);
  --accent-3-soft: rgba(34,211,238,0.14);

  --good: #34d399;
  --good-soft: rgba(52,211,153,0.16);
  --warn: #fbbf24;
  --warn-soft: rgba(251,191,36,0.16);
  --bad: #f87171;
  --bad-soft: rgba(248,113,113,0.16);

  --shadow-sm: 0 1px 2px rgba(0,0,0,0.3);
  --shadow-md: 0 8px 24px -8px rgba(0,0,0,0.5), 0 2px 6px -2px rgba(0,0,0,0.3);
  --shadow-lg: 0 20px 45px -12px rgba(0,0,0,0.6), 0 6px 16px -6px rgba(0,0,0,0.35);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg-grad), var(--bg);
  background-attachment: fixed;
  color: var(--ink);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  font-size: 14.5px;
  line-height: 1.5;
  transition: background-color 0.2s ease, color 0.2s ease;
}

a { color: var(--accent); text-decoration: none; font-weight: 600; }
a:hover { color: var(--accent-2); }

/* ---- Topbar ---------------------------------------------------------- */

header.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 28px; border-bottom: 1px solid var(--border-soft);
  background: color-mix(in srgb, var(--panel) 82%, transparent);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  position: sticky; top: 0; z-index: 20;
}
header.topbar h1 { font-size: 16.5px; margin: 0; font-weight: 800; letter-spacing: -0.01em; display: flex; align-items: center; gap: 10px; }
header.topbar .sub { color: var(--muted); font-size: 12.5px; margin-top: 3px; }
header.topbar .topbar-right { display: flex; align-items: center; gap: 8px; }

.logo-icon { width: 30px; height: 30px; min-width: 30px; border-radius: 9px; box-shadow: 0 4px 14px -2px rgba(124,58,237,0.5); display: block; }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; min-width: 36px; height: 36px; padding: 0; border-radius: 999px;
  font-size: 14px; font-weight: 700; color: var(--ink);
}
.icon-btn svg { width: 17px; height: 17px; display: block; }

/* ---- Layout ------------------------------------------------------------ */

.container { max-width: 1080px; margin: 0 auto; padding: 32px 24px 80px; }

.panel {
  background: var(--panel);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
  padding: 26px 28px;
  margin-bottom: 22px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.25s ease, background-color 0.2s ease, border-color 0.2s ease;
  position: relative;
}
.panel:hover { box-shadow: var(--shadow-md); }
.panel h2 {
  margin: 0 0 4px; font-size: 15.5px; font-weight: 800; letter-spacing: -0.01em;
  display: flex; align-items: center; gap: 10px;
}
.panel .hint { color: var(--muted); font-size: 12.8px; margin-bottom: 16px; }

.row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }

/* ---- Forms ------------------------------------------------------------ */

label { display: block; font-size: 11.5px; color: var(--muted); margin-bottom: 6px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.055em; }

input[type=text], input[type=number], input[type=password], input[type=email], textarea, select {
  width: 100%; padding: 11px 13px; border-radius: 10px;
  border: 1.5px solid var(--border); background: var(--panel-soft); color: var(--ink);
  font-size: 14px; font-family: inherit; transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
input[type=text]:hover, input[type=number]:hover, input[type=email]:hover, input[type=password]:hover, textarea:hover { border-color: color-mix(in srgb, var(--border) 40%, var(--ink)); }
input[type=text]:focus, input[type=number]:focus, input[type=password]:focus, input[type=email]:focus, textarea:focus, select:focus {
  outline: none; border-color: var(--accent); background: var(--panel);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
/* ---- File inputs: themed "choose file" button + bobbing icon ------------- */

input[type=file] { font-size: 12.5px; color: var(--muted); }
input[type=file]::file-selector-button {
  margin-right: 10px; padding: 8px 16px 8px 30px; border-radius: 10px;
  border: 1.5px solid var(--accent); background: var(--accent-soft); color: var(--accent);
  font-weight: 700; font-size: 12.5px; font-family: inherit; cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
input[type=file]:hover::file-selector-button { background: var(--accent); color: #fff; transform: translateY(-1px); }

.file-field { position: relative; display: inline-block; }
.file-field-icon {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: var(--accent); pointer-events: none; z-index: 1;
  transition: color 0.15s ease;
}
.file-field-icon svg { width: 100%; height: 100%; display: block; }
.file-field:hover .file-field-icon { color: #fff; animation: file-icon-bob 0.7s ease infinite; }
@keyframes file-icon-bob {
  0%, 100% { transform: translateY(-50%); }
  50% { transform: translateY(-70%); }
}

textarea { resize: vertical; min-height: 68px; }
.field { margin-bottom: 14px; }

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

button {
  cursor: pointer; border: 1.5px solid var(--border); background: var(--panel);
  color: var(--ink); border-radius: 10px; padding: 9px 17px;
  font-size: 13px; font-weight: 700; font-family: inherit;
  transition: transform 0.12s ease, box-shadow 0.15s ease, border-color 0.15s ease, background 0.15s ease;
  box-shadow: var(--shadow-sm);
}
button:hover { border-color: color-mix(in srgb, var(--border) 30%, var(--ink)); transform: translateY(-1px); box-shadow: var(--shadow-md); }
button:active { transform: translateY(0); }
button:disabled { opacity: 0.5; cursor: default; transform: none; box-shadow: none; }

button.primary {
  background: linear-gradient(95deg, #7C3AED, #EC4899);
  border-color: transparent; color: #fff;
  box-shadow: 0 8px 22px -6px rgba(124,58,237,0.6);
}
button.primary:hover { filter: brightness(1.08); box-shadow: 0 10px 22px -4px rgba(124,58,237,0.6); }

button.accent3 {
  background: linear-gradient(135deg, var(--accent-3), var(--accent));
  border-color: transparent; color: #fff;
  box-shadow: 0 6px 16px -4px rgba(6,182,212,0.45);
}

button.danger { color: var(--bad); }
button.danger:hover { border-color: var(--bad); background: var(--bad-soft); }
button.small { padding: 6px 12px; font-size: 12px; border-radius: 8px; }

/* ---- Tour list cards ---------------------------------------------------- */

.tour-card {
  display: flex; justify-content: space-between; align-items: center;
  padding: 16px 20px; border: 1px solid var(--border-soft); border-radius: 14px;
  margin-bottom: 10px; background: var(--panel);
  box-shadow: var(--shadow-sm); transition: box-shadow 0.2s ease, transform 0.2s ease;
}
.tour-card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
.tour-card .name { font-weight: 700; font-size: 14.5px; }
.tour-card .meta { color: var(--muted); font-size: 12.5px; margin-top: 2px; }

/* ---- Places -------------------------------------------------------------- */

.place {
  border: 1px solid var(--border-soft); border-radius: 14px; padding: 18px;
  margin-bottom: 14px; background: var(--panel-soft);
}
.place-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.place-head .idx {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #fff; font-size: 11.5px; font-weight: 800; margin-right: 9px;
  box-shadow: 0 3px 8px -2px rgba(124,58,237,0.5);
}
.thumb { width: 88px; height: 62px; object-fit: cover; border-radius: 8px; background: var(--border-soft); box-shadow: var(--shadow-sm); }

.toggle-row { display: flex; align-items: center; gap: 10px; margin: 14px 0; cursor: pointer; user-select: none; }
.toggle-row input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle-switch {
  position: relative; width: 38px; height: 22px; border-radius: 999px; flex-shrink: 0;
  background: var(--border); transition: background 0.15s ease;
}
.toggle-switch::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px;
  border-radius: 50%; background: #fff; box-shadow: var(--shadow-sm); transition: transform 0.15s ease;
}
.toggle-row input:checked + .toggle-switch { background: linear-gradient(95deg, #7C3AED, #EC4899); }
.toggle-row input:checked + .toggle-switch::after { transform: translateX(16px); }
.toggle-label { font-size: 12.5px; font-weight: 600; color: var(--ink); text-transform: none; letter-spacing: 0; }
.narr-block { border-top: 1px dashed var(--border); margin-top: 14px; padding-top: 12px; }
.narr-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.narr-lang-label { font-size: 11px; font-weight: 800; color: var(--muted); margin-bottom: 5px; letter-spacing: 0.04em; }
audio { width: 100%; height: 32px; margin-top: 7px; border-radius: 8px; }

/* ---- Status pills / badges ------------------------------------------------ */

.status-pill { display: inline-block; font-size: 10.5px; padding: 3px 9px; border-radius: 999px; font-weight: 800; letter-spacing: 0.02em; }
.status-pill.ok { background: var(--good-soft); color: var(--good); }
.status-pill.no { background: var(--border-soft); color: var(--muted-2); }

.badge { font-size: 10.5px; padding: 3px 10px; border-radius: 999px; background: var(--accent-soft); color: var(--accent); font-weight: 800; letter-spacing: 0.02em; }
.badge.cyan { background: var(--accent-3-soft); color: var(--accent-3); }

/* ---- Travel mode per leg -------------------------------------------------- */
/* How you reach a stop — walk, car, ferry. Sits with that stop's route
   narration, because both describe the journey there rather than the place. */

.travel-mode-field { margin-bottom: 14px; }
.mode-chips { display: flex; gap: 8px; flex-wrap: wrap; }
.mode-chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 14px; border-radius: 999px;
  border: 1.5px solid var(--border); background: var(--panel-soft);
  font-size: 12.5px; font-weight: 700; color: var(--muted);
}
.mode-chip:hover { border-color: color-mix(in srgb, var(--border) 30%, var(--ink)); }
.mode-chip.active {
  border-color: var(--accent); color: var(--ink);
  background: var(--accent-soft); box-shadow: 0 0 0 3px var(--accent-soft);
}
.mode-chip-icon { font-size: 15px; line-height: 1; }

/* ---- Bulk import of places ------------------------------------------------ */
/* Sits above the list of places as an alternative to filling that list in by
   hand, so it is styled as its own inset panel rather than as more form. */

.import-box {
  border: 1px dashed var(--border); border-radius: 14px;
  padding: 16px 18px; margin-bottom: 18px; background: var(--panel-soft);
}
.import-head { display: flex; align-items: center; gap: 8px; font-size: 13.5px; }
.import-head svg { width: 16px; height: 16px; color: var(--accent); }
.import-box .hint { margin: 6px 0 0; }
.import-box .toggle-row { margin-top: 10px; }
.import-report {
  margin-top: 12px; padding: 12px 14px; border-radius: 10px;
  background: var(--panel); border: 1px solid var(--border-soft);
  font-size: 12.5px; line-height: 1.55; color: var(--muted);
}
.import-report strong { color: var(--ink); }
.import-fields { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 11.5px; color: var(--muted-2); }
.import-report ul { margin: 6px 0 0; padding-left: 18px; }
.import-report li { margin: 2px 0; }

/* ---- Misc sections -------------------------------------------------------- */

.toolbar { display: flex; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
/* The account's remaining video allowance, beside the render buttons. */
.allowance {
  display: inline-block; margin-bottom: 14px;
  padding: 6px 14px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent);
  font-size: 12.5px; font-weight: 700;
}
.allowance.spent { background: var(--bad-soft); color: var(--bad); }
.allowance[hidden] { display: none; }

/* ---- Accounts (superadmin panel) ------------------------------------------- */

.limit-row { display: flex; align-items: center; gap: 16px; }
.limit-row input[type=number] { max-width: 130px; }

.user-row {
  display: grid; grid-template-columns: 1fr auto auto; gap: 18px; align-items: center;
  padding: 14px 16px; border: 1px solid var(--border-soft); border-radius: 12px;
  margin-bottom: 8px; background: var(--panel-soft);
}
.user-row.suspended { opacity: 0.6; }
.user-main { min-width: 0; }
.user-email { font-weight: 700; font-size: 14px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.user-meta { font-size: 12px; color: var(--muted); margin-top: 3px; }
.usage-spent { color: var(--bad); font-weight: 700; }
.user-limit { display: flex; align-items: center; gap: 12px; }
.user-limit input[type=number] { width: 92px; }
.user-limit input:disabled { opacity: 0.45; }
.user-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }

@media (max-width: 860px) {
  .user-row { grid-template-columns: 1fr; gap: 12px; }
  .user-actions { justify-content: flex-start; }
}

/* ---- Secret fields (API keys) ---------------------------------------------- */
/* The stored key is in the field, masked, with an eye to read it when needed. */

.secret-field { position: relative; flex: 1; min-width: 220px; }
.secret-field input { padding-right: 42px; font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 13px; }
.secret-eye {
  position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
  width: 30px; height: 30px; padding: 0; border: none; background: transparent;
  box-shadow: none; color: var(--muted-2);
  display: flex; align-items: center; justify-content: center;
}
.secret-eye:hover { background: var(--accent-soft); color: var(--accent); transform: translateY(-50%); box-shadow: none; }
.secret-eye.on { color: var(--accent); }
.secret-eye svg { width: 16px; height: 16px; display: block; }

/* ---- Export language tabs -------------------------------------------------- */
/* One video per language, so the tabs pick which one to show rather than
   filtering a list. The dot marks a language that has a video ready. */

.lang-tabs { display: flex; gap: 6px; margin: 4px 0 12px; }
.lang-tab {
  padding: 7px 16px; border-radius: 999px;
  border: 1.5px solid var(--border); background: var(--panel-soft);
  font-size: 12.5px; font-weight: 700; color: var(--muted);
  display: inline-flex; align-items: center; gap: 7px;
}
.lang-tab:hover { border-color: color-mix(in srgb, var(--border) 30%, var(--ink)); }
.lang-tab.active {
  border-color: var(--accent); color: var(--ink);
  background: var(--accent-soft); box-shadow: 0 0 0 3px var(--accent-soft);
}
.lang-tab.has-export::after {
  content: ''; width: 7px; height: 7px; border-radius: 50%;
  background: var(--good); box-shadow: 0 0 0 2px var(--good-soft);
}

.export-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 12px 16px; border: 1px solid var(--border-soft); border-radius: 12px;
  margin-bottom: 8px; background: var(--panel-soft);
}

/* Toasts live in the top-right corner. They stack in a column rather than each
   being placed at the same fixed spot: staging a few files in a row used to
   pile them on top of one another, showing only the last. Above dialogs, so a
   message about what just happened is not hidden by one. */
.toast-stack {
  position: fixed; top: 16px; right: 16px; z-index: 100;
  display: flex; flex-direction: column; align-items: flex-end; gap: 9px;
  max-width: min(420px, calc(100vw - 32px));
  pointer-events: none;                 /* never blocks the controls beneath */
}
/* A toast has to be legible over whatever it lands on, so it does not reuse
   --panel: on the dark theme that is #111117 against a #09090B page, which is
   almost no step at all. It gets its own surface, lifted clearly off the page
   in both themes, and says which kind of news it is with a filled icon and a
   coloured edge rather than by flooding the whole shape with colour. */
.toast {
  --toast-bg: #ffffff;
  --toast-border: rgba(20,22,31,0.10);
  --toast-ink: #14151f;
  --toast-shadow: 0 18px 42px -12px rgba(20,22,31,0.30), 0 4px 12px -4px rgba(20,22,31,0.14);
  --toast-accent: var(--good);

  display: flex; align-items: flex-start; gap: 11px;
  background: var(--toast-bg); color: var(--toast-ink);
  border: 1px solid var(--toast-border); border-left: 4px solid var(--toast-accent);
  padding: 13px 17px 13px 14px; border-radius: 12px;
  font-size: 13.5px; font-weight: 600; line-height: 1.45; letter-spacing: -0.005em;
  max-width: 100%; box-shadow: var(--toast-shadow); pointer-events: auto;
  animation: toast-in 0.22s cubic-bezier(.22,.85,.34,1);
}
:root[data-theme="dark"] .toast {
  --toast-bg: #1e1e28;
  --toast-border: rgba(255,255,255,0.13);
  --toast-ink: #f4f4f8;
  --toast-shadow: 0 18px 42px -10px rgba(0,0,0,0.72), 0 4px 14px -4px rgba(0,0,0,0.55);
}
.toast.err { --toast-accent: var(--bad); }

/* Filled, so the state is readable at a glance and at this size. */
.toast-icon {
  flex: 0 0 auto; width: 19px; height: 19px; margin-top: 1px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--toast-accent); color: #fff;
}
.toast-icon svg { width: 11px; height: 11px; display: block; }
.toast-msg { min-width: 0; word-break: break-word; }
@keyframes toast-in { from { opacity: 0; transform: translateX(14px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } }

/* ---- Render jobs: one progress bar each ----------------------------------- */
.job-line { font-size: 12.5px; color: var(--muted); padding: 9px 0; }
.job-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.job-head .job-pct { margin-left: auto; }
.job-cancel { flex: none; padding: 3px 10px; font-size: 11.5px; }
.job-name { font-weight: 800; color: var(--text); letter-spacing: 0.02em; }
.job-pct { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.progress {
  height: 7px; margin: 6px 0 5px; border-radius: 99px; overflow: hidden;
  background: color-mix(in srgb, var(--border) 70%, transparent);
}
.progress-fill {
  height: 100%; border-radius: 99px; background: linear-gradient(90deg, #3b82f6, #10b981);
  /* The bar is repainted once a second from the server's own percentage, so it
     is eased across that gap rather than stepping. */
  transition: width 900ms linear;
}
.job-line.is-done .progress-fill { background: #10b981; }
.job-line.is-error .progress-fill { background: #ef4444; }
.job-line.is-cancelled .progress-fill { background: var(--muted); }
.job-line.is-cancelled .job-phase, .job-line.is-cancelled .job-name { opacity: 0.6; }
.job-phase { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 11.5px; }
.job-line.is-error .job-phase { color: #ef4444; }

/* ---- Export quality picker ------------------------------------------------- */
.quality-list { display: grid; gap: 8px; margin-top: 14px; }
.quality-option {
  /* radio · name · dimensions · note — one row, note pushed to the right.
     Also undoes the global uppercase `label` styling: these rows are options
     to read, not field captions. */
  display: grid; grid-template-columns: auto auto auto 1fr; align-items: baseline; gap: 10px;
  padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  cursor: pointer; transition: border-color 150ms ease, background 150ms ease;
  margin-bottom: 0; text-transform: none; letter-spacing: 0; font-size: 13px;
}
.quality-option:hover { border-color: var(--border-soft); }
.quality-option.active { border-color: #3b82f6; background: color-mix(in srgb, #3b82f6 10%, transparent); }
.quality-option input { margin: 0; align-self: center; }
.quality-name { font-weight: 800; color: var(--ink); font-size: 14px; }
.quality-dims { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12px; color: var(--muted); }
.quality-note { font-size: 12px; color: var(--muted); text-align: right; }
.modal-narrow { max-width: 520px; }
.empty { color: var(--muted-2); font-size: 13.5px; padding: 26px 0; text-align: center; }

.mapboxgl-ctrl-logo { opacity: 0.6; }

/* ---- Sticky stage timeline ------------------------------------------------- */

/* Sits directly under the topbar, whose height is measured on the page rather
   than guessed at here — a tour name long enough to wrap used to push the
   topbar taller than this offset and leave the two overlapping. */
.stage-timeline {
  position: sticky; top: var(--topbar-h, 65px); z-index: 19;
  padding: 16px 24px 12px;
  background: color-mix(in srgb, var(--panel) 90%, transparent);
  backdrop-filter: blur(14px) saturate(1.4); -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border-bottom: 1px solid var(--border-soft);
}
/* Scrolling to a section leaves room for both sticky bars plus a gap, so the
   section's heading comes to rest just below the timeline instead of behind
   it. --sticky-h is measured on the page; the fallback is only for the moment
   before the first measurement. */
[id^="anchor-"] { scroll-margin-top: calc(var(--sticky-h, 130px) + 18px); }

.stage-track {
  position: relative; max-width: 880px; margin: 0 auto;
  display: grid; grid-template-columns: repeat(6, 1fr);
}
.stage-track::before {
  content: ''; position: absolute; top: 23px; left: 8.33%; right: 8.33%; height: 2px;
  background: linear-gradient(90deg, #ec4899, #a855f7, #6366f1, #3b82f6, #06b6d4, #10b981);
  opacity: 0.55; z-index: 0;
}
.stage-item {
  position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
  background: none; border: none; box-shadow: none; padding: 4px; border-radius: 10px;
}
/* No hover background. A filled block behind the whole item read as a card
   appearing under the cursor — a surface that is not really there. The node and
   its label answer the pointer instead, which is all a button needs to say. */
.stage-item:hover { transform: none; box-shadow: none; background: none; }
.stage-item:not(.active):hover .stage-node {
  background: color-mix(in srgb, var(--stage-color) 13%, var(--panel));
  box-shadow: 0 5px 14px -4px color-mix(in srgb, var(--stage-color) 60%, transparent);
}
.stage-item:hover .stage-label { color: var(--stage-color); }
.stage-node {
  width: 46px; height: 46px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  font-size: 18px; background: var(--panel); border: 2.5px solid var(--stage-color); color: var(--stage-color);
  box-shadow: 0 2px 8px -2px rgba(20,22,31,0.15); transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.stage-item.active .stage-node { background: var(--stage-color); color: #fff; transform: scale(1.08); box-shadow: 0 6px 16px -4px var(--stage-color); }
.stage-label { font-size: 12.5px; font-weight: 800; color: var(--ink); margin-top: 3px; transition: color 0.15s ease; }
.stage-sub { font-size: 10.3px; color: var(--muted); }
@media (max-width: 640px) { .stage-sub { display: none; } }

/* ---- Map style chips ------------------------------------------------------ */

.style-chips { display: flex; flex-wrap: nowrap; gap: 8px; overflow-x: auto; padding-bottom: 2px; }
.style-chip {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 4px; flex: 0 0 auto;
  border: none; background: transparent; box-shadow: none;
}
.style-chip:hover { transform: none; box-shadow: none; }
.chip-swatch {
  width: 76px; height: 64px; border-radius: 10px; display: block;
  background-color: var(--border-soft); background-size: cover; background-position: center;
  box-shadow: 0 3px 10px -3px rgba(20,22,31,0.25);
  border: 2px solid var(--border);
}
.style-chip:hover .chip-swatch { border-color: color-mix(in srgb, var(--border) 30%, var(--ink)); }
.style-chip.active .chip-swatch { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.chip-label { font-size: 11px; font-weight: 600; color: var(--muted); text-align: center; white-space: nowrap; }
.style-chip.active .chip-label { color: var(--ink); font-weight: 700; }

/* ---- Color pickers (route / marker colors) -------------------------------- */

.color-swatch {
  width: 44px; height: 40px; padding: 2px; border-radius: 10px; cursor: pointer;
  border: 1.5px solid var(--border); background: var(--panel-soft);
}
.color-swatch::-webkit-color-swatch-wrapper { padding: 2px; }
.color-swatch::-webkit-color-swatch { border-radius: 7px; border: none; }
.color-hex { max-width: 110px; text-transform: uppercase; font-family: ui-monospace, "SF Mono", Menlo, monospace; }

/* ---- Marker style chips ---------------------------------------------------- */

.marker-preview {
  position: relative;
  width: 76px; height: 64px; border-radius: 10px; display: flex; align-items: center; justify-content: center;
  background: var(--panel-soft); border: 2px solid var(--border); box-shadow: 0 3px 10px -3px rgba(20,22,31,0.25);
}
.style-chip:hover .marker-preview { border-color: color-mix(in srgb, var(--border) 30%, var(--ink)); }
.style-chip.active .marker-preview { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.marker-preview span { display: block; border-radius: 50%; background: var(--mk-color, #3b82f6); }
.marker-preview-dot span { width: 20px; height: 20px; border: 2px solid #111; }
.marker-preview-ring span { width: 24px; height: 24px; background: color-mix(in srgb, var(--mk-color, #3b82f6) 25%, transparent); border: 3px solid var(--mk-color, #3b82f6); }
.marker-preview-bold span { width: 28px; height: 28px; border: 3px solid #fff; box-shadow: 0 2px 6px rgba(0,0,0,0.35); }
.marker-preview-glow span:last-child, .marker-preview-halo span:last-child {
  position: relative; z-index: 1; width: 16px; height: 16px; border: 2px solid #111;
}
.marker-preview-glow .glow {
  position: absolute; width: 42px; height: 42px; border-radius: 50%;
  background: var(--mk-color, #3b82f6); opacity: 0.5; filter: blur(7px);
}
.marker-preview-halo .halo {
  position: absolute; width: 38px; height: 38px; border-radius: 50%;
  background: color-mix(in srgb, var(--mk-color, #3b82f6) 30%, transparent);
}
.marker-preview-pin .pin-shape {
  width: 26px; height: 26px; border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
  background: var(--mk-color, #3b82f6); border: 2px solid #fff; box-shadow: 0 2px 6px rgba(0,0,0,0.3);
  position: relative; margin-top: -6px;
}
.marker-preview-pin .pin-shape::after {
  content: ''; position: absolute; top: 50%; left: 50%; width: 9px; height: 9px; border-radius: 50%;
  background: #fff; transform: translate(-50%, -50%) rotate(45deg);
}


/* ---- Floating actions ------------------------------------------------------ */
/* One stack, so the buttons align to each other instead of each being nailed to
   its own hand-picked offset from the bottom of the window — which drifted the
   moment a label wrapped or a button was added. */

.fab-stack {
  position: fixed; right: 28px; bottom: 28px; z-index: 25;
  display: flex; flex-direction: column; align-items: stretch; gap: 10px;
}

.fab {
  display: flex; align-items: center; justify-content: flex-start; gap: 9px;
  padding: 12px 20px; border-radius: 999px;
  font-size: 13.5px; font-weight: 700; white-space: nowrap;
  transition: transform 0.14s ease, box-shadow 0.18s ease, border-color 0.18s ease, filter 0.18s ease;
}
.fab svg { width: 18px; height: 18px; flex-shrink: 0; }
.fab:hover { transform: translateY(-2px); }

.fab-primary {
  border: none; background: linear-gradient(95deg, #7C3AED, #EC4899); color: #fff;
  box-shadow: 0 10px 28px -6px rgba(124,58,237,0.55);
  padding: 13px 22px;
}
.fab-primary:hover { filter: brightness(1.08); box-shadow: 0 12px 28px -4px rgba(124,58,237,0.6); }

.fab-ghost {
  background: var(--panel); color: var(--accent); border: 1.5px solid var(--border-soft);
  box-shadow: var(--shadow-lg);
}
.fab-ghost:hover { border-color: var(--accent); box-shadow: var(--shadow-lg); }
.fab-ghost.open { border-color: var(--accent); background: var(--accent-soft); }

/* ---- Video preview: one button, languages on click ------------------------- */

.fab-with-menu { position: relative; display: flex; }
.fab-with-menu .fab { width: 100%; }

.fab-menu {
  position: absolute; right: 0; bottom: calc(100% + 10px);
  min-width: 250px; padding: 6px;
  background: var(--panel); border: 1px solid var(--border-soft);
  border-radius: 14px; box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; gap: 2px;
  animation: fab-menu-in 0.16s ease;
}
.fab-menu[hidden] { display: none; }
@keyframes fab-menu-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

.fab-menu-item {
  display: flex; align-items: center; gap: 11px; width: 100%;
  padding: 10px 12px; border-radius: 10px;
  border: none; background: transparent; box-shadow: none;
  text-align: left; font-family: inherit;
}
.fab-menu-item:hover { background: var(--accent-soft); transform: none; box-shadow: none; }
.fab-menu-item .mi-icon { font-size: 17px; line-height: 1; flex-shrink: 0; }
.fab-menu-item .mi-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.fab-menu-item .mi-name { font-size: 13.5px; font-weight: 700; color: var(--ink); }
.fab-menu-item .mi-sub  { font-size: 11.5px; font-weight: 500; color: var(--muted); }

#route-preview-map { width: 100%; height: 480px; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--border); }

/* ---- Map picker modal ------------------------------------------------------ */

.modal-overlay {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  background: rgba(5,6,10,0.6); backdrop-filter: blur(4px); padding: 20px;
}
.modal-overlay[hidden] { display: none; }
.modal-box {
  width: 100%; max-width: 680px; background: var(--panel); border: 1px solid var(--border-soft);
  border-radius: var(--radius); padding: 20px; box-shadow: var(--shadow-lg);
  /* Never taller than the space it has; long dialogs scroll inside themselves
     rather than running off the bottom of the screen. */
  max-height: calc(100vh - 40px); overflow-y: auto;
  animation: modal-in 0.2s cubic-bezier(.22,.85,.34,1);
}
@keyframes modal-in {
  from { opacity: 0; transform: translateY(10px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .modal-box { animation: none; } }

.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
#modal-map { width: 100%; height: 420px; border-radius: var(--radius-sm); overflow: hidden; border: 1px solid var(--border); }

/* ---- A filled media slot, and the preview it opens ----------------------- */
/* Once a stop holds a photo or a clip, its file input is put behind Replace and
   the slot names what is stored. The name is the button that opens it. */
.media-slot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* A file chosen but not yet uploaded. It is shown exactly like a saved one —
   it is what the stop will hold — with the badge carrying the difference. */
.pending-badge {
  display: inline-flex; align-items: center; padding: 4px 9px; border-radius: 999px;
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase;
  background: color-mix(in srgb, var(--warn) 18%, transparent);
  color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
}
.media-slot.is-pending .media-slot-name { border-style: dashed; border-color: color-mix(in srgb, var(--warn) 55%, transparent); }
.media-slot-name {
  display: inline-flex; align-items: center; gap: 7px; min-width: 0; max-width: 100%;
  padding: 8px 12px; border-radius: 10px; font-size: 12.5px; font-weight: 600;
  border: 1.5px solid var(--border); background: var(--panel); color: var(--ink);
  box-shadow: none;
}
.media-slot-name svg { width: 15px; height: 15px; flex: 0 0 auto; color: var(--accent); }
/* The name is the part that must survive a narrow column, so it is the part
   that truncates — the icon and the buttons beside it stay put. */
.media-slot-name span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.media-slot-name:hover { border-color: var(--accent); color: var(--accent); }
.media-slot-name:hover svg { color: var(--accent); }

/* A label wrapping the file input: the whole chip opens the picker, and no
   script is needed to forward the click to a hidden input. */
.media-slot-replace {
  display: inline-flex; align-items: center; cursor: pointer; margin: 0;
  padding: 8px 13px; border-radius: 10px; font-size: 12px; font-weight: 700;
  border: 1.5px solid var(--accent); background: var(--accent-soft); color: var(--accent);
  text-transform: none; letter-spacing: 0;
  transition: background 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.media-slot-replace:hover { background: var(--accent); color: #fff; transform: translateY(-1px); }
.media-slot-replace input[type=file] { display: none; }

.media-preview-body {
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-soft, rgba(0,0,0,0.25)); border: 1px solid var(--border);
  border-radius: var(--radius-sm); overflow: hidden; min-height: 180px;
}
/* Capped against the viewport, not just the dialog, so a tall portrait photo
   cannot push its own controls off the bottom of the screen. */
.media-preview-body img,
.media-preview-body video { max-width: 100%; max-height: 68vh; display: block; }

hr { border: none; border-top: 1px dashed var(--border); margin: 18px 0; }

/* ---- Login page ─ solid text column + artwork column + login panel -------- */
/* Layout mirrors the approved design: the copy sits on a SOLID background
   column (never on top of the artwork, so nothing ever collides), the
   artwork occupies the middle, and the login card sits in its own panel. */

.auth-body {
  margin: 0; min-height: 100vh; display: flex; flex-direction: column; position: relative;
  background: #09090B; color: #fff;
  font-family: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, sans-serif;
}
:root[data-theme="light"] .auth-body { background: #ffffff; color: #14151f; }

/* padding-top is the header's room. The artwork is absolutely positioned, so
   it is laid out against the padding box and still reaches the top edge. */
.auth-shell { flex: 1; display: flex; min-height: 0; position: relative; padding-top: 70px; }

/* ── Header ───────────────────────────────────────────────────────────────
   Floats over the artwork rather than banding it, so the picture runs to the
   top edge of the page. Being lifted out of the flow, it reserves its room
   through the shell's padding below — otherwise the centred copy would ride up
   underneath it. Its left padding matches the copy column's, lining the mark
   up with the headline. */
.auth-header {
  position: absolute; top: 0; left: 0; right: 0; z-index: 10;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 17px 52px; background: transparent;
}
/* Standing on the artwork, the brand carries its own legibility shadow — the
   gradient word by drop-shadow, which follows the glyphs, since a text-shadow
   would show through its transparent fill. */
.auth-header .hero-brand-name { text-shadow: 0 2px 14px rgba(0,0,0,0.85), 0 1px 4px rgba(0,0,0,0.7); }
.auth-header .hero-brand-by { text-shadow: 0 1px 10px rgba(0,0,0,0.9), 0 1px 3px rgba(0,0,0,0.8); }
.auth-header .grad { text-shadow: none; filter: drop-shadow(0 2px 10px rgba(0,0,0,0.95)) drop-shadow(0 1px 3px rgba(0,0,0,0.9)); }
:root[data-theme="light"] .auth-header .hero-brand-name { text-shadow: 0 2px 14px rgba(255,255,255,0.95), 0 1px 4px rgba(255,255,255,0.9); }
:root[data-theme="light"] .auth-header .hero-brand-by { text-shadow: 0 1px 10px rgba(255,255,255,1), 0 1px 3px rgba(255,255,255,0.95); }
:root[data-theme="light"] .auth-header .grad { filter: drop-shadow(0 2px 10px rgba(255,255,255,1)) drop-shadow(0 1px 3px rgba(255,255,255,1)); }

/* ── Hero ─────────────────────────────────────────────────────────────── */
.auth-hero { flex: 1; display: flex; min-width: 0; position: relative; }

.hero-copy {
  width: 510px; flex-shrink: 0; padding: 42px 26px 42px 52px;
  display: flex; flex-direction: column; justify-content: center; gap: 22px;
  position: relative; z-index: 2; background: transparent;
}
/* Text sits directly on the artwork, so it carries its own legibility
   shadow rather than a backing panel. (The brand is exempt — it lives on the
   solid header strip now.) */
.hero-copy .hero-title { text-shadow: 0 2px 18px rgba(0,0,0,0.85), 0 1px 4px rgba(0,0,0,0.7); }
.hero-copy .hero-desc,
.hero-copy .steps-label,
.hero-copy .tl-title,
.hero-copy .tl-desc { text-shadow: 0 1px 10px rgba(0,0,0,0.9), 0 1px 3px rgba(0,0,0,0.8); }
:root[data-theme="light"] .hero-copy .hero-title { text-shadow: 0 2px 18px rgba(255,255,255,0.95), 0 1px 4px rgba(255,255,255,0.9); }
:root[data-theme="light"] .hero-copy .hero-desc,
:root[data-theme="light"] .hero-copy .steps-label,
:root[data-theme="light"] .hero-copy .tl-title,
:root[data-theme="light"] .hero-copy .tl-desc { text-shadow: 0 1px 10px rgba(255,255,255,1), 0 1px 3px rgba(255,255,255,0.95); }
/* Gradient text is painted via background-clip with a transparent fill, so a
   text-shadow shows THROUGH the glyphs and muddies them. Use drop-shadow,
   which follows the glyph alpha instead. */
.hero-copy .grad { text-shadow: none; filter: drop-shadow(0 2px 12px rgba(0,0,0,0.95)) drop-shadow(0 1px 3px rgba(0,0,0,0.9)); }
:root[data-theme="light"] .hero-copy .grad { filter: drop-shadow(0 2px 10px rgba(255,255,255,1)) drop-shadow(0 1px 3px rgba(255,255,255,1)); }

/* Sized for the header strip: large enough to be the mark of the page, small
   enough that the strip stays a strip and the artwork keeps the room. */
.hero-brand { display: flex; align-items: center; gap: 11px; min-width: 0; }
.hero-logo { width: 36px; height: 36px; border-radius: 10px; display: block; flex-shrink: 0; box-shadow: 0 6px 18px -4px rgba(124,58,237,0.55); }
.hero-brand-name { font-size: 19px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.15; }
.hero-brand-by { font-size: 9.5px; color: #8b8b96; margin-top: 2px; }
:root[data-theme="light"] .hero-brand-by { color: #6f7080; }
.grad { background: linear-gradient(100deg, #A78BFA, #EC4899); -webkit-background-clip: text; background-clip: text; color: transparent; }

.hero-title { font-size: 33px; line-height: 1.22; font-weight: 800; letter-spacing: -0.025em; margin: 0; }
.hero-desc { font-size: 12.8px; line-height: 1.85; color: #a1a1aa; margin: 0; }
:root[data-theme="light"] .hero-desc { color: #5b5c6b; }

/* ── "How it works" timeline ──────────────────────────────────────────────
   The steps spell out the same beats as the description above them, in the
   same order. A step is a node (icon chip) plus its copy, threaded onto one
   continuous rail. Order is carried by the rail rather than by numbering it:
   a lit line draws down the rail on a loop and each step brightens as the
   line reaches it, so the eye is walked through the sequence. */
.hero-steps { display: flex; flex-direction: column; gap: 14px; }
.steps-label {
  font-size: 10px; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: #A78BFA; display: flex; align-items: center; gap: 9px;
}
.steps-label::after {
  content: ''; height: 1px; flex: 1;
  background: linear-gradient(90deg, rgba(167,139,250,0.55), rgba(236,72,153,0.14), transparent);
}
:root[data-theme="light"] .steps-label { color: #7C3AED; }

/* One rail threading every node, starting at the centre of the first. It ends
   by fading out rather than at a measured point: the last step is as tall as
   its copy, not its node, so any fixed end would either overshoot the last
   node or fall short of it as soon as a line of copy wraps.
   --rail-top is half a node's height. */
.timeline {
  list-style: none; margin: 0; padding: 0; position: relative;
  --rail-x: 16px; --rail-top: 17px;
  /* One pass over the five steps: 2s of the cycle each. Every delay below is
     derived from that, so the pulse and the step it lights arrive together. */
  --cycle: 10s;
}
/* The unlit rail, drawn as the gaps between one node and the next: running it
   through the chips would show a line behind every icon, and stopping it under
   the last node needs no measuring this way. */
.tl-step:not(:last-child)::before {
  content: ''; position: absolute; left: var(--rail-x); width: 2px; border-radius: 2px;
  top: calc(var(--rail-top) * 2 + 2px); bottom: -2px;
  background: rgba(167,139,250,0.26);
}
:root[data-theme="light"] .tl-step:not(:last-child)::before { background: rgba(124,58,237,0.2); }

/* The pulse running down the rail. `top` is animated in percentages so the
   travel spans the list whatever the copy does to its height, and the pulse is
   centred on that point so it meets each node head-on. It sits behind the
   chips, so a node reads as lighting up from within as the pulse passes. */
.timeline::after {
  content: ''; position: absolute; left: var(--rail-x); width: 2px; border-radius: 2px;
  height: 44px; margin-top: -22px; top: var(--rail-top); z-index: 0;
  background: linear-gradient(180deg, rgba(167,139,250,0) 0%, #A78BFA 38%, #EC4899 70%, rgba(236,72,153,0) 100%);
  box-shadow: 0 0 14px rgba(167,139,250,0.7);
  animation: tl-pulse var(--cycle) linear 1.2s infinite;
}
/* Travels over the first 80% of the cycle — one step every 2s — then waits out
   the last 2s so the run reads as finished before it begins again. */
@keyframes tl-pulse {
  0%   { top: var(--rail-top); opacity: 0; }
  5%   { opacity: 1; }
  74%  { opacity: 1; }
  80%  { top: calc(100% - var(--rail-top)); opacity: 0; }
  100% { top: calc(100% - var(--rail-top)); opacity: 0; }
}

.tl-step { position: relative; display: flex; gap: 14px; padding-bottom: 15px; }
.tl-step:last-child { padding-bottom: 0; }

.tl-node {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 11px; position: relative; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  background: linear-gradient(145deg, rgba(124,58,237,0.34), rgba(236,72,153,0.24));
  border: 1px solid var(--node-bd); color: var(--node-fg);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--node-glow), var(--node-lift);
  /* Both states carry two shadow layers so the pair can interpolate. */
  --node-bd: rgba(167,139,250,0.55); --node-bd-on: rgba(236,72,153,0.95);
  --node-fg: #C4B5FD;               --node-fg-on: #fff;
  --node-glow: 0 0 0 0 rgba(167,139,250,0);
  --node-glow-on: 0 0 0 5px rgba(167,139,250,0.16);
  --node-lift: 0 6px 18px -8px rgba(124,58,237,0.85);
  --node-lift-on: 0 10px 24px -8px rgba(236,72,153,0.9);
}
.tl-node svg { width: 17px; height: 17px; display: block; }
:root[data-theme="light"] .tl-node {
  background: linear-gradient(145deg, rgba(124,58,237,0.14), rgba(236,72,153,0.1));
  --node-bd: rgba(124,58,237,0.35);  --node-bd-on: rgba(219,39,119,0.9);
  --node-fg: #6D28D9;                --node-fg-on: #4C1D95;
  --node-glow-on: 0 0 0 5px rgba(124,58,237,0.12);
  --node-lift: 0 6px 16px -8px rgba(124,58,237,0.5);
  --node-lift-on: 0 10px 22px -8px rgba(219,39,119,0.55);
}

.tl-body { padding-top: 2px; min-width: 0; }
.tl-title { font-size: 12.5px; font-weight: 700; line-height: 1.35; }
.tl-desc { font-size: 11.3px; line-height: 1.55; color: #a1a1aa; margin-top: 3px; }
:root[data-theme="light"] .tl-desc { color: #5b5c6b; }

/* ── The sweep ─────────────────────────────────────────────────────────────
   Each step is lit for one fifth of the cycle. The node and its copy animate
   separately (a keyframe can only reach the element it is on), so both take
   the same per-step delay from the rules below. */
.tl-node { animation: tl-node-lit var(--cycle) ease-in-out infinite; }
.tl-body { animation: tl-body-lit var(--cycle) ease-in-out infinite; }
.tl-step:nth-child(1) .tl-node, .tl-step:nth-child(1) .tl-body { animation-delay: 1.2s; }
.tl-step:nth-child(2) .tl-node, .tl-step:nth-child(2) .tl-body { animation-delay: 3.2s; }
.tl-step:nth-child(3) .tl-node, .tl-step:nth-child(3) .tl-body { animation-delay: 5.2s; }
.tl-step:nth-child(4) .tl-node, .tl-step:nth-child(4) .tl-body { animation-delay: 7.2s; }
.tl-step:nth-child(5) .tl-node, .tl-step:nth-child(5) .tl-body { animation-delay: 9.2s; }

@keyframes tl-node-lit {
  0%, 20%, 100% {
    transform: none; border-color: var(--node-bd); color: var(--node-fg);
    box-shadow: var(--node-glow), var(--node-lift);
  }
  3%, 13% {
    transform: scale(1.1); border-color: var(--node-bd-on); color: var(--node-fg-on);
    box-shadow: var(--node-glow-on), var(--node-lift-on);
  }
}
@keyframes tl-body-lit {
  0%, 20%, 100% { opacity: .78; transform: none; }
  3%, 13%       { opacity: 1;   transform: translateX(3px); }
}

/* Steps arrive in sequence on load — after the copy above them has landed
   (see the page choreography below) and ahead of the first sweep. */
.tl-step { animation: tl-in .5s cubic-bezier(.22,.85,.34,1) both; }
.tl-step:nth-child(1) { animation-delay: .30s; }
.tl-step:nth-child(2) { animation-delay: .38s; }
.tl-step:nth-child(3) { animation-delay: .46s; }
.tl-step:nth-child(4) { animation-delay: .54s; }
.tl-step:nth-child(5) { animation-delay: .62s; }
@keyframes tl-in {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: none; }
}

/* Nothing here carries meaning the still state does not: with motion off the
   pulse is dropped and every step reads at full strength on the rail. */
@media (prefers-reduced-motion: reduce) {
  .tl-step, .tl-node, .tl-body { animation: none; }
  .tl-body { opacity: 1; }
  .timeline::after { display: none; }
}

/* ── Page choreography ─────────────────────────────────────────────────────
   One wave down the page on load: brand, headline, description, then the
   timeline label and its steps, with the card and the footer arriving beside
   them. Everything is done inside a second — this is the first thing a client
   sees, and motion that outstays that stops being an entrance and becomes a
   wait. Each piece animates opacity and transform only, so nothing reflows. */
@keyframes auth-rise {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
.hero-brand, .hero-title, .hero-desc, .steps-label,
.auth-footer, .hero-toggles {
  animation: auth-rise .6s cubic-bezier(.22,.85,.34,1) both;
}
.hero-brand   { animation-delay: 0s; }
.hero-toggles { animation-delay: .06s; }   /* with the brand: one header */
.hero-title   { animation-delay: .12s; }
.hero-desc    { animation-delay: .19s; }
.steps-label  { animation-delay: .27s; }
.auth-footer  { animation-delay: .38s; }

/* The card carries the entrance on its panel rather than on itself, so that
   swapping the card's own animation for the shake below cannot re-trigger it. */
.auth-panel { animation: auth-card-in .65s cubic-bezier(.22,.85,.34,1) .16s both; }
@keyframes auth-card-in {
  from { opacity: 0; transform: translateY(16px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* A slow drift across the artwork. Long and gentle enough to register as depth
   rather than as movement — the frame never appears to be doing anything, it
   just is not quite where it was a minute ago. Scaling up only, so the cover
   image can never pull away from an edge. */
.hero-art img { animation: art-drift 46s ease-in-out infinite alternate; }
@keyframes art-drift {
  from { transform: scale(1); }
  to   { transform: scale(1.07) translateY(-1.2%); }
}

/* A light travelling across the headline's gradient. The gradient is widened
   and its position animated; the glyphs themselves never move. */
.hero-title .grad {
  background: linear-gradient(100deg, #A78BFA 0%, #EC4899 38%, #F0ABFC 50%, #A78BFA 68%, #A78BFA 100%);
  background-size: 280% 100%;
  -webkit-background-clip: text; background-clip: text;
  animation: grad-sheen 9s ease-in-out 1.4s infinite;
}
@keyframes grad-sheen {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}

/* The timeline is the tallest thing in the copy column, so on a short window
   it tightens rather than letting the centred column clip at both ends. */
@media (max-height: 700px) {
  .auth-header { padding-top: 12px; padding-bottom: 12px; }
  .auth-shell { padding-top: 60px; }
  .hero-copy { gap: 16px; padding-top: 30px; padding-bottom: 30px; }
  .hero-title { font-size: 29px; }
  .tl-step { padding-bottom: 10px; }
  .timeline { --rail-x: 14px; --rail-top: 15px; }
  .tl-node { width: 30px; height: 30px; border-radius: 10px; }
  .tl-node svg { width: 15px; height: 15px; }
  .tl-desc { font-size: 10.8px; margin-top: 2px; }
}

/* Artwork column — image is its own element so the copy never overlaps it. */
.hero-art { position: absolute; inset: 0; z-index: 0; overflow: hidden; background: #09090B; }
.auth-hero { position: relative; z-index: 2; background: transparent; }
.hero-art img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 42%; }
.hero-art .art-light { display: none; }
:root[data-theme="light"] .hero-art .art-dark { display: none; }
:root[data-theme="light"] .hero-art .art-light { display: block; }
:root[data-theme="light"] .hero-art { background: #ffffff; }

/* Fade only on the panel-facing edge; the copy column side is left clean. */
.hero-art-fade {
  position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background: linear-gradient(90deg, rgba(9,9,11,0.82) 0%, rgba(9,9,11,0.58) 20%, rgba(9,9,11,0.18) 36%, rgba(9,9,11,0) 50%);
}
:root[data-theme="light"] .hero-art-fade {
  background: linear-gradient(90deg, rgba(255,255,255,0.88) 0%, rgba(255,255,255,0.66) 20%, rgba(255,255,255,0.22) 36%, rgba(255,255,255,0) 50%);
}

/* Sits at the right of the header, opposite the brand. Glass chips, because
   they stand on the artwork rather than on a strip. */
.hero-toggles { display: flex; gap: 8px; flex-shrink: 0; }
.hero-toggles .icon-btn {
  width: 34px; min-width: 34px; height: 34px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(20,20,28,0.55); border: 1px solid rgba(255,255,255,0.16); color: #fff;
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.hero-toggles .icon-btn svg { width: 18px; height: 18px; display: block; }
/* Light mode: dark icon on a light chip. */
:root[data-theme="light"] .hero-toggles .icon-btn {
  background: rgba(255,255,255,0.9); border-color: rgba(20,21,31,0.12); color: #14151f;
}
:root[data-theme="light"] .hero-toggles .icon-btn:hover { background: #fff; border-color: rgba(20,21,31,0.2); }
:root[data-theme="light"] .hero-toggles .icon-btn:hover { background: #fff; border-color: rgba(20,21,31,0.2); }

/* ── Login panel ──────────────────────────────────────────────────────── */
.auth-panel {
  width: 32%; min-width: 480px; max-width: 548px; flex-shrink: 0;
  position: relative; z-index: 2; background: transparent;
  display: flex; align-items: center; justify-content: center; padding: 26px;
}

.auth-card {
  width: 100%; max-width: 470px; background: rgba(15,15,21,0.86);
  backdrop-filter: blur(22px); -webkit-backdrop-filter: blur(22px);
  border: 1px solid rgba(255,255,255,0.1); border-radius: 18px; padding: 30px 28px;
  box-shadow: 0 20px 60px -16px rgba(0,0,0,0.7);
}
:root[data-theme="light"] .auth-card {
  background: rgba(255,255,255,0.9); border-color: rgba(20,21,31,0.09);
  box-shadow: 0 16px 50px -14px rgba(20,21,31,0.22);
}

/* Company mark above the sign-in copy. The artwork is a navy wordmark whose
   seal has white knocked out of it, so recolouring it for the dark card would
   invert the seal. It keeps its true colours and sits on a white chip instead;
   in light mode the card is already white, so the chip steps back to nothing. */
.auth-brand { display: flex; justify-content: center; margin-bottom: 18px; }
.auth-brand-chip {
  display: inline-flex; align-items: center; padding: 9px 16px;
  background: #fff; border-radius: 12px;
  box-shadow: 0 8px 24px -10px rgba(0,0,0,0.75);
}
:root[data-theme="light"] .auth-brand-chip { background: none; box-shadow: none; padding: 0; }
.auth-brand-logo { height: 24px; width: auto; display: block; }

.auth-heading { font-size: 25px; font-weight: 800; text-align: center; margin: 0 0 7px; letter-spacing: -0.02em; }
.auth-sub { font-size: 11.5px; color: #8b8b96; text-align: center; margin-bottom: 22px; line-height: 1.55; }
:root[data-theme="light"] .auth-sub { color: #6f7080; }

/* Icon-inside inputs (placeholder doubles as the label, as in the design) */
.input-icon { position: relative; margin-bottom: 12px; }
.input-icon > svg {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  width: 17px; height: 17px; color: #6f7080; pointer-events: none;
}
.input-icon input {
  width: 100%; padding: 12px 14px 12px 40px; font-size: 12.8px; font-family: inherit;
  border-radius: 10px; border: 1px solid rgba(255,255,255,0.1);
  background: rgba(255,255,255,0.03); color: #fff;
  transition: border-color .15s ease, box-shadow .15s ease;
}
:root[data-theme="light"] .input-icon input { background: #fbfbfe; border-color: #e6e6f0; color: #14151f; }
.input-icon input::placeholder { color: #6f7080; }
.input-icon input:focus {
  outline: none; border-color: #7C3AED; box-shadow: 0 0 0 3px rgba(124,58,237,0.22);
}
.eye-btn {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  background: none; border: none; box-shadow: none; padding: 6px; cursor: pointer;
  color: #6f7080; min-width: auto; height: auto;
}
.eye-btn svg { width: 17px; height: 17px; display: block; }
.eye-btn:hover { transform: translateY(-50%); background: none; box-shadow: none; color: #A78BFA; }
.eye-btn.on { color: #7C3AED; }

.auth-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 12px 0 16px; }
.remember { display: flex; align-items: center; gap: 6px; font-size: 8.8px; color: #8b8b96; cursor: pointer; user-select: none; margin: 0; text-transform: none; letter-spacing: 0; font-weight: 500; white-space: nowrap; }
.remember input { width: 13px; height: 13px; accent-color: #7C3AED; cursor: pointer; flex-shrink: 0; }
:root[data-theme="light"] .remember { color: #6f7080; }
.link-pink {
  background: none; border: none; box-shadow: none; padding: 0; cursor: pointer;
  color: #EC4899; font-size: 8.8px; font-weight: 600; font-family: inherit;
  min-width: auto; height: auto; text-align: right; white-space: nowrap;
}
.link-pink:hover { transform: none; box-shadow: none; color: #A78BFA; }

.auth-submit {
  width: 100%; padding: 13px; border: none; border-radius: 10px; cursor: pointer;
  font-size: 14px; font-weight: 700; font-family: inherit; color: #fff;
  background: linear-gradient(95deg, #7C3AED, #EC4899);
  box-shadow: 0 8px 22px -6px rgba(124,58,237,0.6);
  transition: filter .15s ease;
}
.auth-submit:hover { filter: brightness(1.08); }
.auth-submit:disabled { opacity: .65; cursor: default; }

/* ── Form feedback ─────────────────────────────────────────────────────────
   The button lifts under the cursor and a highlight crosses it once, so the
   primary action answers the pointer. */
.auth-submit {
  position: relative; overflow: hidden;
  display: flex; align-items: center; justify-content: center; gap: 9px;
  transition: filter .15s ease, transform .15s ease, box-shadow .2s ease;
}
.auth-submit:hover:not(:disabled) {
  transform: translateY(-1px); box-shadow: 0 13px 30px -8px rgba(124,58,237,0.68);
}
.auth-submit:active:not(:disabled) { transform: translateY(0); }
.auth-submit::after {
  content: ''; position: absolute; top: 0; bottom: 0; left: -60%; width: 42%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,0.34), transparent);
  transform: skewX(-18deg); pointer-events: none; opacity: 0;
}
.auth-submit:hover:not(:disabled)::after { animation: btn-sheen .75s ease; }
@keyframes btn-sheen {
  from { left: -60%; opacity: 1; }
  to   { left: 118%; opacity: 1; }
}
/* Signing in is a wait on the network, so it gets a spinner rather than only a
   change of label. It is a flex item beside the label the script sets. */
.auth-submit.is-loading::before {
  content: ''; flex: 0 0 auto; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.42); border-top-color: #fff;
  animation: btn-spin .7s linear infinite;
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

/* A rejected password shakes the card and the reason fades in under it. */
.auth-card.shake { animation: card-shake .45s cubic-bezier(.36,.07,.19,.97) both; }
@keyframes card-shake {
  10%, 90%      { transform: translateX(-2px); }
  20%, 80%      { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-7px); }
  40%, 60%      { transform: translateX(7px); }
  100%          { transform: none; }
}
.auth-error:not(:empty) { animation: auth-rise .28s ease both; }

/* The icon in a field tints as the field takes focus. */
.input-icon > svg { transition: color .16s ease; }
.input-icon:focus-within > svg { color: #A78BFA; }
:root[data-theme="light"] .input-icon:focus-within > svg { color: #7C3AED; }

.hero-toggles .icon-btn { transition: transform .18s ease, background .2s ease, border-color .2s ease; }
.hero-toggles .icon-btn:hover { transform: translateY(-1px) scale(1.06); }

/* With motion off, every one of these is decoration that the still page says
   just as well — except the sign-in spinner, which is the only signal that the
   request is still running. */
@media (prefers-reduced-motion: reduce) {
  .hero-brand, .hero-title, .hero-desc, .steps-label, .auth-footer, .hero-toggles,
  .auth-panel, .hero-art img, .hero-title .grad, .auth-card.shake,
  .auth-error:not(:empty), .auth-submit:hover:not(:disabled)::after { animation: none; }
  .auth-submit:hover:not(:disabled) { transform: none; }
  .hero-toggles .icon-btn:hover { transform: none; }
}

.auth-error { color: #f87171; font-size: 11.5px; text-align: center; margin-top: 9px; min-height: 1em; }
.auth-foot { text-align: center; font-size: 10px; color: #8b8b96; margin-top: 16px; line-height: 1.7; }
.auth-foot .link-pink { font-size: 10px; }
:root[data-theme="light"] .auth-foot { color: #6f7080; }

/* ── Footer strip ─────────────────────────────────────────────────────── */
.auth-footer {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px;
  padding: 13px 52px; background: #060609; border-top: 1px solid rgba(255,255,255,0.06);
}
:root[data-theme="light"] .auth-footer { background: #f7f7fb; border-top-color: #ececf5; }
.auth-footer-items { display: flex; gap: 34px; flex-wrap: wrap; }
.auth-footer-items span { display: inline-flex; align-items: center; gap: 8px; font-size: 10.5px; }
.auth-footer-items svg { width: 17px; height: 17px; color: #A78BFA; flex-shrink: 0; }
.auth-footer-items b { font-weight: 600; }
.auth-footer-rights { font-size: 10.5px; color: #8b8b96; }
:root[data-theme="light"] .auth-footer-rights { color: #6f7080; }

@media (max-width: 1250px) {
  .hero-copy { width: auto; flex: 1; }
}
@media (max-width: 900px) {
  .auth-shell { flex-direction: column; }
  .hero-copy { display: none; }
  /* Header and footer now bracket the shell, so the panel fills what is left
     rather than claiming a full viewport of its own and overflowing it. */
  .auth-panel { width: 100%; max-width: none; min-width: 0; flex: 1; }
  .auth-header { padding: 13px 20px; }
  .auth-footer { padding: 11px 20px; }
  .auth-footer-items { gap: 16px; }
}

/* ---- Watermark position picker ------------------------------------------- */

.wm-grid {
  display: grid; grid-template-columns: repeat(3, 34px); grid-template-rows: repeat(3, 26px);
  gap: 3px; padding: 5px; border-radius: 10px;
  border: 1.5px solid var(--border); background: var(--panel-soft);
}
.wm-cell {
  padding: 0; border-radius: 5px; border: 1.5px dashed var(--border);
  background: transparent; box-shadow: none; min-width: 0;
}
.wm-cell:hover { transform: none; box-shadow: none; border-color: var(--accent); background: var(--accent-soft); }
.wm-cell.active {
  border-style: solid; border-color: transparent;
  background: linear-gradient(95deg, #7C3AED, #EC4899);
  box-shadow: 0 3px 10px -3px rgba(124,58,237,0.6);
}

.wm-preview {
  position: relative; width: 160px; height: 90px; border-radius: 8px; overflow: hidden;
  border: 1.5px solid var(--border); background: repeating-conic-gradient(var(--border-soft) 0% 25%, var(--panel) 0% 50%) 50% / 14px 14px;
}
.wm-preview img { position: absolute; display: block; object-fit: contain; }

input[type=range] { width: 100%; accent-color: var(--accent); }

/* ---- confirmDialog --------------------------------------------------------- */
/* Sits above the modal that opened it — a confirm is always a response to
   something already on screen, so it has to stack on top of it. */
.confirm-overlay { z-index: 90; }
.confirm-box { max-width: 440px; }
.confirm-message { color: var(--muted); font-size: 13.5px; line-height: 1.6; }
/* Actions sit at the end of the dialog, with the safe answer furthest from
   the pointer's resting place on the confirming one. */
.confirm-actions { margin-top: 18px; justify-content: flex-end; flex-wrap: wrap; }
/* A destructive confirm gets a filled red button. The outline .danger used
   elsewhere is too quiet for the one click that cannot be undone. */
button.danger-solid {
  background: var(--bad); border-color: var(--bad); color: #fff; font-weight: 700;
}
button.danger-solid:hover { filter: brightness(1.08); box-shadow: 0 10px 22px -4px var(--bad-soft); }
.confirm-box.is-danger .modal-head strong { color: var(--bad); }

/* ---- Busy lock ------------------------------------------------------------ */
/* Everything is dimmed and inert while a long job runs, EXCEPT anything marked
   data-busy-allow — which is how a render's own Cancel button stays reachable. */
body.is-busy .panel,
body.is-busy .stage-timeline,
body.is-busy .topbar-right { opacity: 0.5; pointer-events: none; user-select: none; }
body.is-busy [data-busy-allow],
body.is-busy [data-busy-allow] * { opacity: 1; pointer-events: auto; user-select: auto; }

/* Sits above the toast (bottom 24) and the floating action stack (bottom 28),
   both of which occupy the bottom-right corner — a centred banner at the same
   height would be covered by every toast the job itself produces. */
.busy-banner {
  position: fixed; left: 50%; bottom: 92px; transform: translateX(-50%);
  z-index: 95; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  max-width: min(92vw, 720px); padding: 12px 18px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--border-soft);
  box-shadow: var(--shadow-lg); font-size: 13px; color: var(--ink);
}
.busy-text { font-weight: 700; }
.busy-warn { color: var(--muted); font-size: 12px; }
.busy-spinner {
  width: 15px; height: 15px; flex: none; border-radius: 50%;
  border: 2px solid var(--border); border-top-color: #7c3aed;
  animation: busy-spin 0.8s linear infinite;
}
@keyframes busy-spin { to { transform: rotate(360deg); } }

/* ---- Narration progress ---------------------------------------------------- */
.progress-modal .modal-box { max-width: 480px; }
.narr-progress-bar {
  height: 8px; border-radius: 999px; background: var(--border); overflow: hidden; margin: 14px 0 10px;
}
.narr-progress-fill {
  height: 100%; width: 0%; border-radius: 999px;
  background: linear-gradient(90deg, #7c3aed, #ec4899); transition: width 0.35s ease;
}
.narr-progress-line { display: flex; justify-content: space-between; gap: 12px; font-size: 13px; }
.narr-progress-current { color: var(--muted); }
.narr-progress-count { font-variant-numeric: tabular-nums; font-weight: 800; }
.warn-note { margin-top: 10px; color: var(--warn, #d97706); font-weight: 600; }

/* ---- Advanced settings, folded away ---------------------------------------- */
/* A native <details>: closed by default, opened by click or keyboard, and its
   fields stay in the form either way. */
.advanced { margin-top: 18px; border-top: 1px solid var(--line); padding-top: 14px; }
.advanced > summary {
  display: flex; align-items: center; gap: 9px; cursor: pointer; list-style: none;
  padding: 9px 12px; margin: 0 -12px; border-radius: 10px;
  font-size: 13.5px; font-weight: 700; color: var(--ink);
  transition: background .15s ease, color .15s ease;
}
.advanced > summary::-webkit-details-marker { display: none; }
.advanced > summary:hover { background: var(--accent-soft); color: var(--accent); }
.advanced > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.adv-chevron { width: 15px; height: 15px; flex-shrink: 0; color: var(--muted); transition: transform .2s ease, color .15s ease; }
.advanced[open] > summary .adv-chevron { transform: rotate(90deg); color: var(--accent); }
.advanced > summary:hover .adv-chevron { color: var(--accent); }
.advanced-body { padding-top: 4px; animation: adv-open .22s ease both; }
@keyframes adv-open { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .adv-chevron { transition: none; }
  .advanced-body { animation: none; }
}

/* ---- Narration & audio summary --------------------------------------------- */
.narr-summary { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
.narr-stat {
  display: flex; align-items: baseline; gap: 8px; padding: 10px 14px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--ink) 4%, transparent);
}
.narr-stat-num { font-size: 18px; font-weight: 800; font-variant-numeric: tabular-nums; }
.narr-stat-label { font-size: 12px; color: var(--muted); }
.narr-stat.is-ok .narr-stat-num { color: var(--good, #10b981); }
.narr-stat.is-gap .narr-stat-num { color: var(--warn, #f59e0b); }
/* The list of gaps inside a confirmation — scrolls rather than growing the box
   off the screen on a forty-stop tour. */
.gap-list {
  margin: 12px 0 0; padding: 10px 12px; max-height: 190px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: 12.5px; line-height: 1.8; color: var(--muted);
}
.gap-list div { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- Narration draft picker ------------------------------------------------ */
/* Every row here is a <label>, which inherits the global form-label rule
   (uppercase, letter-spaced, 11.5px, muted). That is right for a field caption
   and wrong for a sentence, so it is reset first — the export dialog does the
   same for its own option rows. */
.draft-choice,
.draft-pick,
.draft-choice *,
.draft-pick * {
  text-transform: none; letter-spacing: 0; margin-bottom: 0;
}

/* The box is capped to the window and scrolls inside, so choosing "Choose
   sections" on a forty-stop tour cannot push the buttons off the screen. */
.draft-modal-box {
  max-width: 600px; max-height: 86vh; display: flex; flex-direction: column;
}
.draft-modal-body {
  overflow-y: auto; flex: 1 1 auto; min-height: 0;
  margin: 14px -4px 0; padding: 0 4px;
}
.draft-modal-foot {
  flex: none; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border);
}

.draft-choices { display: grid; gap: 6px; }
.draft-choice {
  display: grid; grid-template-columns: auto 1fr auto; gap: 2px 10px; align-items: center;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  cursor: pointer; color: var(--ink); font-weight: 400;
  transition: border-color .15s, background .15s;
}
.draft-choice:hover { border-color: var(--border-soft); }
.draft-choice.active { border-color: #7c3aed; background: color-mix(in srgb, #7c3aed 9%, transparent); }
.draft-choice.is-disabled { opacity: .45; pointer-events: none; }
.draft-choice input { margin: 0; }
.draft-choice-name { font-weight: 700; font-size: 13.5px; color: var(--ink); }
.draft-choice-count { font-size: 12px; color: var(--muted); white-space: nowrap; }
.draft-choice-note {
  grid-column: 2 / -1; font-size: 12px; color: var(--muted); line-height: 1.45;
}

.draft-custom-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 18px 0 8px; flex-wrap: wrap;
}
.draft-custom-title { font-weight: 700; font-size: 13px; color: var(--ink); }
.draft-custom-actions { display: flex; gap: 6px; }
.draft-custom-list {
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 4px;
}
.draft-pick {
  display: flex; align-items: center; gap: 9px; padding: 6px 9px;
  border-radius: 8px; cursor: pointer; font-size: 13px; font-weight: 400; color: var(--ink);
}
.draft-pick:hover { background: color-mix(in srgb, var(--ink) 6%, transparent); }
.draft-pick input { margin: 0; flex: none; }
.draft-pick-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A stop's own two lines are stepped in, so the list reads as stops rather than
   a flat run of forty checkboxes. */
.draft-pick.is-sub { padding-left: 24px; }
.draft-pick.is-sub .draft-pick-label { color: var(--muted); }
.draft-pick-tag { font-size: 11px; color: var(--muted); white-space: nowrap; }
.draft-pick-tag.is-empty { color: var(--warn, #f59e0b); font-weight: 700; }
.draft-group-head {
  font-size: 12px; font-weight: 700; color: var(--ink);
  padding: 10px 9px 4px; text-transform: none; letter-spacing: 0;
}
.draft-group-head + .draft-pick.is-sub { padding-left: 24px; }

/* Narrow windows: the option row's name/count columns collapse rather than
   squeezing the note into a two-word-per-line ribbon. */
@media (max-width: 560px) {
  .draft-choice { grid-template-columns: auto 1fr; }
  .draft-choice-count { grid-column: 2; justify-self: start; }
  .draft-choice-note { grid-column: 1 / -1; }
  .busy-banner { bottom: 84px; flex-direction: column; align-items: flex-start; gap: 4px; border-radius: 14px; }
  .narr-summary { flex-direction: column; }
  .narr-stat { justify-content: space-between; }
}

/* A value the user can read but not edit — same footprint as an input so the
   field lines up with the ones beside it, without pretending to be editable. */
.readonly-value {
  padding: 11px 13px; border-radius: 10px; font-size: 13.5px;
  border: 1px dashed var(--border); background: color-mix(in srgb, var(--ink) 3%, transparent);
  color: var(--ink); word-break: break-all;
}
.fallback-note { font-size: 11.5px; color: var(--muted); margin-left: 8px; }

/* What a key has left to spend, under the key it belongs to. Three states, and
   the colour is the whole message: fine, nearly gone, or nothing to report. */
.credit-line { font-size: 12px; color: var(--muted); margin-top: 6px; min-height: 16px; }
.credit-line.is-ok { color: var(--accent-3); }
.credit-line.is-warn { color: var(--bad); }
.credit-line.is-muted { color: var(--muted-2); }

/* ---- A switch that currently decides nothing -------------------------------- */
/* The per-stop marker switches only apply while the tour is on its default
   marker. With it off they are disabled rather than hidden: the row still says
   what it would do, so the setting is discoverable instead of appearing only
   once some other switch happens to be flipped. */
.own-marker-row.is-moot { opacity: 0.5; cursor: default; }
.own-marker-row.is-moot .toggle-label { font-style: italic; }

/* ---- Dashboard stat cards -------------------------------------------------- */
/* A row of totals above the work itself, on both dashboards. Every figure is
   counted from data the page has already loaded, so the cards cannot drift from
   the rows underneath them.

   Each card is coloured by --card-color, set per card in the markup: one
   variable drives the tint, the border, the icon and the glow, so a new card
   needs a hue rather than a rule. */
.stat-cards {
  display: grid; gap: 14px; margin-bottom: 20px;
  grid-template-columns: repeat(auto-fit, minmax(205px, 1fr));
}

.stat-card {
  --card-color: var(--accent);
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 14px;
  padding: 17px 19px; border-radius: 18px;
  border: 1px solid color-mix(in srgb, var(--card-color) 24%, transparent);
  /* A wash from the top-right corner rather than a flat fill, so the card has
     a light source and does not read as a plain rectangle. */
  background:
    radial-gradient(130% 110% at 100% 0%, color-mix(in srgb, var(--card-color) 16%, transparent) 0%, transparent 62%),
    linear-gradient(155deg, color-mix(in srgb, var(--card-color) 9%, var(--panel)) 0%, var(--panel) 68%);
  box-shadow: var(--shadow-sm);
  transition: transform .18s ease, box-shadow .22s ease, border-color .22s ease;
}
/* The decorative bloom in the corner. Purely a shape — no content to read, and
   it never intercepts the pointer. */
.stat-card::before {
  content: ''; position: absolute; right: -34px; bottom: -46px;
  width: 128px; height: 128px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, color-mix(in srgb, var(--card-color) 20%, transparent) 0%, transparent 70%);
}
.stat-card:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--card-color) 44%, transparent);
  box-shadow: 0 16px 34px -14px color-mix(in srgb, var(--card-color) 60%, transparent), var(--shadow-md);
}

.stat-card-icon {
  position: relative; flex: 0 0 auto;
  width: 44px; height: 44px; border-radius: 14px;
  display: inline-flex; align-items: center; justify-content: center;
  background: linear-gradient(145deg, var(--card-color), color-mix(in srgb, var(--card-color) 62%, #000));
  color: #fff;
  box-shadow: 0 9px 20px -8px color-mix(in srgb, var(--card-color) 75%, transparent);
}
.stat-card-icon svg { width: 21px; height: 21px; display: block; }

.stat-card-body { position: relative; min-width: 0; }
/* Tabular figures so a column of numbers does not jitter as it updates. */
.stat-card-num {
  font-size: 28px; font-weight: 800; line-height: 1.05; letter-spacing: -0.03em;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.stat-card-label {
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--muted); margin-top: 5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* They arrive together with the page, in order, so the row assembles rather
   than appearing. */
.stat-card { animation: stat-in .45s cubic-bezier(.22,.85,.34,1) both; }
.stat-card:nth-child(1) { animation-delay: .02s; }
.stat-card:nth-child(2) { animation-delay: .08s; }
.stat-card:nth-child(3) { animation-delay: .14s; }
.stat-card:nth-child(4) { animation-delay: .20s; }
@keyframes stat-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .stat-card { animation: none; }
  .stat-card:hover { transform: none; }
}

/* ---- Itinerary page --------------------------------------------------------- */
/* A cinematic hero over the page's own artwork, with the itinerary on a glass
   sheet that rides up into it. The palette is declared here rather than taken
   wholesale from the app's tokens: this page is a piece of travel writing, not
   a screen of the builder, and it is darker and warmer than the tool is.
   Only the presentation lives here — every id, class hook and behaviour the
   page's script relies on is unchanged. */
.itin-body {
  margin: 0; min-height: 100vh; scroll-behavior: smooth;
  --itin-page: #07070D;
  --itin-card: rgba(18, 18, 28, 0.85);
  --itin-sheet: rgba(15, 15, 25, 0.82);
  --itin-line: rgba(255, 255, 255, 0.08);
  --itin-ink: #F7F5FF;
  --itin-dim: #9693A8;
  --itin-violet: #8B5CF6;
  --itin-pink: #EC4899;
  --itin-green: #10B981;
  --itin-grad: linear-gradient(135deg, #8B5CF6, #EC4899);
  background:
    radial-gradient(900px 620px at 8% 42%, rgba(139, 92, 246, 0.035), transparent 70%),
    radial-gradient(760px 520px at 96% 62%, rgba(236, 72, 153, 0.025), transparent 70%),
    radial-gradient(680px 480px at 46% 96%, rgba(16, 185, 129, 0.015), transparent 70%),
    var(--itin-page);
  color: var(--itin-ink);
}
/* Light and dark differ only in surface, ink and border — never in metrics —
   so the theme can be crossfaded with nothing on the page moving. */
.itin-sheet, .itin-card, .itin-side, .itin-node, .itin-mode, .itin-back,
.itin-hero-tools .icon-btn, .itin-card-where, .itin-stat-icon {
  transition: background-color 480ms ease, background-image 480ms ease,
              border-color 480ms ease, box-shadow 480ms ease, color 480ms ease;
}
.itin-title, .itin-subtitle, .itin-kicker, .itin-card-title, .itin-card-notes,
.itin-stat-num, .itin-stat-label, .itin-leg-mode, .itin-leg-figs,
.itin-side-title, .itin-side-note { transition: color 480ms ease; }
/* The same page in daylight: the artwork carries the mood, so the surfaces
   only have to stay out of its way. */
:root[data-theme="light"] .itin-body {
  --itin-page: #F6F4FB;
  --itin-card: rgba(255, 255, 255, 0.86);
  --itin-sheet: rgba(255, 255, 255, 0.80);
  --itin-line: rgba(20, 20, 40, 0.09);
  --itin-ink: #16142A;
  --itin-dim: #6B6880;
}

/* ---- hero ---- */
.itin-hero { position: relative; min-height: 440px; display: flex; align-items: flex-start; }
/* The picture runs on well past the hero and is spent long before its own
   bottom edge is reached. Ending it AT the hero left a straight horizontal cut
   across the page — plainest to the right of the sheet, where it read as a box
   of photograph sitting on flat colour. `cover` is measured from the top, so
   lengthening the frame reveals more of the same picture without reframing it
   at any width. */
.itin-art { position: absolute; inset: 0 0 -260px; overflow: hidden; }
/* Both frames are always present and crossfaded, so switching theme changes
   the picture without moving a single element on the page. */
.itin-art img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center top;
  opacity: 0; transition: opacity 500ms ease;
}
.itin-art .art-dark { opacity: 1; }
:root[data-theme="light"] .itin-art .art-dark { opacity: 0; }
:root[data-theme="light"] .itin-art .art-light { opacity: 1; }
/* Readable over any frame, and dissolving into the page so the picture is the
   top of the page rather than a panel sitting on it. The vertical wash reaches
   the page colour outright well above the frame's bottom, so whatever is left
   of the photograph is already gone by the time it is clipped — there is no
   edge to see. */
.itin-art-fade {
  position: absolute; inset: 0;
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--itin-page) 82%, transparent) 0%,
      color-mix(in srgb, var(--itin-page) 40%, transparent) 40%,
      transparent 64%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--itin-page) 18%, transparent) 0%,
      transparent 12%,
      transparent 44%,
      color-mix(in srgb, var(--itin-page) 46%, transparent) 56%,
      color-mix(in srgb, var(--itin-page) 88%, transparent) 63%,
      var(--itin-page) 68%,
      var(--itin-page) 100%);
}

.itin-hero-inner {
  position: relative; z-index: 1;
  width: 100%; max-width: 1400px; margin: 0 auto;
  padding: 24px 32px 96px;
}
.itin-hero-bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 46px; }
.itin-hero-tools { display: flex; gap: 10px; }
/* Glass discs, sized to the touch target rather than to the icon. */
.itin-hero-tools .icon-btn {
  width: 42px; min-width: 42px; height: 42px; padding: 0; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.10); border: 1px solid var(--itin-line); color: var(--itin-ink);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
:root[data-theme="light"] .itin-hero-tools .icon-btn { background: rgba(255,255,255,0.72); }
.itin-hero-tools .icon-btn:hover { background: rgba(255,255,255,0.18); }
:root[data-theme="light"] .itin-hero-tools .icon-btn:hover { background: #fff; }

.itin-back {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 9px 16px; border-radius: 11px;
  font-size: 13px; font-weight: 600; color: var(--itin-ink); text-decoration: none;
  background: rgba(255,255,255,0.08); border: 1px solid var(--itin-line);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  transition: background .18s ease, gap .18s ease;
}
:root[data-theme="light"] .itin-back { background: rgba(255,255,255,0.72); }
.itin-back:hover { background: rgba(255,255,255,0.15); gap: 12px; }
:root[data-theme="light"] .itin-back:hover { background: #fff; }
.itin-back svg { width: 16px; height: 16px; }

.itin-kicker {
  display: flex; align-items: center; gap: 7px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase;
  color: #A78BFA; min-height: 15px;
}
:root[data-theme="light"] .itin-kicker { color: var(--itin-violet); }
.itin-kicker svg { width: 15px; height: 15px; }

.itin-title {
  margin: 12px 0 0; font-size: clamp(36px, 4.6vw, 60px); font-weight: 800;
  letter-spacing: -0.03em; line-height: 1.05; color: var(--itin-ink); max-width: 20ch;
}
.itin-subtitle {
  margin: 10px 0 0; font-size: clamp(14px, 1.35vw, 17px); font-weight: 500;
  letter-spacing: 0.04em; line-height: 1.5; color: var(--itin-dim); max-width: 46ch;
}
.itin-subtitle[hidden] { display: none; }
.itin-title-rule { width: 84px; height: 3px; border-radius: 3px; margin: 20px 0 0; background: var(--itin-grad); }

/* Figures sit in the hero, spaced and divided rather than boxed. */
.itin-summary { display: flex; flex-wrap: wrap; align-items: center; gap: 0; margin-top: 26px; }
.itin-stat { display: flex; align-items: center; gap: 15px; padding: 4px 36px; }
.itin-stat:first-child { padding-left: 0; }
.itin-stat + .itin-stat { border-left: 1px solid var(--itin-line); }
.itin-stat-icon {
  flex: 0 0 auto; width: 54px; height: 54px; border-radius: 17px;
  display: inline-flex; align-items: center; justify-content: center;
}
.itin-stat-icon svg { width: 24px; height: 24px; display: block; }
.itin-stat-icon.is-violet { background: color-mix(in srgb, var(--itin-violet) 18%, transparent); color: #A78BFA; }
.itin-stat-icon.is-pink   { background: color-mix(in srgb, var(--itin-pink) 18%, transparent);   color: #F472B6; }
.itin-stat-icon.is-green  { background: color-mix(in srgb, var(--itin-green) 18%, transparent);  color: #34D399; }
:root[data-theme="light"] .itin-stat-icon.is-violet { color: var(--itin-violet); }
:root[data-theme="light"] .itin-stat-icon.is-pink { color: var(--itin-pink); }
:root[data-theme="light"] .itin-stat-icon.is-green { color: var(--itin-green); }
.itin-stat-num {
  font-size: 30px; font-weight: 800; color: var(--itin-ink);
  letter-spacing: -0.03em; font-variant-numeric: tabular-nums; line-height: 1.1;
}
.itin-stat-unit { font-size: 16px; font-weight: 600; margin-left: 4px; color: var(--itin-dim); }
.itin-stat-label {
  font-size: 11px; font-weight: 700; letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--itin-dim); margin-top: 5px;
}

.itin-kicker, .itin-title, .itin-subtitle, .itin-title-rule, .itin-summary, .itin-hero-bar {
  animation: itin-rise .6s cubic-bezier(.22,.85,.34,1) both;
}
.itin-hero-bar   { animation-delay: .02s; }
.itin-kicker     { animation-delay: .08s; }
.itin-title      { animation-delay: .15s; }
.itin-subtitle   { animation-delay: .21s; }
.itin-title-rule { animation-delay: .26s; }
.itin-summary    { animation-delay: .32s; }
@keyframes itin-rise { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }

/* ---- the sheet the itinerary sits on ---- */
.itin-main { max-width: 1400px; margin: 0 auto; padding: 0 32px 120px; }
.itin-sheet {
  position: relative; z-index: 1; margin-top: -72px;
  padding: 30px 44px 52px;
  background: rgba(15, 15, 25, 0.82);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 30px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
}
:root[data-theme="light"] .itin-sheet {
  background: linear-gradient(135deg, rgba(255,255,255,0.88), rgba(248,246,255,0.82));
  border-color: rgba(120, 90, 180, 0.10);
  box-shadow: 0 20px 60px rgba(80, 60, 120, 0.10);
}

/* ---- the spine ---- */
.itin-row { display: grid; grid-template-columns: 52px 100px 1fr; gap: 0; }
/* A grid track sized to `1fr` still refuses to go below its content's minimum,
   and the aside's one-line body has a wide one — without this the narrow
   screens are pushed sideways by a row that ought to be shrinking. */
.itin-gutter, .itin-content { min-width: 0; }
.itin-rail { display: flex; flex-direction: column; align-items: center; }
.itin-rail-line { width: 2px; flex: 1 1 auto; min-height: 14px; border-radius: 2px; background: var(--itin-line); transition: background .7s ease; }
.itin-row.is-in .itin-rail-line { background: linear-gradient(180deg, var(--itin-violet), var(--itin-pink)); }
.itin-row.is-in .itin-rail-line.is-travel {
  background: repeating-linear-gradient(180deg, color-mix(in srgb, var(--itin-violet) 70%, transparent) 0 7px, transparent 7px 14px);
}
.itin-row:first-child .itin-rail-line.up,
.itin-row:last-child .itin-rail-line.down { visibility: hidden; }
/* Fixed above, flexible below: the marker lands beside the head of its card. */
.itin-row.is-stop .itin-rail-line.up { flex: 0 0 46px; }
.itin-row.is-optional .itin-rail-line.up { flex: 0 0 24px; }
.itin-row.is-leg .itin-rail-line.up { flex: 0 0 20px; }

.itin-node {
  --node-hue: var(--itin-violet);
  position: relative; flex: 0 0 auto; width: 46px; height: 46px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 15.5px; font-weight: 700; color: #fff;
  background: linear-gradient(150deg, var(--node-hue), color-mix(in srgb, var(--node-hue) 60%, #000));
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--node-hue) 12%, transparent);
}
/* Where the walk begins and where it finishes, coloured as the map has always
   coloured them: green at the start, red at the end. The hue drives the whole
   marker — its fill, its halo and the ring it throws on arrival — so naming it
   here is enough. */
.itin-node.is-start { --node-hue: #10B981; }
.itin-node.is-end   { --node-hue: #EF4444; }
.itin-pin.is-start  { background: linear-gradient(150deg, #34D399, #059669); }
.itin-pin.is-end    { background: linear-gradient(150deg, #F87171, #DC2626); }

.itin-row.is-in .itin-node { animation: itin-pop .55s cubic-bezier(.34,1.5,.5,1) both; }
.itin-row.is-in .itin-node::after {
  content: ''; position: absolute; inset: -3px; border-radius: 50%;
  border: 2px solid var(--node-hue);
  animation: itin-ring 1.1s cubic-bezier(.25,.6,.35,1) .25s both;
}
@keyframes itin-pop { from { opacity: 0; transform: scale(0.55); } to { opacity: 1; transform: none; } }
@keyframes itin-ring { from { opacity: .6; transform: scale(1); } to { opacity: 0; transform: scale(1.9); } }

.itin-mode {
  flex: 0 0 auto; width: 36px; height: 36px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: #A78BFA; background: color-mix(in srgb, var(--itin-violet) 14%, transparent);
  border: 1px solid var(--itin-line);
}
:root[data-theme="light"] .itin-mode { color: var(--itin-violet); background: #fff; }
.itin-row.is-in .itin-mode { animation: itin-pop .5s cubic-bezier(.34,1.5,.5,1) both; }
.itin-mode svg { width: 17px; height: 17px; display: block; }
.itin-row.is-in .itin-mode svg { animation: itin-step 2.4s ease-in-out .5s infinite; }
@keyframes itin-step { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-2.5px); } }

.itin-row.is-in .itin-content { animation: itin-slide .6s cubic-bezier(.22,.85,.34,1) both; }
@keyframes itin-slide { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }

/* ---- a stop ---- */
.itin-card {
  display: grid; grid-template-columns: 400px 1fr; overflow: hidden;
  background: rgba(20, 20, 30, 0.82); border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: 24px; margin: 0 0 44px;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
  transition: transform .2s ease, box-shadow .25s ease, border-color .2s ease;
}
:root[data-theme="light"] .itin-card {
  background: rgba(255, 255, 255, 0.86);
  border-color: rgba(100, 80, 150, 0.12);
  box-shadow: 0 8px 30px rgba(80, 60, 120, 0.06);
}
.itin-card:hover {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--itin-violet) 32%, transparent);
  box-shadow: 0 16px 44px rgba(0, 0, 0, 0.32);
}
:root[data-theme="light"] .itin-card:hover { box-shadow: 0 16px 44px rgba(80, 60, 120, 0.12); }
.itin-card-media { overflow: hidden; }
.itin-card-img {
  width: 100%; height: 100%; min-height: 332px; object-fit: cover; display: block;
  background: rgba(255,255,255,0.04);
  transition: transform .55s cubic-bezier(.22,.85,.34,1);
}
.itin-card:hover .itin-card-img { transform: scale(1.04); }
.itin-card-img.is-empty { display: flex; align-items: center; justify-content: center; color: var(--itin-dim); }
.itin-card-img.is-empty svg { width: 38px; height: 38px; }
.itin-card-body { position: relative; padding: 38px; min-width: 0; display: flex; flex-direction: column; justify-content: center; overflow: hidden; }

/* Text container sits on the left of card body */
.itin-card-info { position: relative; z-index: 2; max-width: 58%; }

.itin-card-where {
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: 7px; margin: 0 0 16px;
  padding: 7px 13px; border-radius: 999px;
  background: rgba(130, 80, 255, 0.12); border: 1px solid rgba(150, 100, 255, 0.15);
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase;
  color: #A78BFA;
}
:root[data-theme="light"] .itin-card-where { color: var(--itin-violet); }
.itin-card-where svg { width: 13px; height: 13px; }
.itin-card-title { margin: 0; font-size: 28px; font-weight: 700; letter-spacing: -0.025em; color: var(--itin-ink); line-height: 1.2; }
.itin-card-rule { width: 64px; height: 3px; border-radius: 3px; margin: 16px 0 18px; background: var(--itin-grad); }
.itin-card-notes {
  margin: 0; font-size: 16px; line-height: 1.7; color: var(--itin-dim);
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}

.itin-card-btn {
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: 8px; margin-top: 26px;
  padding: 12px 20px; border-radius: 11px; cursor: pointer;
  font-size: 13.5px; font-weight: 600; font-family: inherit;
  border: none; color: #fff; background: var(--itin-grad);
  transition: box-shadow .2s ease, transform .15s ease, gap .15s ease;
}
.itin-card-btn svg { width: 14px; height: 14px; }
.itin-card-btn:hover {
  transform: translateY(-1px); gap: 11px;
  box-shadow: 0 14px 34px -12px rgba(236, 72, 153, 0.65);
}


/* The illustration palette. The drawings name their fills rather than fixing
   them, so the same scene is painted for the theme it is read in — deeper and
   quieter at night, and in daylight the brighter set below. */
.itin-body {
  --il-cloud: #262C4A;   --il-cloud-warm: #33304A;
  --il-blue: #3F5893;    --il-blue-2: #4A6AB0;
  --il-sky: #2F7FA6;     --il-sky-2: #3E93C0;   --il-sky-3: #1C5C84;
  --il-green: #17624E;   --il-green-2: #114C3D; --il-green-3: #0B3A2E; --il-green-4: #0D4436;
  --il-pink: #C2568F;    --il-rose: #C05264;    --il-rose-2: #A8384F;
  --il-violet: #5B5BD6;  --il-violet-2: #4A44C4; --il-violet-3: #6E6ACB; --il-violet-4: #8B7FD4;
  --il-plum: #9A6BD0;    --il-plum-2: #6B2FA8;  --il-plum-3: #5A2790;  --il-plum-4: #481B72;
  --il-red: #A93B37;     --il-red-2: #7E2523;   --il-red-3: #B25B57;
  --il-ink: #98A1BC;     --il-ink-2: #8792AE;   --il-ink-3: #97A1BB;   --il-ink-4: #A8B0C7;
  --il-wood: #8A5732;    --il-gold: #8E6B23;    --il-gold-2: #916821;
  --il-white: #E6E9F5;
}
:root[data-theme="light"] .itin-body {
  --il-cloud: #EEF2FF;   --il-cloud-warm: #FEF3C7;
  --il-blue: #93C5FD;    --il-blue-2: #60A5FA;
  --il-sky: #38BDF8;     --il-sky-2: #7DD3FC;   --il-sky-3: #0284C7;
  --il-green: #34D399;   --il-green-2: #059669; --il-green-3: #065F46; --il-green-4: #047857;
  --il-pink: #F472B6;    --il-rose: #FB7185;    --il-rose-2: #F43F5E;
  --il-violet: #6366F1;  --il-violet-2: #4F46E5; --il-violet-3: #818CF8; --il-violet-4: #A78BFA;
  --il-plum: #C084FC;    --il-plum-2: #7E22CE;  --il-plum-3: #6B21A8;  --il-plum-4: #581C87;
  --il-red: #EF4444;     --il-red-2: #B91C1C;   --il-red-3: #F87171;
  --il-ink: #1E293B;     --il-ink-2: #334155;   --il-ink-3: #475569;   --il-ink-4: #0F172A;
  --il-wood: #78350F;    --il-gold: #FDE68A;    --il-gold-2: #FBBF24;
  --il-white: #FFFFFF;
}

/* ---- illustration panel (floats seamlessly inside card body) ---- */
.itin-card-illus {
  position: absolute; right: 20px; bottom: 18px; top: 0;
  width: 48%; max-width: 290px; pointer-events: none; z-index: 1;
  display: flex; align-items: flex-end; justify-content: flex-end;
  background: transparent; border: none; overflow: hidden;
  /* Dissolved into the card at both ends. The drawing's hills run past the
     bottom of its own frame, so without this the fill is clipped into a
     straight line — floating above the card if the panel is inset, welded to
     the corner if it is not. Faded, it simply stops. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 26%, #000 86%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 26%, #000 86%, transparent 100%);
}

/* Sized by its own proportions and stood on the card's bottom edge. Stretching
   it to the full height instead letterboxed it — the drawing stopped short of
   the card in a straight line, which read as a box sitting in the white. */
.itin-illus-svg {
  width: 100%; height: auto; display: block;
}

/* The fetched subject. Only the glyph's shape is used — it is filled with the
   page's own gradient, so it belongs to the theme rather than importing one,
   and a file from another server never becomes markup. */
.itin-illus-subject {
  position: absolute; bottom: 21%; left: 16px;
  width: 104px; height: 104px; display: block; pointer-events: none;
  background: linear-gradient(150deg, var(--itin-violet), var(--itin-pink));
  -webkit-mask: var(--subject) center / contain no-repeat;
  mask: var(--subject) center / contain no-repeat;
  opacity: 0.95;
}
/* Painted in the colour the drawn scene used for the same thing — a torii is
   vermilion, a bus sign is violet — rather than one gradient for everything.
   The tokens are the illustrations' own, so this follows the theme too. */
.itin-card-illus[data-category="transit"]  .itin-illus-subject { background: linear-gradient(150deg, var(--il-violet), var(--il-violet-2)); }
.itin-card-illus[data-category="shrine"]   .itin-illus-subject { background: linear-gradient(150deg, var(--il-red-3), var(--il-red-2)); }
.itin-card-illus[data-category="mountain"] .itin-illus-subject { background: linear-gradient(150deg, var(--il-violet-3), var(--il-violet-2)); }
.itin-card-illus[data-category="water"]    .itin-illus-subject { background: linear-gradient(150deg, var(--il-sky), var(--il-sky-3)); }
:root[data-theme="light"] .itin-illus-subject { opacity: 0.9; }

/* ---- the leg, held against the spine ---- */
.itin-gutter { padding-left: 0; }
/* Set just off the spine and hung below the icon rather than beside it, so the
   leg reads as a note on the timeline instead of a second column. */
.itin-leg-line {
  display: flex; flex-direction: column;
  gap: 3px; min-height: 40px;
  margin-left: -12px; padding: 64px 0 18px;
}
.itin-leg-mode { font-weight: 700; letter-spacing: 0.15em; text-transform: uppercase; font-size: 10.5px; color: #A78BFA; }
:root[data-theme="light"] .itin-leg-mode { color: var(--itin-violet); }
.itin-leg-figs { font-variant-numeric: tabular-nums; font-weight: 500; font-size: 13px; color: var(--itin-dim); }
.itin-leg-figs + .itin-leg-figs::before { content: '\2022\00a0'; }
.itin-leg-same { font-style: italic; font-size: 12.5px; color: var(--itin-dim); }

/* ---- a stop the walk only passes ---- */
.itin-row.is-optional .itin-node {
  width: 26px; height: 26px; font-size: 12px;
  background: transparent; color: #A78BFA;
  border: 2px dashed color-mix(in srgb, var(--itin-violet) 55%, transparent);
  box-shadow: none;
}
.itin-side {
  display: flex; align-items: center; gap: 16px; margin: 0 0 44px;
  padding: 14px 20px; border-radius: 16px;
  background: rgba(20, 20, 30, 0.55);
  border: 1px dashed var(--itin-line);
  transition: border-color .2s ease, transform .18s ease;
}
:root[data-theme="light"] .itin-side { background: rgba(255, 255, 255, 0.45); border-color: rgba(100, 80, 150, 0.16); }
.itin-side:hover { border-color: color-mix(in srgb, var(--itin-violet) 38%, transparent); transform: translateX(3px); }
.itin-side-img { width: 62px; height: 62px; flex: 0 0 auto; border-radius: 12px; object-fit: cover; display: block; background: rgba(255,255,255,0.04); }
.itin-side-img.is-empty { display: flex; align-items: center; justify-content: center; color: var(--itin-dim); }
.itin-side-img.is-empty svg { width: 20px; height: 20px; }
.itin-side-body { min-width: 0; flex: 1; }
.itin-side-title { margin: 0; font-size: 15.5px; font-weight: 600; color: var(--itin-ink); line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.itin-side-note { margin: 4px 0 0; font-size: 12.5px; color: var(--itin-dim); line-height: 1.5; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.itin-side-tag {
  flex: 0 0 auto; font-size: 9.5px; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase;
  color: #34D399; padding: 4px 10px; border-radius: 999px;
  background: color-mix(in srgb, var(--itin-green) 15%, transparent);
}
.itin-side-map { flex: 0 0 auto; background: none; border: none; box-shadow: none; padding: 6px; color: var(--itin-dim); cursor: pointer; min-width: auto; height: auto; }
.itin-side-map svg { width: 17px; height: 17px; display: block; }
.itin-side-map:hover { color: #A78BFA; transform: none; box-shadow: none; background: none; }

/* ---- the map a stop opens into ---- */
.itin-map-box { max-width: 940px; }
#itin-map { width: 100%; height: 470px; border-radius: 16px; overflow: hidden; border: 1px solid var(--itin-line); }
.itin-map-foot { margin-top: 12px; font-size: 13px; line-height: 1.6; color: var(--itin-dim); }
.itin-pin {
  width: 32px; height: 32px; border-radius: 50%; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700; color: #fff; background: var(--itin-grad);
  border: 2.5px solid #fff; box-shadow: 0 3px 10px rgba(0,0,0,0.35);
}
.itin-pin.is-optional { width: 22px; height: 22px; font-size: 10px; background: var(--itin-green); border-width: 2px; }

@media (prefers-reduced-motion: reduce) {
  .itin-kicker, .itin-title, .itin-subtitle, .itin-title-rule, .itin-summary, .itin-hero-bar,
  .itin-row.is-in .itin-content, .itin-row.is-in .itin-node, .itin-row.is-in .itin-node::after,
  .itin-row.is-in .itin-mode, .itin-row.is-in .itin-mode svg { animation: none; }
  .itin-card:hover .itin-card-img { transform: none; }
  .itin-art img { transition: none; }
}

/* Tablet: the card stays horizontal, everything gives a little ground. */
@media (max-width: 1100px) {
  .itin-card { grid-template-columns: 300px 1fr 180px; }
  .itin-card-img { min-height: 280px; }
  .itin-card-body { padding: 30px; }
  .itin-card-title { font-size: 24px; }
  .itin-row { grid-template-columns: 48px 88px 1fr; }
  .itin-sheet { padding: 34px 28px 40px; }
}

/* Mobile: the card stacks, the spine narrows to a rail, nothing overflows. */
@media (max-width: 760px) {
  .itin-hero { min-height: 500px; }
  .itin-hero-inner { padding: 18px 18px 90px; }
  .itin-hero-bar { margin-bottom: 32px; }
  .itin-stat { padding: 4px 18px; }
  .itin-stat:first-child { padding-left: 0; }
  .itin-main { padding: 0 14px 80px; }
  .itin-sheet { margin-top: -62px; padding: 24px 16px 30px; border-radius: 24px; }
  /* Two columns now. The gutter and the card share the second one — a row only
     ever fills one of them — so the walk still shows rather than being hidden
     along with the column it used to sit in. */
  .itin-row { grid-template-columns: 38px 1fr; }
  .itin-gutter, .itin-content { grid-column: 2; }
  .itin-gutter { padding-left: 10px; }
  .itin-leg-line { margin-left: 0; padding: 18px 0; }
  .itin-node { width: 36px; height: 36px; font-size: 13px; }
  .itin-mode { width: 30px; height: 30px; }
  .itin-card { grid-template-columns: 1fr; margin-bottom: 32px; }
  .itin-card-illus { display: none; }  /* Hidden on mobile — not enough room */
  .itin-card-img { min-height: 210px; }
  .itin-card-body { padding: 24px; }
  .itin-card-title { font-size: 21px; }
  .itin-side { margin-bottom: 32px; padding: 12px 14px; gap: 12px; }
  .itin-side-tag { display: none; }
  #itin-map { height: 320px; }
}
