/* CFMA Tools Portal — visual identity built around the CFMA triangle mark
 * and the survey/aviation brand palette. Tiles use real app icons and a
 * per-tile accent colour so the dashboard feels less like a list and more
 * like an instrument panel. */
:root {
  --ink: #263441;
  --ink-deep: #1a2530;
  --ink-soft: #3b4d5e;
  --charcoal: #343434;
  --cream: #f8eacf;
  --cream-soft: #fbf6ec;
  --amber: #dea027;
  --amber-light: #e7b34a;
  --amber-dark: #b8821a;
  --survey-green: #2c4035;
  --white: #ffffff;
  --rule: #e6dccc;
  --rule-strong: #c9bca6;
  --surface: #ffffff;
  --shadow-sm: 0 1px 2px rgba(38, 52, 65, 0.06);
  --shadow-md: 0 4px 16px rgba(38, 52, 65, 0.10);
  --shadow-lg: 0 12px 32px rgba(38, 52, 65, 0.18);
  --radius: 12px;
  --radius-sm: 8px;
  --radius-lg: 18px;
  --font: "Open Sans", "Segoe UI", system-ui, -apple-system, sans-serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.5;
  color: var(--charcoal);
  background:
    radial-gradient(1200px 600px at 80% -10%, rgba(222, 160, 39, 0.10), transparent 60%),
    radial-gradient(900px 500px at -10% 110%, rgba(44, 64, 53, 0.08), transparent 60%),
    var(--cream-soft);
  min-height: 100vh;
  /* Reserve room at the bottom of every page for the fixed Queenstown
     scenery so content never disappears underneath the mountains. */
  padding-bottom: 180px;
}

a { color: var(--ink); }
a:hover { color: var(--amber-dark); }

/* ── Top bar ───────────────────────────────────────────────── */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 28px;
  background: linear-gradient(180deg, var(--ink-deep) 0%, var(--ink) 100%);
  color: var(--white);
  border-bottom: 3px solid var(--amber);
  position: relative;
}
.topbar::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -3px;
  height: 3px;
  background: linear-gradient(90deg, var(--amber) 0%, var(--amber-light) 50%, var(--amber) 100%);
}
.brand { display: flex; align-items: center; gap: 14px; text-decoration: none; color: inherit; }
.brand-mark { width: 40px; height: 40px; flex: 0 0 auto; }
.brand-mark img { width: 100%; height: 100%; display: block; }
.brand-text { display: flex; flex-direction: column; line-height: 1.1; }
.brand-name {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  font-size: 17px;
  font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--cream);
}
.brand-version {
  display: inline-flex;
  align-items: center;
  height: 17px;
  padding: 0 6px;
  border: 1px solid rgba(222, 160, 39, 0.7);
  border-radius: 999px;
  background: rgba(222, 160, 39, 0.16);
  color: var(--amber-light);
  font-size: 10px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.brand-sub { font-size: 10.5px; color: rgba(248, 234, 207, 0.55); letter-spacing: 0.16em; text-transform: uppercase; margin-top: 3px; }
.topbar-right {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 13px;
  color: rgba(255,255,255,0.75);
}
.install-btn {
  color: var(--amber);
  text-decoration: none;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.04em;
  padding: 5px 12px;
  border: 1px solid rgba(222, 160, 39, 0.55);
  border-radius: 999px;
  background: rgba(222, 160, 39, 0.10);
  transition: background 0.15s;
}
.install-btn:hover { background: rgba(222, 160, 39, 0.20); color: var(--cream); }
.version { color: rgba(248, 234, 207, 0.45); font-variant-numeric: tabular-nums; font-size: 11px; }
.who { padding: 4px 10px; border: 1px solid rgba(255,255,255,0.2); border-radius: 999px; }

/* ── Layout ────────────────────────────────────────────────── */
.container {
  max-width: 1200px;
  width: 100%;
  margin: 0 auto;
  /* Big bottom padding so the last section never disappears behind the
     fixed Queenstown scenery. Matches the scenery height + breathing room. */
  padding: 44px 28px 220px;
}

/* ── Hero / intro ──────────────────────────────────────────── */
.intro {
  position: relative;
  margin-bottom: 36px;
  padding: 28px 28px 26px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.95) 0%, rgba(255,255,255,0.75) 100%),
    radial-gradient(400px 200px at 100% 0%, rgba(222, 160, 39, 0.15), transparent 70%);
  border: 1px solid var(--rule);
  border-left: 4px solid var(--amber);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.intro::before {
  content: "";
  position: absolute;
  top: -40px; right: -20px;
  width: 160px; height: 160px;
  background: url("/icons/cfma-mark.svg") no-repeat center/contain;
  opacity: 0.08;
  pointer-events: none;
}
.intro h1 {
  font-size: 32px;
  margin: 0 0 6px;
  color: var(--ink);
  font-weight: 800;
  letter-spacing: -0.01em;
  position: relative;
}
.intro .lede {
  margin: 0;
  color: var(--ink-soft);
  font-size: 15px;
  position: relative;
  max-width: 680px;
}
.section-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--amber-dark);
  font-weight: 700;
  margin-bottom: 16px;
  padding: 4px 12px;
  background: rgba(222, 160, 39, 0.10);
  border-radius: 999px;
  border: 1px solid rgba(222, 160, 39, 0.25);
}

/* ── Tool grid ─────────────────────────────────────────────── */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 18px;
}
.tile {
  --tile-accent: var(--amber);
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 22px 22px 18px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--charcoal);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
  box-shadow: var(--shadow-sm);
  min-height: 170px;
  overflow: hidden;
  isolation: isolate;
}
.tile::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, var(--tile-accent) 0%, transparent 60%);
  opacity: 0.04;
  z-index: -1;
  transition: opacity 0.2s ease;
}
.tile::after {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--tile-accent), transparent 85%);
  opacity: 0;
  transition: opacity 0.2s ease;
}
.tile:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-lg);
  border-color: var(--tile-accent);
}
.tile:hover::before { opacity: 0.10; }
.tile:hover::after  { opacity: 1; }

.tile-icon {
  width: 64px; height: 64px;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--cream) 0%, var(--cream-soft) 100%);
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  margin-bottom: 16px;
  font-size: 22px;
  font-weight: 700;
  color: var(--ink);
  flex: 0 0 auto;
  transition: transform 0.2s ease, border-color 0.2s ease;
}
.tile-icon-img {
  width: 44px;
  height: 44px;
  display: block;
  object-fit: contain;
  transition: transform 0.25s ease;
}
.tile:hover .tile-icon { border-color: var(--tile-accent); }
.tile:hover .tile-icon-img { transform: scale(1.06) rotate(-2deg); }

.tile-name {
  font-size: 16px;
  font-weight: 800;
  color: var(--ink);
  margin: 0 0 4px;
  letter-spacing: -0.005em;
}

/* Status badge inline with the tile name — "Beta", "Alpha", "New", etc.
 * Designed to be eye-catching: solid bright fill, white text, soft glow,
 * subtle pulse animation. Five tones: amber (default), red, green, ink, gray. */
