:root {
  --brand: #1d6f5e;
  --brand-dark: #14493e;
  --brand-light: #e7f4f0;
  --danger: #c0392b;
  --danger-bg: #fdecea;
  --warn: #a15c00;
  --warn-bg: #fff4e0;
  --ink: #1c2321;
  --ink-soft: #566;
  --border: #dfe6e3;
  --bg: #f6f8f7;
  --radius: 12px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--ink); }
body { min-height: 100vh; display: flex; flex-direction: column; }
a { color: var(--brand); }
img { max-width: 100%; display: block; }

/* ---------- Header ---------- */
header.site {
  background: var(--brand-dark);
  color: #fff;
  padding: 14px 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  position: sticky;
  top: 0;
  z-index: 500;
}
header.site .brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 1.15rem;
  text-decoration: none;
  color: #fff;
}
header.site .brand-logo { width: 30px; height: 30px; flex-shrink: 0; }
header.site nav { display: flex; align-items: center; gap: 14px; font-size: 0.92rem; }
header.site nav a { color: #dff3ee; text-decoration: none; }
header.site nav a:hover { color: #fff; }
header.site button.primary-btn { padding: 8px 14px; font-size: 0.88rem; }
header.site .nav-toggle {
  display: none;
  background: transparent;
  border: none;
  color: #fff;
  font-size: 1.4rem;
  line-height: 1;
  padding: 4px 6px;
  margin-left: auto;
}

/* ---------- Buttons / forms ---------- */
button, .btn {
  font: inherit;
  cursor: pointer;
  border: none;
  border-radius: 8px;
  padding: 10px 16px;
  background: #eef2f0;
  color: var(--ink);
  text-decoration: none;
  display: inline-block;
}
button.primary-btn, .btn.primary {
  background: var(--brand);
  color: #fff;
}
button.primary-btn:hover, .btn.primary:hover { background: var(--brand-dark); }
button.danger-btn { background: var(--danger); color: #fff; }
/* A visible-but-secondary button — the default button background (#eef2f0)
   is too close to the page background (#f6f8f7) to read clearly wherever a
   button sits directly on the page rather than inside a white .card. */
button.outline-btn, .btn.outline {
  background: var(--brand-light);
  color: var(--brand-dark);
  border: 1px solid var(--brand);
}
button.outline-btn:hover, .btn.outline:hover { background: #d9ede7; }
button:disabled { opacity: 0.55; cursor: not-allowed; }

label { display: block; font-size: 0.85rem; font-weight: 600; margin: 14px 0 4px; color: var(--ink); }
input, textarea, select {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
  background: #fff;
}
/* Checkboxes/radios shouldn't inherit the full-width text-input styling
   above — that's what was stretching each radio into a large padded box
   and throwing off alignment with its label text wherever a checkbox/radio
   wasn't specifically wrapped in .checkbox-row (which already had its own
   fix for this). Scoping it here instead makes it universal. */
input[type="checkbox"], input[type="radio"] {
  /* iOS Safari in particular doesn't render a consistent intrinsic checkbox
     size when left at width:auto — it can come out visibly larger/smaller
     depending on the surrounding flex context (e.g. inside .guidance-card
     vs. directly in a modal body). Pinning an explicit size fixes that
     everywhere instead of leaving it up to each browser's default. */
  width: 18px;
  height: 18px;
  padding: 0;
  border-radius: 0;
  flex-shrink: 0;
}
textarea { resize: vertical; min-height: 80px; }
.hint { font-size: 0.78rem; color: var(--ink-soft); margin-top: 4px; }
.form-row { display: flex; gap: 12px; }
.form-row > * { flex: 1; }

/* ---------- Layout helpers ---------- */
.container { max-width: 1100px; margin: 0 auto; padding: 18px; width: 100%; }
.card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px;
}
main { flex: 1; }
.intro { max-width: 720px; margin: 6px 0 22px; }
.intro h1 { font-size: 1.6rem; margin: 0 0 8px; }
.intro p { margin: 0; color: var(--ink-soft); line-height: 1.5; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 800px) {
  .grid-2 { grid-template-columns: 1fr; }
  header.site { flex-wrap: nowrap; }
  header.site .nav-toggle { display: block; }
  header.site nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    background: var(--brand-dark);
    padding: 8px 18px 16px;
    box-shadow: 0 6px 14px rgba(0,0,0,0.25);
  }
  header.site nav.open { display: flex; }
  header.site nav a { padding: 8px 0; width: 100%; }
  header.site nav #auth-slot { margin-top: 6px; padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.15); width: 100%; }
}

/* "+ Start a campaign" / "+ Report a hazard" — on narrow phones these sit
   right next to a heading in the same row, and the full label text crowds
   or wraps awkwardly. Below 480px, collapse to a round "+" icon button;
   the full label stays in the accessible name (aria-label) even though
   it's visually hidden. */
@media (max-width: 480px) {
  .add-btn {
    width: 40px;
    height: 40px;
    padding: 0;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.3rem;
    font-weight: 700;
    line-height: 1;
    flex-shrink: 0;
  }
  .add-btn-label { display: none; }
}

/* ---------- Safety banner (persistent, high priority) ---------- */
.safety-banner {
  background: var(--danger-bg);
  border-bottom: 2px solid var(--danger);
  color: var(--danger);
  padding: 10px 18px;
  font-size: 0.92rem;
  font-weight: 600;
  text-align: center;
}
.safety-banner strong { text-decoration: underline; }

.guidance-card {
  background: var(--warn-bg);
  border: 1px solid #f0d29a;
  border-radius: var(--radius);
  padding: 16px 18px;
  color: var(--warn);
}
.guidance-card h3 { margin-top: 0; color: #7a4900; }
.guidance-card ul { margin: 8px 0 0; padding-left: 20px; }

/* ---------- Home / map ---------- */
/* isolation:isolate gives each map its own stacking context, so Leaflet's
   internal control z-index (1000) can't climb above the sticky header,
   modals, or anything else outside the map. */
#map, #campaign-map, #boundary-map, #log-map, #hazard-map, #hazard-update-map {
  width: 100%; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--border);
  isolation: isolate;
}
#map { height: 62vh; min-height: 380px; }
#campaign-map { height: 46vh; min-height: 320px; }
#boundary-map { height: 380px; }

.map-wrap { position: relative; }
.map-expand-btn {
  position: absolute; top: 10px; right: 10px; z-index: 450;
  background: #fff; border: 1px solid var(--border);
  box-shadow: 0 1px 4px rgba(0,0,0,0.2);
  padding: 6px 10px; font-size: 0.85rem;
}
.map-wrap.expanded {
  position: fixed; inset: 0; z-index: 950; border-radius: 0; padding: 0;
  background: #fff;
}
.map-wrap.expanded #campaign-map { height: 100vh; border-radius: 0; border: none; }
.live-dot {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 0.72rem; color: var(--ink-soft); font-weight: 600;
}
.live-dot .pulse {
  width: 8px; height: 8px; border-radius: 50%; background: #2ecc71;
  box-shadow: 0 0 0 0 rgba(46, 204, 113, 0.6);
  animation: pulse 2s infinite;
}
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 rgba(46, 204, 113, 0.6); }
  70% { box-shadow: 0 0 0 6px rgba(46, 204, 113, 0); }
  100% { box-shadow: 0 0 0 0 rgba(46, 204, 113, 0); }
}

/* ---------- Tab pills (Campaigns / Hazards) ---------- */
.tab-pills { display: flex; gap: 8px; margin-bottom: 18px; align-items: center; }
.tab-pill {
  background: #fff; border: 1px solid var(--border); border-radius: 999px;
  padding: 9px 18px; font-weight: 600; color: var(--ink-soft);
}
.tab-pill.active { background: var(--brand); border-color: var(--brand); color: #fff; }
.tab-pill-count {
  display: inline-block; margin-left: 4px; font-size: 0.78rem; font-weight: 700;
  opacity: 0.85;
}
/* The distance-filter toggle icon only exists for the mobile collapse
   below — on wider screens the filter bar itself is already visible, so
   there's nothing for this button to reveal. */
/* Sized to match .add-btn's 40px mobile-collapsed "+" circle (see the
   480px breakpoint below) so the two icon buttons look like a matched
   set, not two different sizes of round button. */
/* ".icon-btn" repeated in all of these selectors isn't redundant — .icon-btn
   itself (further down this file) sets "display: inline-flex" and is
   declared AFTER this block, so on a specificity tie it would win by source
   order alone and this button would stay visible on every screen size.
   Doubling the class here bumps specificity so this always wins instead. */
.icon-btn.loc-filter-toggle-btn { display: none; width: 40px; height: 40px; margin-left: auto; border: 1px solid var(--border); background: #fff; color: var(--ink-soft); flex-shrink: 0; }
/* The SVG's width/height attributes only set its *intrinsic* size — as a
   flex child of this inline-flex button, that's still just a hint the
   flexbox algorithm can shrink on the main axis (which squashes width
   only, not height, hence a lopsided box instead of a smaller square).
   Pinning size + flex-shrink:0 in CSS on the svg itself stops that. */
.icon-btn.loc-filter-toggle-btn svg { width: 20px; height: 20px; flex-shrink: 0; }
.icon-btn.loc-filter-toggle-btn:hover { background: #eef2f0; color: var(--ink); }
/* Deliberately subtle even when open — this just reveals a filter bar,
   it's not a primary action, so it shouldn't compete with the tab pills
   (which use the solid brand color for their own "active" state). */
.icon-btn.loc-filter-toggle-btn.active { background: var(--brand-light); color: var(--brand-dark); border-color: var(--brand); }
@media (max-width: 640px) {
  .icon-btn.loc-filter-toggle-btn { display: inline-flex; }
  .loc-filter-bar { display: none !important; }
  .loc-filter-bar.open { display: flex !important; }
}

.campaign-list { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }
.campaign-list-item {
  display: flex;
  gap: 12px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: #fff;
  text-decoration: none;
  color: inherit;
  transition: box-shadow 0.15s;
}
.campaign-list-item:hover { box-shadow: 0 2px 10px rgba(0,0,0,0.08); }
.campaign-list-item.selected { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-light) inset; }
.campaign-list-item img { width: 64px; height: 64px; object-fit: contain; object-position: center; border-radius: 8px; background: #eee; flex-shrink: 0; }
.campaign-list-item .meta { display: flex; flex-direction: column; gap: 2px; }
.campaign-list-item .meta .name { font-weight: 700; }
.campaign-list-item .meta .sub { font-size: 0.82rem; color: var(--ink-soft); }
.badge { display: inline-block; font-size: 0.72rem; font-weight: 700; padding: 2px 8px; border-radius: 20px; text-transform: uppercase; letter-spacing: 0.03em; }
.badge.active { background: #fdecea; color: var(--danger); }
.badge.resolved { background: #e6f4ea; color: #217a3d; }
.badge.paused { background: #eee; color: #666; }
.badge.closed { background: #eee; color: #444; }
.badge.unlisted { background: #eef1f4; color: #5b6472; }

.color-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: #eef2f0; color: var(--ink); text-decoration: none;
  font-size: 1.1rem; flex-shrink: 0;
}
.icon-btn:hover { background: var(--brand); color: #fff; }

/* ---------- Campaign detail ---------- */
.subject-photo { width: 100%; height: 340px; object-fit: contain; object-position: center; border-radius: var(--radius); background: #eee; }
.info-block { margin-top: 16px; }
.info-block h3 { margin-bottom: 6px; }
.owner-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* ---------- Search log feed ---------- */
.log-feed-scroll { max-height: 420px; overflow-y: auto; }
.log-entry { border-bottom: 1px solid var(--border); padding: 10px 0; }
.log-entry:last-child { border-bottom: none; }
.log-entry .top { display: flex; justify-content: space-between; font-size: 0.8rem; color: var(--ink-soft); }
.log-entry .notes { margin-top: 4px; }
.log-entry .found-detail { margin-top: 4px; font-size: 0.85rem; background: var(--warn-bg); border-radius: 6px; padding: 6px 8px; }
.log-entry.hidden-entry { opacity: 0.45; }
.log-entry .entry-actions { display: flex; gap: 8px; margin-top: 6px; }
.log-entry .entry-actions button { font-size: 0.75rem; padding: 4px 10px; }

.fab {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 400;
  border-radius: 999px;
  padding: 14px 22px;
  font-weight: 700;
  box-shadow: 0 4px 16px rgba(0,0,0,0.25);
}

.modal-backdrop {
  position: fixed; inset: 0; background: rgba(20,30,28,0.5);
  display: flex; align-items: flex-end; justify-content: center;
  z-index: 900;
}
.modal-backdrop.hidden { display: none; }
.modal-sheet {
  background: #fff; width: 100%; max-width: 560px;
  border-radius: 16px 16px 0 0;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
@media (min-width: 640px) {
  .modal-backdrop { align-items: center; }
  .modal-sheet { border-radius: 16px; }
}
.modal-sheet-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px; border-bottom: 1px solid var(--border);
  flex-shrink: 0; background: #fff;
}
.modal-sheet-body { padding: 16px 20px 28px; overflow-y: auto; }
.modal-sheet .close-x { background: none; padding: 4px 8px; font-size: 1.1rem; }
.checkbox-row { display: flex; align-items: flex-start; gap: 8px; margin: 10px 0; }
.checkbox-row input { width: 18px; height: 18px; margin-top: 3px; }
.checkbox-row label { margin: 0; font-weight: 500; }

/* Hazard icon picker — a small grid of tappable emoji buttons standing in
   for a radio group (see #hazard-icon-picker), so reporters can flag what
   kind of hazard it is at a glance instead of everything showing the same
   generic warning triangle. */
.icon-picker { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.icon-picker-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  width: 60px;
  padding: 8px 4px 6px;
  border: 2px solid var(--border);
  border-radius: 10px;
  background: #fff;
  font-size: 1.3rem;
  line-height: 1;
}
.icon-picker-btn .icon-picker-label { font-size: 0.62rem; font-weight: 600; color: var(--ink-soft); line-height: 1.15; }
.icon-picker-btn:hover { border-color: var(--brand); }
.icon-picker-btn.selected { border-color: var(--brand); background: var(--brand-light); }
.icon-picker-btn.selected .icon-picker-label { color: var(--brand-dark); }

footer.site {
  text-align: center;
  font-size: 0.78rem;
  color: var(--ink-soft);
  padding: 20px;
}

.toast {
  position: fixed; top: 70px; left: 50%; transform: translateX(-50%);
  background: var(--ink); color: #fff; padding: 10px 18px; border-radius: 8px;
  font-size: 0.88rem; z-index: 1000; box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.empty-state { text-align: center; padding: 40px 20px; color: var(--ink-soft); }

/* ---------- iOS "Add to Home Screen" looping demo ----------
   Small, self-contained animated mockup of the real (fiddly) iOS Safari
   path to installing the site, used alongside the text instructions
   telling iPhone users to add the site to their Home Screen before push
   notifications will work (Apple only allows web push for an installed
   PWA on iOS, never a regular Safari tab). Confirmed step-by-step against
   a real recording of the flow:
     1. Tap "•••" in Safari's toolbar → a light context menu opens
     2. Tap "Share" (first row in that menu) → the real share sheet opens
     3. Tap "View More" in the share sheet's action row (not just scroll)
        → the sheet expands to reveal more options
     4. Tap "Add to Home Screen" → a naming dialog opens with a green
        "Open as Web App" toggle that must stay ON, or the icon just opens
        a Safari bookmark instead of installing as a standalone app
     5. Tap "Add" (top right of that dialog) to finish — the screen briefly
        flashes to black (Safari closing) before landing on the Home Screen
     6. Find the new icon on the Home Screen and tap it to launch the app —
        that's the app instance push notifications actually work from.
   Purely decorative — aria-hidden, the real instructions are the text next
   to it — so it's fine if a browser doesn't support one of the animation
   properties; it just won't animate. */
.ios-install-demo {
  width: 240px;
  max-width: 100%;
  margin-top: 8px;
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  background: #f2f2f7;
  position: relative;
}
.ios-demo-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px 10px;
  background: #e4e4ea;
}
.ios-demo-url {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.78rem;
  color: #555;
}
.ios-demo-stage {
  position: relative;
  height: 168px;
  background: #fff;
  overflow: hidden;
}
.ios-demo-stage > div {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  opacity: 0;
  transform: translateY(100%);
}
/* Real Safari toolbar sits at the bottom of the screen, not next to the
   address bar — "•••" is the rightmost icon in it. */
.ios-demo-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 7px 10px;
  background: #e4e4ea;
  border-top: 1px solid #d3d3d9;
}
.ios-demo-toolbar-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #8a8a90;
  font-size: 0.85rem;
}
.ios-demo-more-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 6px;
  color: var(--brand);
  flex-shrink: 0;
  font-weight: 700;
  font-size: 0.85rem;
  letter-spacing: 1px;
  animation: ios-demo-more-pulse 20s ease-in-out infinite;
}

/* Step 1→2: context menu after tapping "•••" — a light popover near the
   toolbar, not a full-width dark sheet (matches the real iOS look). */
.ios-demo-menu {
  left: auto;
  right: 8px;
  bottom: 8px;
  width: 68%;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.2);
  padding: 4px;
  animation: ios-demo-menu-show 20s ease-in-out infinite;
}
.ios-demo-menu-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 0.78rem;
  color: var(--ink);
}
.ios-demo-menu-row.dim { color: var(--ink-soft); }
.ios-demo-menu-row.target { animation: ios-demo-menu-row-pulse 20s ease-in-out infinite; }

/* Step 2→3: real share sheet, collapsed then expanded via "View More" */
.ios-demo-sheet {
  background: #fff;
  border-top: 1px solid var(--border);
  border-radius: 10px 10px 0 0;
  padding: 4px;
  animation: ios-demo-sheet-show 20s ease-in-out infinite;
}
.ios-demo-sheet-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 0.76rem;
  color: var(--ink);
}
.ios-demo-sheet-row.dim { color: var(--ink-soft); }
.ios-demo-sheet-row.target { animation: ios-demo-sheet-row-pulse 20s ease-in-out infinite; }
.ios-demo-sheet-row.more-only {
  max-height: 0;
  overflow: hidden;
  padding-top: 0;
  padding-bottom: 0;
  opacity: 0;
  animation: ios-demo-more-rows-reveal 20s ease-in-out infinite;
}
/* This row is both .more-only (needs to expand into view) and the final
   tap target (needs a click highlight) — one keyframe set handles both,
   since only the last-declared "animation" property on an element wins. */
.ios-demo-sheet-row.target-final {
  max-height: 0;
  overflow: hidden;
  padding-top: 0;
  padding-bottom: 0;
  opacity: 0;
  animation: ios-demo-final-row-reveal-pulse 20s ease-in-out infinite;
}
.ios-demo-plus-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 5px;
  background: #34c759;
  color: #fff;
  font-weight: 700;
  font-size: 0.78rem;
  flex-shrink: 0;
}

/* Step 4→5: naming dialog with the "Open as Web App" toggle and the
   "Add" button (top right) that actually confirms the install. */
.ios-demo-dialog {
  background: #fff;
  border-top: 1px solid var(--border);
  border-radius: 10px 10px 0 0;
  padding: 10px;
  animation: ios-demo-dialog-show 20s ease-in-out infinite;
}
.ios-demo-dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
.ios-demo-dialog-cancel { font-size: 0.72rem; color: var(--ink-soft); }
.ios-demo-dialog-add {
  font-size: 0.74rem;
  font-weight: 700;
  color: var(--brand);
  border: 2px solid transparent;
  border-radius: 6px;
  padding: 2px 6px;
  margin: -2px -6px;
  animation: ios-demo-add-btn-highlight 20s ease-in-out infinite;
}
.ios-demo-dialog-title { font-size: 0.8rem; font-weight: 700; margin-bottom: 6px; }
.ios-demo-dialog-name {
  font-size: 0.76rem;
  color: var(--ink);
  background: #f2f2f7;
  border-radius: 6px;
  padding: 6px 8px;
  margin-bottom: 8px;
}
.ios-demo-dialog-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.74rem;
  color: var(--ink);
  border: 2px solid transparent;
  border-radius: 8px;
  padding: 4px 6px;
  margin: 0 -6px;
  animation: ios-demo-toggle-highlight 20s ease-in-out infinite;
}
.ios-demo-toggle {
  width: 30px;
  height: 17px;
  border-radius: 999px;
  background: #34c759;
  position: relative;
  flex-shrink: 0;
}
.ios-demo-toggle::after {
  content: "";
  position: absolute;
  top: 2px; right: 2px;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: #fff;
}

/* Step 5→6: after "Add" is tapped, Safari briefly flashes to black (the
   app closing) before landing on the Home Screen with the new icon. Both
   layers are direct children of .ios-install-demo (not .ios-demo-stage)
   so they cover the address bar and bottom toolbar too — by this point
   you've left Safari entirely, so none of its chrome should still show. */
.ios-demo-blackout {
  position: absolute;
  inset: 0;
  z-index: 9;
  background: #000;
  opacity: 0;
  pointer-events: none;
  animation: ios-demo-blackout-fade 20s ease-in-out infinite;
}
.ios-demo-homescreen {
  position: absolute;
  inset: 0;
  z-index: 8;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: linear-gradient(160deg, #cfe0ea, #9fb9cc);
  opacity: 0;
  pointer-events: none;
  animation: ios-demo-homescreen-show 20s ease-in-out infinite;
}
.ios-demo-homescreen-icon-wrap {
  width: 52px;
  height: 52px;
  border-radius: 13px;
  overflow: hidden;
  box-shadow: 0 2px 6px rgba(0,0,0,0.25);
  animation: ios-demo-homescreen-icon-pulse 20s ease-in-out infinite;
}
.ios-demo-homescreen-icon { width: 100%; height: 100%; object-fit: cover; display: block; }
.ios-demo-homescreen-label {
  font-size: 0.72rem;
  font-weight: 600;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0,0,0,0.35);
}

@keyframes ios-demo-more-pulse {
  0%, 1% { background: transparent; }
  4%, 6% { background: rgba(29,111,94,0.18); }
  9%, 100% { background: transparent; }
}
@keyframes ios-demo-menu-show {
  0%, 7% { transform: translateY(100%); opacity: 0; }
  9%, 19% { transform: translateY(0); opacity: 1; }
  21%, 100% { transform: translateY(100%); opacity: 0; }
}
@keyframes ios-demo-menu-row-pulse {
  0%, 14% { background: transparent; }
  16%, 19% { background: rgba(29,111,94,0.16); }
  21%, 100% { background: transparent; }
}
@keyframes ios-demo-sheet-show {
  0%, 21% { transform: translateY(100%); opacity: 0; }
  23%, 45% { transform: translateY(0); opacity: 1; }
  47%, 100% { transform: translateY(100%); opacity: 0; }
}
@keyframes ios-demo-sheet-row-pulse {
  0%, 28% { background: transparent; }
  30%, 32% { background: rgba(29,111,94,0.18); }
  34%, 100% { background: transparent; }
}
@keyframes ios-demo-more-rows-reveal {
  0%, 32% { max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0; }
  34%, 45% { max-height: 60px; opacity: 1; padding-top: 8px; padding-bottom: 8px; }
  47%, 100% { max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0; }
}
/* Reveal the row (same timing as the other more-only rows), then show a
   green click-highlight flash right before "Add to Home Screen" is tapped. */
@keyframes ios-demo-final-row-reveal-pulse {
  0%, 32% { max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0; background: transparent; }
  34%, 39% { max-height: 40px; opacity: 1; padding-top: 8px; padding-bottom: 8px; background: transparent; }
  41%, 44% { max-height: 40px; opacity: 1; padding-top: 8px; padding-bottom: 8px; background: rgba(52,199,89,0.3); }
  45%, 46% { max-height: 40px; opacity: 1; padding-top: 8px; padding-bottom: 8px; background: transparent; }
  47%, 100% { max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0; background: transparent; }
}
@keyframes ios-demo-dialog-show {
  0%, 47% { transform: translateY(100%); opacity: 0; }
  49%, 63% { transform: translateY(0); opacity: 1; }
  65%, 100% { transform: translateY(100%); opacity: 0; }
}
/* Draws attention to the toggle once the dialog is on screen — it's the
   one thing that has to be checked, since leaving it off just creates a
   bookmark instead of installing the app. Happens before the "Add" tap. */
@keyframes ios-demo-toggle-highlight {
  0%, 51% { border-color: transparent; box-shadow: none; }
  53%, 57% { border-color: #34c759; box-shadow: 0 0 0 2px rgba(52,199,89,0.25); }
  59%, 100% { border-color: transparent; box-shadow: none; }
}
/* Click-highlight on the "Add" button — the actual confirm tap, right
   after the toggle's been checked and just before the dialog closes. */
@keyframes ios-demo-add-btn-highlight {
  0%, 58% { border-color: transparent; background: transparent; }
  60%, 62% { border-color: var(--brand); background: rgba(29,111,94,0.16); }
  64%, 100% { border-color: transparent; background: transparent; }
}
/* Step 5→6: the screen flashes to solid black right after "Add" is tapped
   (Safari closing), fully black for a beat, then fades back out as the
   Home Screen takes over underneath it. Given a lot more room now — this
   whole tail (65-100%) is over a third of the loop, specifically so the
   icon and its tap are easy to actually see. */
@keyframes ios-demo-blackout-fade {
  0%, 64% { opacity: 0; }
  68%, 74% { opacity: 1; }
  80%, 100% { opacity: 0; }
}
/* Fade in the Home Screen with the new icon as the blackout clears, hold
   it on screen for a good while, then flash the icon as if it's being
   tapped to launch the app — with a clear pause before and after the tap
   so the click itself is easy to catch, not just a blink. */
@keyframes ios-demo-homescreen-show {
  0%, 70% { opacity: 0; }
  76%, 97% { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes ios-demo-homescreen-icon-pulse {
  0%, 85% { transform: scale(1); box-shadow: 0 2px 6px rgba(0,0,0,0.25); }
  89%, 93% { transform: scale(0.88); box-shadow: 0 2px 6px rgba(0,0,0,0.25), 0 0 0 4px rgba(255,255,255,0.6); }
  97%, 100% { transform: scale(1); box-shadow: 0 2px 6px rgba(0,0,0,0.25); }
}
@media (prefers-reduced-motion: reduce) {
  .ios-demo-more-icon,
  .ios-demo-menu, .ios-demo-menu-row.target,
  .ios-demo-sheet, .ios-demo-sheet-row.target, .ios-demo-sheet-row.more-only, .ios-demo-sheet-row.target-final,
  .ios-demo-dialog, .ios-demo-dialog-toggle-row, .ios-demo-dialog-add,
  .ios-demo-blackout, .ios-demo-homescreen, .ios-demo-homescreen-icon-wrap { animation: none; }
  .ios-demo-menu, .ios-demo-sheet, .ios-demo-blackout, .ios-demo-homescreen { display: none; }
  .ios-demo-dialog { transform: translateY(0); opacity: 1; }
  .ios-demo-dialog-toggle-row { border-color: #34c759; box-shadow: 0 0 0 2px rgba(52,199,89,0.25); }
}