.tile-badge {
  display: inline-block;
  vertical-align: middle;
  margin: -3px 0 0 9px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.2;
  border: 1px solid transparent;
  white-space: nowrap;
  color: #fff;
  text-shadow: 0 1px 0 rgba(0,0,0,0.10);
  box-shadow:
    0 1px 0 rgba(255,255,255,0.25) inset,
    0 1px 4px rgba(38,52,65,0.18),
    0 0 0 3px var(--tile-badge-glow, rgba(222, 160, 39, 0.20));
  animation: tile-badge-pulse 2.4s ease-in-out infinite;
}
.tile-badge-amber {
  background: linear-gradient(180deg, #ecb44a 0%, #c98a17 100%);
  border-color: #a87411;
  --tile-badge-glow: rgba(222, 160, 39, 0.30);
}
.tile-badge-red {
  background: linear-gradient(180deg, #c5634d 0%, #8e2f1f 100%);
  border-color: #6a1f12;
  --tile-badge-glow: rgba(176, 74, 58, 0.30);
}
.tile-badge-green {
  background: linear-gradient(180deg, #4a6b54 0%, #2c4035 100%);
  border-color: #1c2c22;
  --tile-badge-glow: rgba(44, 64, 53, 0.30);
}
.tile-badge-ink {
  background: linear-gradient(180deg, #3b4d5e 0%, #1a2530 100%);
  border-color: #0e1820;
  --tile-badge-glow: rgba(38, 52, 65, 0.30);
}
.tile-badge-gray {
  background: linear-gradient(180deg, #b7ad9c 0%, #8b8273 100%);
  border-color: #6e6657;
  --tile-badge-glow: rgba(110, 102, 87, 0.28);
}

@keyframes tile-badge-pulse {
  0%, 100% { box-shadow:
    0 1px 0 rgba(255,255,255,0.25) inset,
    0 1px 4px rgba(38,52,65,0.18),
    0 0 0 3px var(--tile-badge-glow); }
  50% { box-shadow:
    0 1px 0 rgba(255,255,255,0.25) inset,
    0 2px 6px rgba(38,52,65,0.22),
    0 0 0 6px var(--tile-badge-glow); }
}

@media (prefers-reduced-motion: reduce) {
  .tile-badge { animation: none; }
}
.tile-version {
  width: fit-content;
  margin: -1px 0 8px;
  padding: 2px 7px;
  border: 1px solid color-mix(in srgb, var(--tile-accent) 38%, var(--rule));
  border-radius: 999px;
  background: color-mix(in srgb, var(--tile-accent) 10%, #fffdf8);
  color: color-mix(in srgb, var(--tile-accent) 58%, var(--ink));
  font-size: 10.5px;
  font-weight: 800;
  line-height: 1.25;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.tile-desc {
  font-size: 13px;
  color: var(--ink-soft);
  margin: 0;
  flex: 1;
  line-height: 1.45;
}
.tile-meta {
  display: flex; gap: 6px; margin-top: 14px;
  font-size: 10.5px; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700;
}
.tile-chip {
  padding: 3px 9px;
  background: var(--cream-soft);
  border: 1px solid var(--rule);
  border-radius: 999px;
}
.tile-chip.live {
  background: rgba(44, 64, 53, 0.08);
  border-color: rgba(44, 64, 53, 0.25);
  color: var(--survey-green);
}
.tile-chip.soon {
  background: rgba(222, 160, 39, 0.10);
  border-color: rgba(222, 160, 39, 0.30);
  color: var(--amber-dark);
}
.tile.placeholder { opacity: 0.65; cursor: default; }
.tile.placeholder:hover { transform: none; border-color: var(--rule); box-shadow: var(--shadow-sm); }
.tile.placeholder:hover::before { opacity: 0.04; }
.tile.placeholder:hover::after  { opacity: 0; }

/* ── Tile feedback button ──────────────────────────────────── */
.tile-feedback {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1px solid var(--rule);
  background: rgba(255, 255, 255, 0.85);
  color: var(--ink-soft);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.55;
  transition: opacity 0.15s, background 0.15s, border-color 0.15s, transform 0.15s;
  padding: 0;
  z-index: 2;
}
.tile-feedback:hover {
  opacity: 1;
  background: var(--cream);
  border-color: var(--amber);
  color: var(--amber-dark);
  transform: scale(1.08);
}
.tile-feedback:focus-visible {
  opacity: 1;
  outline: 2px solid var(--amber);
  outline-offset: 2px;
}
.tile-feedback svg { display: block; }

/* ── Feedback modal ────────────────────────────────────────── */
.feedback-modal {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.feedback-modal.open { display: flex; }
.feedback-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(26, 37, 48, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.feedback-card {
  position: relative;
  max-width: 480px;
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 26px 26px 22px;
  box-shadow: var(--shadow-lg);
  max-height: calc(100vh - 48px);
  overflow-y: auto;
}
.feedback-close {
  position: absolute;
  top: 10px;
  right: 12px;
  background: transparent;
  border: 0;
  font: 600 22px/1 system-ui;
  color: var(--ink-soft);
  cursor: pointer;
  width: 28px;
  height: 28px;
  border-radius: 50%;
}
.feedback-close:hover { background: var(--cream-soft); color: var(--ink); }
.feedback-heading {
  font-size: 20px;
  font-weight: 800;
  color: var(--ink);
  margin: 0 0 4px;
  letter-spacing: -0.01em;
}
.feedback-sub { margin: 0 0 18px; color: var(--ink-soft); font-size: 13px; }

.feedback-types {
  border: 0;
  padding: 0;
  margin: 0 0 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.feedback-types legend {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  color: var(--amber-dark);
  font-weight: 700;
  margin-bottom: 8px;
}
.feedback-types label {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 10px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 14px;
  transition: border-color 0.15s, background 0.15s;
}
.feedback-types label:hover { border-color: var(--amber); background: var(--cream-soft); }
.feedback-types input { accent-color: var(--amber); }

.feedback-field { display: block; margin-bottom: 14px; }
.feedback-field span {
  display: block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  color: var(--amber-dark);
  font-weight: 700;
  margin-bottom: 6px;
}
.feedback-field textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  font: inherit;
  font-size: 14px;
  color: var(--charcoal);
  resize: vertical;
  min-height: 90px;
  background: var(--cream-soft);
}
.feedback-field textarea:focus {
  outline: none;
  border-color: var(--amber);
  background: var(--white);
}

.feedback-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 8px; }
.feedback-btn-secondary,
.feedback-btn-primary {
  padding: 8px 16px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--rule);
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.feedback-btn-secondary { background: var(--white); color: var(--ink-soft); }
.feedback-btn-secondary:hover { background: var(--cream-soft); }
.feedback-btn-primary { background: var(--ink); color: var(--cream); border-color: var(--ink); }
.feedback-btn-primary:hover { background: var(--amber-dark); border-color: var(--amber-dark); color: var(--white); }
.feedback-fineprint { margin: 10px 0 0; font-size: 11px; color: var(--ink-soft); text-align: right; }


/* ── Meta block ────────────────────────────────────────────── */
.meta {
  margin-top: 44px;
  padding: 22px 26px;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}
.meta h2 {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--amber-dark);
  margin: 0 0 10px;
  font-weight: 700;
}
.meta p { margin: 0; color: var(--charcoal); font-size: 14px; }

/* ── Footer ────────────────────────────────────────────────── */
.footer {
  padding: 14px 28px;
  background: var(--ink-deep);
  color: rgba(255,255,255,0.65);
  font-size: 12px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.footer-right { display: flex; gap: 14px; align-items: center; }
.footer a { color: var(--amber); text-decoration: none; }
.footer a:hover { color: var(--cream); }
.version { color: rgba(255,255,255,0.4); font-variant-numeric: tabular-nums; }

/* ── Surveyor mascot ───────────────────────────────────────── */
/* A tiny CFMA surveyor in a hi-vis vest walks back and forth along the
   bottom of the page with his total station tripod. Pure CSS + SVG. */
.surveyor-strip {
  /* Locked to the bottom of the viewport so it sits behind everything
     else as the page's permanent landscape backdrop. */
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 180px;
  margin: 0;
  padding: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
  /* Soft fade at the top of the scene so the mountains feel like they
     emerge from the page rather than starting with a hard line. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 28px);
          mask-image: linear-gradient(to bottom, transparent 0, #000 28px);

  /* === Default (day) variant tokens ===
     These cover the SVG gradients (via var() inside <stop>) and the new
     animated elements. Each [data-variant="…"] override below replaces
     the palette so the same DOM re-tints from sunrise to snow. */
  --qt-sky-top:     #e9ecdc;
  --qt-sky-mid:     #f4ecd8;
  --qt-sky-bot:     #fbf6ec;
  --qt-mtn-top:     #6b7783;
  --qt-mtn-bot:     #4d5a66;
  --qt-walter-top:  #7e8a78;
  --qt-walter-bot:  #5d6a58;
  --qt-lake-top:    #3d6b80;
  --qt-lake-bot:    #2e5468;
  --qt-fore-top:    #7a8a6b;
  --qt-fore-bot:    #576848;
  --qt-snow:        #f8eacf;
  --qt-snow-op:     0.9;
  --qt-celestial:       #f4d27a;
  --qt-celestial-glow:  #f4d27a;
  --qt-celestial-op:    0.85;
  --qt-cable:       #263441;
  --qt-station:     #263441;
  --qt-gondola-fill:#dea027;
  --qt-snowfall-op: 0;       /* hidden in non-snow variants */
}

/* Golden hour — warm, low sun, amber sky. */
.surveyor-strip[data-variant="golden"] {
  --qt-sky-top:    #f6a35a;
  --qt-sky-mid:    #f8c98a;
  --qt-sky-bot:    #fde4c0;
  --qt-mtn-top:    #6d4e3c;
  --qt-mtn-bot:    #4a3225;
  --qt-walter-top: #8a6850;
  --qt-walter-bot: #5e4632;
  --qt-lake-top:   #d28e54;
  --qt-lake-bot:   #8f5a30;
  --qt-fore-top:   #8a6e48;
  --qt-fore-bot:   #5a432a;
  --qt-snow:       #fde0b0;
  --qt-snow-op:    0.85;
  --qt-celestial:      #f9c25a;
  --qt-celestial-glow: #ffb070;
  --qt-celestial-op:   0.95;
}

/* Blue dawn — cool, soft pink-into-blue. */
.surveyor-strip[data-variant="dawn"] {
  --qt-sky-top:    #6f7da6;
  --qt-sky-mid:    #b3b6c5;
  --qt-sky-bot:    #e7d6c8;
  --qt-mtn-top:    #4e5872;
  --qt-mtn-bot:    #2c344a;
  --qt-walter-top: #5e6a82;
  --qt-walter-bot: #444f66;
  --qt-lake-top:   #4f6a8a;
  --qt-lake-bot:   #2e3e58;
  --qt-fore-top:   #56697e;
  --qt-fore-bot:   #38475a;
  --qt-snow:       #e8e6f0;
  --qt-snow-op:    0.85;
  --qt-celestial:      #f6cdb0;   /* pale rising sun */
  --qt-celestial-glow: #f0a890;
  --qt-celestial-op:   0.7;
}

/* Snow weather — overcast grey, lots of snow, falling flakes. */
.surveyor-strip[data-variant="snow"] {
  --qt-sky-top:    #b8c1cb;
  --qt-sky-mid:    #d2d8de;
  --qt-sky-bot:    #e6e9ec;
  --qt-mtn-top:    #6e7a85;
  --qt-mtn-bot:    #485058;
  --qt-walter-top: #8b939c;
  --qt-walter-bot: #686f78;
  --qt-lake-top:   #485e74;
  --qt-lake-bot:   #2e3c4a;
  --qt-fore-top:   #98a098;
  --qt-fore-bot:   #6a746a;
  --qt-snow:       #ffffff;
  --qt-snow-op:    1;
  --qt-celestial:      #d8dde2;   /* sun hidden behind cloud */
  --qt-celestial-glow: #ffffff;
  --qt-celestial-op:   0.45;
  --qt-snowfall-op: 1;
}

/* Ensure interactive content sits in front of the scenery. */
.topbar, .container { position: relative; z-index: 2; }
.surveyor-hills {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  width: 100%;
  height: 100%;
}
.tree {
  position: absolute;
  bottom: 8px;
  transform: translateX(-50%);
  z-index: 1;
}
.tree svg { display: block; }
/* Blocker tree rustles each time the surveyor's anger flares. */
.tree-blocker { animation: tree-blocker-shake 100s ease-in-out infinite; transform-origin: bottom center; }
@keyframes tree-blocker-shake {
  0%, 100% { transform: translateX(-50%) rotate(0); }
  5.8%, 22.2%, 38.5% { transform: translateX(-50%) rotate(-1.2deg); }
  8.5%, 25%,   41.2% { transform: translateX(-50%) rotate(1.2deg); }
  11.5%, 28%, 44.5% { transform: translateX(-50%) rotate(-1.2deg); }
  47.5% { transform: translateX(-50%) rotate(-2deg); }   /* big shake right before trip */
  49.5% { transform: translateX(-50%) rotate(2deg); }
}
.surveyor-ground {
  position: absolute;
  left: 0; right: 0; bottom: 8px;
  height: 1px;
  z-index: 1;
  background: repeating-linear-gradient(
    90deg,
    rgba(38, 52, 65, 0.22) 0,
    rgba(38, 52, 65, 0.22) 6px,
    transparent 6px,
    transparent 12px
  );
}
.surveyor,
.surveyor-tripod {
  position: absolute;
  bottom: 8px;                     /* feet/tripod tip sit on the ground line */
  transform-origin: bottom center;
  will-change: transform, left;
  z-index: 2;                      /* in front of hills + trees */
}
.surveyor-tripod {
  /* Total station planted near the left edge — the rod-man walks
     across the rest of the strip and stops to shoot at points. */
  left: 8%;
}
.surveyor {
  left: 14%;                       /* starts just right of the tripod */
  animation: surveyor-walk 100s cubic-bezier(.4,0,.4,1) infinite;
  pointer-events: auto;            /* clickable inside the otherwise-passive strip */
  cursor: grab;
  touch-action: none;              /* don't scroll when the user drags him on touch */
}
.surveyor.is-grabbed { cursor: grabbing; }
.surveyor svg, .surveyor-tripod svg { display: block; }
.surveyor-pose { display: inline-block; transform-origin: bottom center; }

/* Walk cycle timings — sinusoidal easing on a 0.6s stride. The bob layers
 * a 2× vertical bounce, lateral sway toward the planted foot, and a small
 * constant forward lean for a more lifelike gait. */
.surveyor-pose  { animation: surveyor-bob   0.6s cubic-bezier(.45,.05,.55,.95) infinite; }
.surveyor-leg-l { transform-origin: 13px 38px; animation: surveyor-leg-l 0.6s cubic-bezier(.45,.05,.55,.95) infinite; }
.surveyor-leg-r { transform-origin: 19px 38px; animation: surveyor-leg-r 0.6s cubic-bezier(.45,.05,.55,.95) infinite; }
.surveyor-arm   { transform-origin: 10px 24px; animation: surveyor-arm   0.6s cubic-bezier(.45,.05,.55,.95) infinite; }
/* Lower legs bend at the knee during their respective swing half — Left
 * during 0-50% of the stride, Right during 50-100%. Stance phase stays
 * straight so the planted foot reads cleanly. */
.surveyor-lower-l { transform-origin: 12.5px 45px; animation: surveyor-knee-l 0.6s cubic-bezier(.45,.05,.55,.95) infinite; }
.surveyor-lower-r { transform-origin: 19.5px 45px; animation: surveyor-knee-r 0.6s cubic-bezier(.45,.05,.55,.95) infinite; }

/* Prism reflector + TS beam pulse on each shot beat across the 5 patrols. */
.prism-spark { animation: prism-spark 100s linear infinite; transform-origin: 34px 14px; }
.ts-beam { animation: ts-beam 100s linear infinite; }

/* The prism rod inside the surveyor SVG fades out during the throw beat
 * (80%), stays gone while he walks off, then resets on loop. */
.surveyor-rod { animation: surveyor-rod-fade 100s linear infinite; }

/* Flying rod — cartwheels up and into the lake on a parabolic arc.
 * Positions are percentages of the strip so it lands in the lake band
 * regardless of strip height (mobile uses a shorter strip). */
.surveyor-flying-rod {
  position: absolute;
  left: 78%;
  bottom: 18%;        /* starts near his hand height */
  transform-origin: center;
  opacity: 0;
  animation: surveyor-flying-rod 100s linear infinite;
  z-index: 3;
}

/* Splash sits in the blue Lake Wakatipu band (~17% from the bottom of
 * the strip, which lines up with the lake graphic). */
.surveyor-splash {
  position: absolute;
  left: 35%;
  bottom: 17%;
  transform: translateX(-50%) scale(0.4);
  opacity: 0;
  animation: surveyor-splash 100s linear infinite;
  z-index: 1;         /* under the foreground hills so it reads as ON the lake */
}

/* Dust puff at the moment of impact. */
.surveyor-dust {
  position: absolute;
  left: 64%;
  bottom: 4px;
  transform: translateX(-50%);
  opacity: 0;
  animation: surveyor-dust 100s linear infinite;
  z-index: 2;
}

/* Dazed stars circling above his head while he's lying down. */
.surveyor-stars {
  position: absolute;
  left: 64%;
  bottom: 28px;
  transform: translateX(-50%);
  opacity: 0;
  animation: surveyor-stars-show 100s linear infinite;
  z-index: 3;
  pointer-events: none;
}
.surveyor-star { transform-origin: center; }
.surveyor-star-1 { animation: surveyor-star-spin 1.8s linear infinite; }
.surveyor-star-2 { animation: surveyor-star-spin 1.4s linear infinite reverse; }
.surveyor-star-3 { animation: surveyor-star-spin 2.2s linear infinite; }

/* When the surveyor is in his fallen state, completely stop every limb /
   bob / arm-swing animation AND reset their transforms to neutral, so he
   doesn't look "frozen mid-stride" — he goes limp on the ground. The JS
   adds .is-fallen between cycle beats 38% and 65%. */
.surveyor.is-fallen .surveyor-pose,
.surveyor.is-fallen .surveyor-leg-l,
.surveyor.is-fallen .surveyor-leg-r,
.surveyor.is-fallen .surveyor-lower-l,
.surveyor.is-fallen .surveyor-lower-r,
.surveyor.is-fallen .surveyor-arm {
  animation: none !important;
}
/* Keep the knee straight while he's lying on the ground. */
.surveyor.is-fallen .surveyor-lower-l,
.surveyor.is-fallen .surveyor-lower-r { transform: rotate(0deg) !important; }
/* Splay the legs apart so it's visually unambiguous that he's
   sprawled on the ground, not mid-stride. The free arm flops out
   too. */
.surveyor.is-fallen .surveyor-leg-l { transform: rotate(-26deg) !important; }
.surveyor.is-fallen .surveyor-leg-r { transform: rotate(26deg)  !important; }
.surveyor.is-fallen .surveyor-arm   { transform: rotate(-32deg) !important; }
.surveyor.is-fallen .surveyor-pose  { transform: translateY(0)  !important; }

/* ── Click reaction ─────────────────────────────────────────
 * Tap the surveyor and he trips, lies dazed, gets up, then shakes his
 * pole in the air in rage. Driven by JS adding/removing .is-tripped.
 * The parent's walk animation is paused so he stays where he is; all
 * the motion happens on the pose / limbs / rod inside him. */
.surveyor.is-tripped {
  animation-play-state: paused;     /* freeze x position and facing */
}
.surveyor.is-tripped .surveyor-pose {
  animation: surveyor-click-trip 4s ease-in-out forwards !important;
}
.surveyor.is-tripped .surveyor-leg-l {
  animation: surveyor-click-leg-l 4s ease-in-out forwards !important;
}
.surveyor.is-tripped .surveyor-leg-r {
  animation: surveyor-click-leg-r 4s ease-in-out forwards !important;
}
.surveyor.is-tripped .surveyor-arm {
  animation: surveyor-click-arm 4s ease-in-out forwards !important;
}
/* Legs stay rigid (no knee bend) throughout the trip / rage sequence. */
.surveyor.is-tripped .surveyor-lower-l,
.surveyor.is-tripped .surveyor-lower-r {
  animation: none !important;
  transform: rotate(0deg);
}
.surveyor.is-tripped .surveyor-rod {
  animation: surveyor-pole-shake 0.14s ease-in-out 12 !important;
  animation-delay: 2.5s !important;
  animation-fill-mode: both !important;
  transform-origin: 34px 38px;
}
.surveyor.is-tripped .surveyor-anger {
  animation: surveyor-click-anger 4s ease-in-out forwards !important;
}

@keyframes surveyor-click-trip {
  /* Trip + faceplant (0-12%) */
  0%   { transform: rotate(0deg)  translateY(0); }
  4%   { transform: rotate(-8deg) translateY(-3px); }
  7%   { transform: rotate(30deg) translateY(2px); }
  10%  { transform: rotate(62deg) translateY(8px); }
  12%  { transform: rotate(88deg) translateY(15px); }
  /* Lying dazed (12-50%) */
  50%  { transform: rotate(88deg) translateY(15px); }
  /* Get up (50-62%) */
  54%  { transform: rotate(55deg) translateY(9px); }
  58%  { transform: rotate(25deg) translateY(3px); }
  62%  { transform: rotate(0deg)  translateY(0); }
  /* Rage shake — body wobbles while he shakes the pole (62-100%) */
  66%  { transform: rotate(-3deg) translateY(0); }
  70%  { transform: rotate(3deg)  translateY(-1px); }
  74%  { transform: rotate(-4deg) translateY(0); }
  78%  { transform: rotate(4deg)  translateY(-1px); }
  82%  { transform: rotate(-3deg) translateY(0); }
  86%  { transform: rotate(3deg)  translateY(-1px); }
  90%  { transform: rotate(-2deg) translateY(0); }
  100% { transform: rotate(0deg)  translateY(0); }
}

/* Legs splay during the fall, return to a stomp-stance while raging. */
@keyframes surveyor-click-leg-l {
  0%        { transform: rotate(-15deg); }
  12%, 50%  { transform: rotate(-26deg); }
  62%, 100% { transform: rotate(-8deg); }
}
@keyframes surveyor-click-leg-r {
  0%        { transform: rotate(15deg); }
  12%, 50%  { transform: rotate(26deg); }
  62%, 100% { transform: rotate(8deg); }
}
/* Free arm flops out during the fall, then raises like a furious fist
 * while the other hand shakes the pole. */
@keyframes surveyor-click-arm {
  0%        { transform: rotate(0deg); }
  12%, 50%  { transform: rotate(-32deg); }
  62%       { transform: rotate(-60deg); }
  66%, 100% { transform: rotate(-115deg); }
}

/* The pole itself shakes back and forth — rotates around his grip point. */
@keyframes surveyor-pole-shake {
  0%, 100% { transform: rotate(-16deg) translate(-1px, -1px); }
  50%      { transform: rotate(16deg)  translate(1px, -1px); }
}

/* Angry face shows during the rage phase. */
@keyframes surveyor-click-anger {
  0%, 58%  { opacity: 0; transform: scale(0.9); }
  64%      { opacity: 1; transform: scale(1.5); }
  92%      { opacity: 1; transform: scale(1.5); }
  100%     { opacity: 0; transform: scale(1); }
}

/* ── Drag-and-throw reaction ──────────────────────────────────
 * When the user grabs the surveyor, .is-interrupted pauses his walk and
 * disables all his looping limb / bob / rod / anger animations so the
 * JS can drive position via inline styles. Specific sub-states
 * (.is-grabbed, .is-flying, .in-water, .is-raging, .is-walking-out,
 * .is-storming) layer in the right poses and gaits on top. */
.surveyor.is-interrupted {
  animation-play-state: paused !important;
}
.surveyor.is-interrupted .surveyor-pose,
.surveyor.is-interrupted .surveyor-leg-l,
.surveyor.is-interrupted .surveyor-leg-r,
.surveyor.is-interrupted .surveyor-lower-l,
.surveyor.is-interrupted .surveyor-lower-r,
.surveyor.is-interrupted .surveyor-arm,
.surveyor.is-interrupted .surveyor-rod,
.surveyor.is-interrupted .surveyor-anger {
  animation: none !important;
}

/* Held mid-air: limbs flail out, the surveyor SVG spins around its
 * centre instead of its feet so he tumbles cleanly. */
.surveyor.is-flying {
  transform-origin: center !important;
  z-index: 5;
}
.surveyor.is-flying .surveyor-leg-l { transform: rotate(-18deg); }
.surveyor.is-flying .surveyor-leg-r { transform: rotate(20deg); }
.surveyor.is-flying .surveyor-arm   { transform: rotate(-95deg); }
.surveyor.is-flying .surveyor-lower-l,
.surveyor.is-flying .surveyor-lower-r { transform: rotate(0deg); }

/* Hit-ground tumble — splat for a beat, then reset clears the class. */
.surveyor.hit-ground .surveyor-leg-l { transform: rotate(-30deg); }
.surveyor.hit-ground .surveyor-leg-r { transform: rotate(30deg); }
.surveyor.hit-ground .surveyor-arm   { transform: rotate(-40deg); }
.surveyor.hit-ground .surveyor-lower-l,
.surveyor.hit-ground .surveyor-lower-r { transform: rotate(0deg); }

/* In the lake — bobbing on the surface. */
.surveyor.in-water .surveyor-pose {
  animation: surveyor-water-bob 0.55s ease-in-out infinite !important;
  transform-origin: bottom center;
}
@keyframes surveyor-water-bob {
  0%, 100% { transform: translateY(0)   rotate(-4deg); }
  50%      { transform: translateY(-2px) rotate(4deg); }
}

/* Raging — the angry overlay is glued on and pulsing. */
.surveyor.is-raging .surveyor-anger {
  opacity: 1 !important;
  animation: surveyor-rage-pulse 0.18s ease-in-out infinite alternate !important;
  transform-origin: 16px 19px;
}
@keyframes surveyor-rage-pulse {
  0%   { transform: scale(1.2); }
  100% { transform: scale(1.55); }
}

/* Wading out of the water toward the tripod — a brisk walking gait. */
.surveyor.is-walking-out .surveyor-pose {
  animation: surveyor-bob 0.36s cubic-bezier(.45,.05,.55,.95) infinite !important;
}
.surveyor.is-walking-out .surveyor-leg-l {
  animation: surveyor-leg-l 0.36s cubic-bezier(.45,.05,.55,.95) infinite !important;
}
.surveyor.is-walking-out .surveyor-leg-r {
  animation: surveyor-leg-r 0.36s cubic-bezier(.45,.05,.55,.95) infinite !important;
}
.surveyor.is-walking-out .surveyor-arm {
  animation: surveyor-arm 0.36s cubic-bezier(.45,.05,.55,.95) infinite !important;
}
.surveyor.is-walking-out .surveyor-lower-l {
  animation: surveyor-knee-l 0.36s cubic-bezier(.45,.05,.55,.95) infinite !important;
}
.surveyor.is-walking-out .surveyor-lower-r {
  animation: surveyor-knee-r 0.36s cubic-bezier(.45,.05,.55,.95) infinite !important;
}

/* Storming off — faster, angrier gait. */
.surveyor.is-storming .surveyor-pose {
  animation: surveyor-bob 0.28s cubic-bezier(.45,.05,.55,.95) infinite !important;
}
.surveyor.is-storming .surveyor-leg-l {
  animation: surveyor-leg-l 0.28s cubic-bezier(.45,.05,.55,.95) infinite !important;
}
.surveyor.is-storming .surveyor-leg-r {
  animation: surveyor-leg-r 0.28s cubic-bezier(.45,.05,.55,.95) infinite !important;
}
.surveyor.is-storming .surveyor-arm {
  animation: surveyor-arm 0.28s cubic-bezier(.45,.05,.55,.95) infinite !important;
}
.surveyor.is-storming .surveyor-lower-l {
  animation: surveyor-knee-l 0.28s cubic-bezier(.45,.05,.55,.95) infinite !important;
}
.surveyor.is-storming .surveyor-lower-r {
  animation: surveyor-knee-r 0.28s cubic-bezier(.45,.05,.55,.95) infinite !important;
}

/* Tripod knocked over — tips to the left and lies on the ground. */
.surveyor-tripod.is-knocked {
  animation: tripod-fall 0.7s cubic-bezier(0.3, 0, 0.7, 1.3) forwards;
  transform-origin: 50% 95%;
}
@keyframes tripod-fall {
  0%   { transform: rotate(0deg)   translate(0, 0); }
  40%  { transform: rotate(-85deg) translate(-8px, 4px); }
  60%  { transform: rotate(-96deg) translate(-13px, 6px); }
  80%  { transform: rotate(-88deg) translate(-11px, 8px); }
  100% { transform: rotate(-90deg) translate(-12px, 9px); }
}

/* One-shot splash that fires where he lands in the water. */
@keyframes surveyor-splash-once {
  0%   { opacity: 0;   transform: translateX(-50%) scale(0.4); }
  20%  { opacity: 1;   transform: translateX(-50%) scale(1.0); }
  55%  { opacity: 1;   transform: translateX(-50%) scale(1.7); }
  100% { opacity: 0;   transform: translateX(-50%) scale(2.6); }
}

/* One-shot rage pole-fling — he hurls the rod up and off to the right.
 * translate() is listed BEFORE rotate() so the rod travels along a clean
 * screen-space arc while spinning around its own centre. */
@keyframes surveyor-rage-pole-fling {
  0%   { opacity: 1; transform: translate(0,    0)     rotate(-30deg); }
  25%  { opacity: 1; transform: translate(40px, -80px) rotate(220deg); }
  50%  { opacity: 1; transform: translate(95px, -115px) rotate(440deg); }
  75%  { opacity: 1; transform: translate(155px, -55px) rotate(640deg); }
  100% { opacity: 0; transform: translate(225px, 95px) rotate(820deg); }
}

/* The big 90-second story arc:
 *   Patrol 1 (0-15%)   — walk through all three points and back
 *   Patrol 2 (15-37%)  — walk through them again, frustration building
 *   Trip   (37-43%)    — frustrated step forward, faceplant into the dirt
 *   Lying  (43-58%)    — sprawled on the ground feeling sorry for himself
 *   Get up (58-65%)    — pushes himself up, pole still in hand
 *   Throw  (65-67%)    — flings the pole onto the ground (rod fades, thrown
 *                        rod appears)
 *   Storm off (67-80%) — marches off the right side of the strip
 *   Gone (80-92%)      — off-screen for ~10 seconds
 *   Return (92-100%)   — reappears on the LEFT side and walks back to start
 *                        (rod opacity resets on next loop = picks up a fresh one)
 */
/* The big 100-second story arc:
 *   Patrols 1-3 (0-50%)  — walks back and forth THREE times (slower than
 *                          before so each patrol is more deliberate)
 *   Trip (50-52%)        — frustrated lunge forward, faceplant
 *   Lying (52-72%)       — out cold, legs/arms paused via .is-fallen
 *   Get up (72-76%)      — pushes himself upright
 *   Walks forward (76-79%) — stomps a few paces away from the spot
 *   Throws rod (79-82%)  — flings the pole up and into the lake
 *   Storms off (82-89%)  — marches off the right side
 *   Gone (89-97%)        — ~8s off-screen
 *   Return (97-100%)     — reappears from left, walks back to start
 */
@keyframes surveyor-walk {
  /* ── Patrol 1 (0-16.5%) — slow and deliberate ── */
  0%    { left: 14%; transform: scaleX(1) rotate(0) translateY(0); opacity: 1; }
  3%    { left: 38%; transform: scaleX(1); }   /* shot 1 */
  3.8%  { left: 38%; transform: scaleX(1); }
  5.8%  { left: 60%; transform: scaleX(1); }   /* shot 2 (angry) */
  6.5%  { left: 60%; transform: scaleX(1); }
  8.5%  { left: 86%; transform: scaleX(1); }   /* shot 3 (angry) */
  9.2%  { left: 86%; transform: scaleX(1); }
  9.7%  { left: 86%; transform: scaleX(-1); }  /* turn around */
  11.5% { left: 60%; transform: scaleX(-1); }
  12.2% { left: 60%; transform: scaleX(-1); }
  14%   { left: 38%; transform: scaleX(-1); }
  16%   { left: 14%; transform: scaleX(-1); }
  16.5% { left: 14%; transform: scaleX(1); }   /* turn forward */

  /* ── Patrol 2 (16.5-33%) ── */
  19.5% { left: 38%; transform: scaleX(1); }
  20.2% { left: 38%; transform: scaleX(1); }
  22.2% { left: 60%; transform: scaleX(1); }
  23%   { left: 60%; transform: scaleX(1); }
  25%   { left: 86%; transform: scaleX(1); }
  25.7% { left: 86%; transform: scaleX(1); }
  26.2% { left: 86%; transform: scaleX(-1); }
  28%   { left: 60%; transform: scaleX(-1); }
  28.7% { left: 60%; transform: scaleX(-1); }
  30.5% { left: 38%; transform: scaleX(-1); }
  32.5% { left: 14%; transform: scaleX(-1); }
  33%   { left: 14%; transform: scaleX(1); }

  /* ── Patrol 3 (33-50%) — really fuming, ends with the trip ── */
  36%   { left: 38%; transform: scaleX(1); }
  36.7% { left: 38%; transform: scaleX(1); }
  38.5% { left: 60%; transform: scaleX(1); }   /* angry */
  39.2% { left: 60%; transform: scaleX(1); }
  41.2% { left: 86%; transform: scaleX(1); }   /* angry */
  42%   { left: 86%; transform: scaleX(1); }
  42.5% { left: 86%; transform: scaleX(-1); }
  44.5% { left: 60%; transform: scaleX(-1); }  /* blocker tree in his face */
  45.5% { left: 60%; transform: scaleX(-1); }  /* fuming */
  47.5% { left: 55%; transform: scaleX(-1); }  /* steps closer to the tree */
  49%   { left: 55%; transform: scaleX(-1); }  /* glaring at it */
  49.5% { left: 55%; transform: scaleX(1) rotate(0) translateY(0); }  /* spins forward to attack */

  /* ── TRIP (50-52%) ── */
  50%   { left: 56%; transform: scaleX(1) rotate(0)     translateY(0); }
  50.5% { left: 58%; transform: scaleX(1) rotate(-8deg) translateY(-3px); }   /* off-balance */
  51%   { left: 60%; transform: scaleX(1) rotate(30deg) translateY(2px); }
  51.5% { left: 62%; transform: scaleX(1) rotate(62deg) translateY(8px); }
  52%   { left: 64%; transform: scaleX(1) rotate(88deg) translateY(15px); }   /* SLAMS flat and stays */

  /* ── LYING (52-72%) — out cold, no movement at all ── */
  53%   { left: 64%; transform: scaleX(1) rotate(88deg) translateY(15px); }
  72%   { left: 64%; transform: scaleX(1) rotate(88deg) translateY(15px); }

  /* ── GET UP (72-76%) ── */
  73%   { left: 64%; transform: scaleX(1) rotate(60deg) translateY(10px); }
  74%   { left: 64%; transform: scaleX(1) rotate(35deg) translateY(5px); }
  75%   { left: 64%; transform: scaleX(1) rotate(15deg) translateY(2px); }
  76%   { left: 64%; transform: scaleX(1) rotate(0deg)  translateY(0); }

  /* ── WALKS A LITTLE BIT (76-79%) ── */
  77%   { left: 70%; transform: scaleX(1) rotate(0) translateY(0); }
  78%   { left: 76%; transform: scaleX(1); }
  79%   { left: 78%; transform: scaleX(1); }

  /* ── THROWS POLE UP AND INTO THE LAKE (79-82%) — he stops, rod cocks
   *    back, then launches; pole arc animation is on a separate element. */
  79.5% { left: 78%; transform: scaleX(1); }
  82%   { left: 78%; transform: scaleX(1); }

  /* ── STORMS OFF the right side (82-89%) ── */
  85%   { left: 90%;  transform: scaleX(1); opacity: 1; }
  89%   { left: 110%; transform: scaleX(1); opacity: 1; }

  /* ── OFF-SCREEN (89-97%) — hidden via opacity so the teleport doesn't show ── */
  96.5% { left: 110%; transform: scaleX(1); opacity: 0; }
  97%   { left: -10%; transform: scaleX(1); opacity: 0; }

  /* ── RETURNS from the left (97-100%) ── */
  97.5% { left: -10%; transform: scaleX(1); opacity: 1; }
  100%  { left: 14%;  transform: scaleX(1) rotate(0) translateY(0); opacity: 1; }
}

@keyframes surveyor-rod-fade {
  0%, 78%   { opacity: 1; }
  79%       { opacity: 1; transform: rotate(-12deg); transform-origin: 34px 30px; } /* cocks back */
  79.5%     { opacity: 1; transform: rotate(-30deg); }                              /* big windup */
  80%       { opacity: 0; transform: rotate(0deg); }                                /* gone — pole is now in the air */
  97%       { opacity: 0; }
  100%      { opacity: 1; }                                                          /* fresh rod on return */
}

/* Flying rod — parabolic arc from his hand up high over the foreground
 * and down into the blue lake band. Positions are percentages of the
 * strip so the trajectory scales correctly across breakpoints. */
@keyframes surveyor-flying-rod {
  0%, 79.4% { opacity: 0; left: 78%; bottom: 18%; transform: rotate(0); }
  79.5%     { opacity: 1; left: 78%; bottom: 18%; transform: rotate(-30deg); }    /* leaves his hand */
  80%       { opacity: 1; left: 72%; bottom: 38%; transform: rotate(140deg); }    /* rising */
  80.5%     { opacity: 1; left: 64%; bottom: 56%; transform: rotate(310deg); }    /* still climbing */
  81%       { opacity: 1; left: 55%; bottom: 70%; transform: rotate(480deg); }    /* peak above mountains */
  81.5%     { opacity: 1; left: 46%; bottom: 56%; transform: rotate(640deg); }    /* descending */
  82%       { opacity: 1; left: 38%; bottom: 30%; transform: rotate(800deg); }    /* about to hit water */
  82.3%     { opacity: 0; left: 35%; bottom: 17%; transform: rotate(840deg); }    /* enters lake */
  100%      { opacity: 0; }
}

/* Splash on the lake — small at first, expanding outwards, fading. */
@keyframes surveyor-splash {
  0%, 82.2% { opacity: 0; transform: translateX(-50%) scale(0.4); }
  82.3%     { opacity: 1; transform: translateX(-50%) scale(0.6); }
  82.8%     { opacity: 1; transform: translateX(-50%) scale(1.0); }
  83.5%     { opacity: 0.7; transform: translateX(-50%) scale(1.5); }
  84.5%     { opacity: 0;   transform: translateX(-50%) scale(2.0); }
  100%      { opacity: 0; }
}

/* Dust puff: pops at impact (52%) and dissipates over the next second. */
@keyframes surveyor-dust {
  0%, 51.8% { opacity: 0;   transform: translateX(-50%) scale(0.5); }
  52%       { opacity: 0.9; transform: translateX(-50%) scale(0.7);  }
  53%       { opacity: 0.85; transform: translateX(-50%) scale(1.0); }
  55%       { opacity: 0.5; transform: translateX(-50%) scale(1.4) translateY(-3px); }
  58%       { opacity: 0;   transform: translateX(-50%) scale(1.8) translateY(-6px); }
  100%      { opacity: 0; }
}

/* Dazed stars while he's lying down (56-72%). */
@keyframes surveyor-stars-show {
  0%, 55%   { opacity: 0; }
  56%       { opacity: 1; }
  71%       { opacity: 1; }
  72%       { opacity: 0; }
  100%      { opacity: 0; }
}
@keyframes surveyor-star-spin { to { transform: rotate(360deg); } }
/* Stride beats (with the leg cycle at the same 0.6s period):
 *   0%   — R heel strike : body low, weight transferring to right
 *   25%  — R midstance   : body high, weight on right (lean right)
 *   50%  — L heel strike : body low, weight transferring to left
 *   75%  — L midstance   : body high, weight on left (lean left)
 * Combined with a constant ~2° forward lean. */
@keyframes surveyor-bob {
  0%, 100% { transform: translateY(0)    rotate(2deg); }
  25%      { transform: translateY(-2px) rotate(3.5deg); }
  50%      { transform: translateY(0)    rotate(2deg); }
  75%      { transform: translateY(-2px) rotate(0.5deg); }
}
@keyframes surveyor-leg-l {
  0%, 100% { transform: rotate(-22deg); }
  50%      { transform: rotate(22deg); }
}
@keyframes surveyor-leg-r {
  0%, 100% { transform: rotate(22deg); }
  50%      { transform: rotate(-22deg); }
}
/* Arm swings wider than before — 22° forward to -25° back — for a more
 * confident counter-swing with the opposite leg. */
@keyframes surveyor-arm {
  0%, 100% { transform: rotate(22deg); }
  50%      { transform: rotate(-25deg); }
}
/* Knee bends during the swing half only; straight (0°) during stance so
 * the planted foot stays put under the body. Peak bend at mid-swing. */
@keyframes surveyor-knee-l {
  0%,  50%, 100% { transform: rotate(0deg); }
  15%            { transform: rotate(-18deg); }   /* knee lifting */
  25%            { transform: rotate(-38deg); }   /* peak mid-swing */
  40%            { transform: rotate(-15deg); }   /* straightening for heel strike */
}
@keyframes surveyor-knee-r {
  0%,  50%, 100% { transform: rotate(0deg); }
  65%            { transform: rotate(-18deg); }
  75%            { transform: rotate(-38deg); }
  90%            { transform: rotate(-15deg); }
}
/* Prism + TS beam flash at each shot beat across the 3 slower patrols,
 * then go dark for the tantrum / walk-off / off-screen portion. */
@keyframes prism-spark {
  0%, 100% { opacity: 0.5; r: 1.2; }
  3%,  5.8%, 8.5%,  11.5%, 14%,
  19.5%, 22.2%, 25%,  28%,   30.5%,
  36%,   38.5%, 41.2%, 44.5%, 47.5% { opacity: 1; r: 2; }
  79.5%, 99% { opacity: 0; r: 1; }
}
@keyframes ts-beam {
  0%, 100% { opacity: 0.55; stroke-width: 1; }
  3%,  5.8%, 8.5%,  11.5%, 14%,
  19.5%, 22.2%, 25%,  28%,   30.5%,
  36%,   38.5%, 41.2%, 44.5%, 47.5% { opacity: 0.9; stroke-width: 1.4; }
  50%, 99% { opacity: 0.35; stroke-width: 0.8; }
}

/* ── Anger sequence ─────────────────────────────────────────
 * The blocker tree sits at 50%. Line of sight from the TS (8%) to the
 * prism rod is interrupted whenever the surveyor is to the right of the
 * tree — i.e. at the 60% and 86% shot points (and on the return back
 * through 60%). At those beats the angry overlay fades in and he gives
 * a little frustrated wobble.
 */
.surveyor-anger {
  opacity: 0;
  transform-origin: 16px 19px;
  animation: surveyor-anger 100s linear infinite;
}
@keyframes surveyor-anger {
  /* Anger flickers on at each blocked beat across the 3 patrols, ramping
   * up to a max-scale outburst right before the trip at 50%. */
  0%, 100% { opacity: 0; transform: scale(0.9); }
  /* Patrol 1 — shots 2, 3, and back through 2 */
  5.8%, 8.5%, 11.5% { opacity: 1; transform: scale(1.05); }
  6.8%, 9.5%, 12.5% { opacity: 0; transform: scale(0.9); }
  /* Patrol 2 */
  22.2%, 25%, 28% { opacity: 1; transform: scale(1.15); }
  23.2%, 26%, 29% { opacity: 0; transform: scale(0.9); }
  /* Patrol 3 — boiling over */
  38.5%, 41.2%, 44.5% { opacity: 1; transform: scale(1.25); }
  39.5%, 42.2%, 45.5% { opacity: 0; transform: scale(0.9); }
  /* Fuming at the tree right before the trip */
  47.5%, 49%      { opacity: 1; transform: scale(1.3); }
  /* Final outburst */
  49.5%           { opacity: 1; transform: scale(1.5); }
  50%             { opacity: 0; transform: scale(0.9); }
}

/* The big walk keyframe already drives the SVG's rotate/translate for the
 * trip and fall. No stomp animation needed — anger overlay does the work
 * during the angry beats. */

/* ── Queenstown animated extras ─────────────────────────────
 * Each element is positioned with %s relative to the strip and animated
 * with CSS keyframes. Loop durations are intentionally long so the scene
 * feels alive without being distracting.
 */

/* — Gondola car climbing the cable inside the SVG.
   Cable goes from (595,98) to (535,48) in the 1000x110 viewBox. */
.qt-gondola { animation: qt-gondola-ride 18s ease-in-out infinite; }
@keyframes qt-gondola-ride {
  0%   { transform: translate(595px, 98px); }
  45%  { transform: translate(535px, 48px); }   /* arrives at the top */
  55%  { transform: translate(535px, 48px); }   /* brief stop */
  100% { transform: translate(595px, 98px); }   /* glides back down */
}

/* — Drone orbiting the Remarkables.
   .qt-drone-orbit defines the centre of the loop; .qt-drone spins around
   that centre on a circular path via translate + rotate. */
.qt-drone-orbit {
  position: absolute;
  left: 22%;
  top: 32px;
  width: 0; height: 0;
}
.qt-drone {
  position: absolute;
  transform-origin: center center;
  animation: qt-drone-loop 12s linear infinite;
}
@keyframes qt-drone-loop {
  /* Orbit a 60px radius circle around the orbit anchor */
  0%   { transform: rotate(0deg)   translateX(60px) rotate(0deg); }
  100% { transform: rotate(360deg) translateX(60px) rotate(-360deg); }
}
/* Rotor blur — fast spin */
.qt-rotor { animation: qt-rotor-spin 0.4s linear infinite; transform-origin: center; }
@keyframes qt-rotor-spin { to { transform: rotate(360deg); } }

/* — Paragliders drifting overhead.
   Two of them with different speeds and altitudes for parallax. */
.qt-glider {
  position: absolute;
  top: 18px;
  left: -10%;
  animation: qt-glide-1 55s linear infinite;
}
.qt-glider-2 {
  top: 8px;
  animation: qt-glide-2 75s linear infinite;
  animation-delay: -22s;
}
@keyframes qt-glide-1 {
  0%   { transform: translateX(-30px) translateY(0); }
  25%  { transform: translateX(28vw)  translateY(-6px); }
  50%  { transform: translateX(55vw)  translateY(2px); }
  75%  { transform: translateX(80vw)  translateY(-4px); }
  100% { transform: translateX(110vw) translateY(0); }
}
@keyframes qt-glide-2 {
  0%   { transform: translateX(110vw) translateY(0); }
  50%  { transform: translateX(50vw)  translateY(-4px); }
  100% { transform: translateX(-30px) translateY(2px); }
}

/* — TSS Earnslaw on the lake.
   Lake band sits roughly 88-96/110 of the SVG, i.e. ~80% down the 180px
   strip → ~144-157px from the top. The ship sits with its hull just on
   the water line. */
.qt-earnslaw {
  position: absolute;
  bottom: 36px;
  left: -50px;
  animation: qt-earnslaw-cruise 95s linear infinite;
}
.qt-smoke {
  position: absolute;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: rgba(200, 200, 200, 0.75);
  pointer-events: none;
  filter: blur(0.4px);
}
.qt-smoke-1 { left: 22px; top: -2px;  animation: qt-smoke-puff 3s ease-out infinite; }
.qt-smoke-2 { left: 22px; top: -6px;  width: 8px; height: 8px; animation: qt-smoke-puff 3s ease-out infinite -1s; opacity: 0.55; }
.qt-smoke-3 { left: 22px; top: -10px; width: 10px; height: 10px; animation: qt-smoke-puff 3s ease-out infinite -2s; opacity: 0.35; }
@keyframes qt-earnslaw-cruise {
  0%   { transform: translateX(0); }
  100% { transform: translateX(calc(100vw + 80px)); }
}
@keyframes qt-smoke-puff {
  0%   { transform: translate(0, 0)    scale(0.6); opacity: 0.8; }
  60%  { transform: translate(-6px, -10px) scale(1.0); opacity: 0.4; }
  100% { transform: translate(-12px, -18px) scale(1.4); opacity: 0; }
}

/* — Sheep grazing in the foreground.
   They wander slowly back and forth so the scene has a bit of low-level
   movement near the surveyor. */
.qt-sheep {
  position: absolute;
  bottom: 4px;
}
.qt-sheep-1 { left: 18%; animation: qt-graze-1 30s ease-in-out infinite; }
.qt-sheep-2 { left: 25%; animation: qt-graze-2 35s ease-in-out infinite -10s; }
.qt-sheep-3 { left: 82%; animation: qt-graze-3 28s ease-in-out infinite -5s; }
@keyframes qt-graze-1 {
  0%, 100% { transform: translateX(0)    scaleX(1); }
  45%      { transform: translateX(30px) scaleX(1); }
  50%      { transform: translateX(30px) scaleX(-1); }
  95%      { transform: translateX(0)    scaleX(-1); }
}
@keyframes qt-graze-2 {
  0%, 100% { transform: translateX(0)     scaleX(1); }
  50%      { transform: translateX(-22px) scaleX(-1); }
}
@keyframes qt-graze-3 {
  0%, 100% { transform: translateX(0)    scaleX(-1); }
  50%      { transform: translateX(-30px) scaleX(1); }
}

/* — Snowfall (snow variant only).
   Each flake's --x / --d / --del custom props give independent paths. */
.qt-snowfall {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: var(--qt-snowfall-op, 0);
  transition: opacity 0.4s;
}
.qt-snowfall span {
  position: absolute;
  top: -10px;
  left: var(--x, 50%);
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: #ffffff;
  opacity: 0.85;
  filter: blur(0.3px);
  animation: qt-snow-fall var(--d, 11s) linear infinite;
  animation-delay: var(--del, 0s);
}
@keyframes qt-snow-fall {
  0%   { transform: translate(0, -12px) translateX(0); opacity: 0; }
  8%   { opacity: 0.9; }
  100% { transform: translate(0, 200px) translateX(20px); opacity: 0; }
}

/* Hide grazing sheep and Earnslaw in heavy snow — they'd be lost in
   the noise. Paragliders also tend to land in bad weather. */
.surveyor-strip[data-variant="snow"] .qt-glider,
.surveyor-strip[data-variant="snow"] .qt-sheep,
.surveyor-strip[data-variant="snow"] .qt-earnslaw {
  display: none;
}
/* Drone keeps flying in dawn + golden (CFMA missions). In snow it stays
   in the hangar. */
.surveyor-strip[data-variant="snow"] .qt-drone-orbit { display: none; }

/* Stop entirely for users who prefer reduced motion. */
@media (prefers-reduced-motion: reduce) {
  .surveyor, .surveyor svg, .surveyor-pose,
  .surveyor-leg-l, .surveyor-leg-r, .surveyor-arm,
  .surveyor-lower-l, .surveyor-lower-r,
  .surveyor-anger, .tree-blocker,
  .prism-spark, .ts-beam,
  .qt-gondola, .qt-drone, .qt-rotor,
  .qt-glider, .qt-earnslaw, .qt-smoke,
  .qt-sheep, .qt-snowfall span {
    animation: none !important;
  }
  .surveyor { left: 38%; }
}

@media (max-width: 700px) {
  .topbar { padding: 12px 16px; }
  .brand-mark { width: 34px; height: 34px; }
  .brand-name { font-size: 15px; }
  .container { padding: 24px 16px 36px; }
  .intro { padding: 22px 20px; }
  .intro h1 { font-size: 24px; }
  .intro::before { width: 110px; height: 110px; top: -20px; right: -10px; }
  .tile { padding: 18px 18px 16px; min-height: 150px; }
  .tile-icon { width: 54px; height: 54px; }
  .tile-icon-img { width: 36px; height: 36px; }
  .surveyor-strip { height: 130px; }
  body { padding-bottom: 130px; }
}
