:root {
  --bg: #062a35;
  --surface: #0b3d4a;
  --surface-2: #157a7a;
  --fg: #e6f7f9;
  --fg-dim: #b2e0e6;
  --accent: #ff7f6b;
  --accent-large: #20b2aa;
  --accent-dim: #157a7a;
  --accent-sand: #f5d5c0;
  --danger: #d64545;
  --radius: 12px;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--fg);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

body {
  display: flex;
  flex-direction: column;
  /* Height comes from the html, body { height: 100% } rule above. Not
     100dvh: inside an installed app a reload can evaluate dvh taller than
     the visible screen and nothing re-lays it out until a viewport
     gesture, so the nav sits below the bottom edge, clipped. */
  transition: background-color 0.4s;
  /* The page itself never scrolls: the active screen scrolls internally,
     so the header and the bottom nav stay pinned at all times. */
  overflow: hidden;
}

/* --- Screens --- */
.screen {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: none;
  flex-direction: column;
  padding: 20px;
  max-width: 600px;
  margin: 0 auto;
  width: 100%;
}
.screen.active { display: flex; }

/* --- Header --- */
/* Scoped to body > : the walk-result markup now emits its own <header>
   inside #detail-content; bare element selectors would restyle it. */
body > header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* safe-area inset lives inside the bar, not on body, so the header
     background runs edge-to-edge into the notch zone */
  padding: calc(12px + var(--safe-top)) 20px 12px;
  border-bottom: 1px solid var(--surface);
  flex-shrink: 0;
}
.logo {
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--fg);
}
.logo span { color: var(--accent); }
/* Detail screen drops the header: the artifact frame keeps a uniform
   teal border on all four sides, gaining a row of viewport. */
body.detail-active > header { display: none; }

/* --- Buttons --- */
button {
  background: var(--surface);
  color: var(--fg);
  border: 1px solid var(--surface-2);
  border-radius: var(--radius);
  padding: 14px 20px;
  font-size: 1rem;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
  -webkit-tap-highlight-color: transparent;
}
button:active { background: var(--surface-2); }
button:disabled { opacity: 0.4; cursor: not-allowed; }

.btn-primary {
  background: var(--accent);
  color: var(--bg);
  border-color: var(--accent);
  font-weight: 600;
}
.btn-primary:active { background: var(--accent-dim); }

.btn-danger {
  border-color: var(--danger);
  color: var(--danger);
}

.btn-full { width: 100%; }

/* --- Go screen --- */
#screen-go {
  align-items: center;
  text-align: center;
  gap: 18px;
}
/* Fur texture centred behind the Go screen only. The source is a 3x
   phone-portrait export (1152x2082), deliberately pixel-dense so high-
   DPI phones render ~1:1. cover scales it, but the gate only ever lets
   the element fit inside the image, so it is always contracted - never
   stretched, never enlarged. The height gate leaves ~110px headroom for
   the header + nav chrome, and inside the query the screen's 600px
   column cap is lifted so the fur runs edge to edge (children still
   centre via align-items). Past the gate the screen shows the flat
   colour: no bare edges. Remove this block and the file to drop it. */
@media (max-width: 1152px) and (max-height: 1970px) {
  #screen-go {
    max-width: none;
    background: var(--bg) url('./fur-bg.webp') center / cover no-repeat;
  }
}
/* Centre the content vertically via auto margins rather than
   justify-content: with justify-content an overflowing screen clips its
   top edge out of scroll reach; auto margins collapse to 0 instead. */
#screen-go > :first-child { margin-top: auto; }
#screen-go > :last-child { margin-bottom: auto; }
#screen-go .title {
  font-size: 2.2rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
#screen-go .subtitle {
  color: var(--fg-dim);
  font-size: 1rem;
  max-width: 320px;
  line-height: 1.4;
}
#btn-go {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  font-size: 1.7rem;
  font-weight: 700;
  border: 2px solid var(--accent-large);
  background: var(--surface);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
}
#btn-go:active { background: var(--accent-dim); color: var(--fg); }

/* --- Walk parameter picker (scroll-snap wheels) --- */
.settings-block {
  --item-h: 30px;
  --visible: 3;
  width: 100%;
  max-width: 340px;
}
.labels-row {
  display: flex;
  margin-bottom: 6px;
}
.wheel-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--fg-dim);
}
.col-narrow { flex: 0 0 76px; }
.col-wide { flex: 1; min-width: 0; }

/* Single rounded panel holding all three wheels */
.settings-panel {
  position: relative;
  display: flex;
  background: var(--surface);
  border: 1px solid rgba(230, 247, 249, 0.09);
  border-radius: var(--radius);
  overflow: hidden;
  /* Faint teal tint on the selected row */
  background-image: linear-gradient(
    to bottom,
    transparent calc(50% - var(--item-h) / 2),
    rgba(32, 178, 170, 0.06) calc(50% - var(--item-h) / 2),
    rgba(32, 178, 170, 0.06) calc(50% + var(--item-h) / 2),
    transparent calc(50% + var(--item-h) / 2)
  );
}
/* Thin hairlines above and below the selected row */
.settings-panel::before,
.settings-panel::after {
  content: '';
  position: absolute;
  left: 10px;
  right: 10px;
  height: 1px;
  background: rgba(230, 247, 249, 0.14);
  pointer-events: none;
}
.settings-panel::before { top: calc(50% - var(--item-h) / 2); }
.settings-panel::after { top: calc(50% + var(--item-h) / 2); }

/* Faint boundary between controls */
.wheel-col + .wheel-col { border-left: 1px solid rgba(230, 247, 249, 0.06); }

.wheel {
  height: calc(var(--item-h) * var(--visible));
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent, black 30%, black 70%, transparent);
  mask-image: linear-gradient(to bottom, transparent, black 30%, black 70%, transparent);
  -webkit-overflow-scrolling: touch;
}
.wheel::-webkit-scrollbar { display: none; }
.wheel::before,
.wheel::after {
  content: '';
  display: block;
  height: calc(var(--item-h) * (var(--visible) - 1) / 2);
}
.wheel-item {
  height: var(--item-h);
  scroll-snap-align: center;
  scroll-snap-stop: always;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--fg-dim);
  font-size: 0.95rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  opacity: 0.3;
  transition: opacity 0.15s ease, color 0.15s ease;
}
.wheel-item.selected { color: var(--fg); opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .wheel-item { transition: none; }
}

/* --- Walk screen --- */
#screen-walk { gap: 16px; }
.walk-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  font-size: 0.9rem;
  color: var(--fg-dim);
}
.walk-head-left {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.compass {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 300px;
}
.compass-arrow {
  font-size: 6rem;
  line-height: 1;
  color: var(--accent-large);
  transition: transform 0.2s ease-out;
  will-change: transform;
}
.compass-dist {
  font-size: 2.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.compass-bearing {
  font-size: 0.9rem;
  color: var(--fg-dim);
}
/* Arrival panel replaces the compass readout when a waypoint is reached.
   It shows a large round Photograph button (with a skip link), then
   morphs into a Continue button after the user takes or skips a photo. */
.arrival-panel {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}
.arrival-panel.visible { display: flex; }
.arrival-main-btn {
  width: 110px;
  height: 110px;
  border-radius: 50%;
  border: 2px solid var(--accent-large);
  background: var(--surface);
  color: var(--accent-large);
  font-size: 2.8rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.arrival-main-btn:active {
  background: var(--accent-large);
  color: var(--bg);
}
.arrival-label {
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--fg);
}
.arrival-skip {
  background: none;
  border: none;
  color: var(--fg-dim);
  font-size: 0.9rem;
  text-decoration: underline;
  cursor: pointer;
  padding: 2px 8px;
}
.arrival-thumb {
  max-width: 72px;
  max-height: 72px;
  border-radius: 8px;
  border: 1px solid var(--surface-2);
  display: none;
}
.arrival-thumb.visible { display: block; }
.stop-counter {
  font-size: 0.85rem;
  color: var(--fg-dim);
  text-align: center;
}
.stop-counter b { color: var(--accent); font-size: 1.1rem; }

.card-display {
  background: var(--surface);
  border: 1px solid var(--surface-2);
  border-radius: var(--radius);
  padding: 24px;
  font-size: 1.15rem;
  line-height: 1.6;
  display: none;
}
.card-display.visible { display: block; }

/* The Inner voice: the hexagram its coordinates carried. */
.card-display .hex {
  text-align: center;
  margin-bottom: 14px;
}
.card-display .hex .glyph {
  display: block;
  font-size: 3.6rem;
  line-height: 1.15;
  color: var(--accent-large);
  text-shadow: 0 0 22px rgba(32, 178, 170, 0.4);
}
.card-display .hex .hex-title {
  display: block;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--fg-dim);
  margin-top: 8px;
}
#card-text.haiku {
  text-align: center;
  white-space: pre-line;
}

.walk-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* --- Archive screen --- */
#screen-archive { gap: 12px; }
.archive-toolbar {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}
.archive-toolbar button {
  padding: 8px 14px;
  font-size: 0.85rem;
}
.archive-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--fg-dim);
  text-align: center;
}
.walk-item {
  background: var(--surface);
  border: 1px solid var(--surface-2);
  border-radius: var(--radius);
  padding: 16px;
  cursor: pointer;
  transition: border-color 0.15s;
  display: flex;
  align-items: center;
  gap: 12px;
}
.walk-item:active { border-color: var(--accent-dim); }
.walk-item .body { flex: 1; min-width: 0; }
.walk-item .meta {
  display: flex;
  justify-content: space-between;
  font-size: 0.85rem;
  color: var(--fg-dim);
}
.walk-item .seed {
  font-family: 'SF Mono', 'Menlo', monospace;
  font-size: 0.8rem;
  color: var(--accent);
}
.walk-delete {
  padding: 8px 12px;
  font-size: 0.85rem;
  flex-shrink: 0;
}

/* --- Detail controls: Skin/Filter rails + action bar ---
   Horizontal scroll-snap token lists and a segmented bar, all in rounded
   surface panels with hairline borders — the Go screen wheel aesthetic
   laid flat. Pinned at the bottom of the screen, above the nav. */
.detail-controls {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex-shrink: 0;
}
.rail-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 46px;
  background: var(--surface);
  border: 1px solid rgba(230, 247, 249, 0.09);
  border-radius: 2px;
  padding: 0 12px;
}
.rail-label {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--fg-dim);
  flex-shrink: 0;
}
/* Mode switcher: two stacked micro-caps in the rail's left gutter. Each
   word is its own tap target; the active one reads as pressed (coral
   text on the lighter teal). */
.rail-modes { display: flex; flex-direction: column; gap: 3px; flex-shrink: 0; }
.rail-mode {
  font-family: inherit;
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--fg-dim);
  background: transparent;
  border: none;
  border-radius: 2px;
  padding: 3px 7px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.rail-mode.active { color: var(--accent); background: var(--surface-2); }
.filter-busy {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent);
  flex-shrink: 0;
}

.rail {
  flex: 1;
  min-width: 0;
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);
  mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);
  -webkit-overflow-scrolling: touch;
}
.rail::-webkit-scrollbar { display: none; }
/* Edge spacers so the first and last tokens can snap to the centre.
   50% each: any token narrower than 20% of the rail (Kitsch, Trippy 3)
   cannot centre with less. */
.rail::before, .rail::after { content: ''; flex: 0 0 50%; }
.rail-item {
  min-height: 44px;
  display: flex;
  align-items: center;
  padding: 0 12px;
  scroll-snap-align: center;
  scroll-snap-stop: always;
  white-space: nowrap;
  cursor: pointer;
  color: var(--fg-dim);
  font-size: 0.9rem;
  font-weight: 500;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  opacity: 0.3;
  transition: opacity 0.15s ease, color 0.15s ease;
}
.rail-item.selected { color: var(--fg); opacity: 1; }
/* Surprise's only flourish: a coral period, same as the logo. */
.rail-item.rail-surprise span, .rail-item.rail-save span { color: var(--accent); }
/* Rail-end affordance: a boxed coral plus opens the filters sheet —
   shaped differently from the bare-word items so it reads as a verb. */
.rail-item.rail-plus { opacity: 0.75; }
.rail-plus .plus-box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border: 1px solid var(--accent);
  border-radius: 2px;
  color: var(--accent);
  font-size: 1.05rem;
  line-height: 1;
}
@media (prefers-reduced-motion: reduce) {
  .rail-item { transition: none; }
}
.rail-add {
  flex-shrink: 0;
  width: 34px; height: 34px;
  border: 1px solid rgba(230, 247, 249, 0.18);
  border-radius: 2px;
  background: none; color: var(--fg-dim);
  font-size: 1.1rem; cursor: pointer;
}
.rail-add:active { color: var(--fg); }
.filter-import-actions { display: flex; gap: 8px; }
.filter-import-actions button {
  flex: 1; padding: 8px;
  background: none; color: var(--fg);
  border: 1px solid rgba(230, 247, 249, 0.18); border-radius: 2px;
  font: inherit; font-size: 0.85rem; cursor: pointer;
}

/* Export trigger. A filled primary button, deliberately NOT a surface
   panel: the Skin/Filter rows above are passive choosers (swipe + tap);
   this is a single tap that opens the export sheet. The different
   treatment (accent fill, no hairline border) signals the different
   action so the two interaction modes are not visually conflated. */
.btn-export {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 48px;
  padding: 12px 16px;
  background: var(--accent-dim);
  color: var(--fg);
  border: 1px solid var(--accent-dim);
  border-radius: var(--radius);
  font-size: 1.1rem;
  font-weight: 700;
  text-transform: lowercase;
  -webkit-tap-highlight-color: transparent;
}
.btn-export:active { background: var(--accent); }
.btn-export .chev { opacity: 0.6; font-weight: 400; letter-spacing: -0.08em; }
.detail-actions { display: flex; gap: 8px; }
.detail-actions .btn-export { flex: 1; }

/* Filter management sheet — same chrome as the export sheet. */
.filter-manage-import { padding: 0 20px 10px; }
.filter-manage-import textarea {
  width: 100%; box-sizing: border-box; resize: vertical;
  background: var(--bg); color: var(--fg);
  border: 1px solid rgba(230, 247, 249, 0.15); border-radius: 2px;
  font-family: monospace; font-size: 0.8rem; padding: 8px;
}
.filter-manage-list { padding-bottom: 10px; }
.filter-manage-list .filter-sub {
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--fg-dim); padding: 10px 20px 2px;
}
.filter-card {
  margin: 0 16px 8px;
  padding: 10px;
  background: var(--surface-2);
  border: 1px solid rgba(230, 247, 249, 0.10);
  border-radius: 6px;
}
.filter-card-head { display: flex; align-items: flex-start; gap: 10px; }
.filter-thumb {
  width: 56px; height: 56px; flex-shrink: 0;
  border-radius: 4px; background: var(--bg);
}
.filter-card-info { flex: 1; min-width: 0; }
.filter-card-info .filter-name {
  font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.filter-effects {
  font-size: 0.72rem; color: var(--fg-dim); margin-top: 3px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.filter-card-delete {
  flex-shrink: 0; padding: 0 2px;
  background: none; border: 0; color: var(--fg-dim);
  font: inherit; font-size: 1rem; cursor: pointer;
}
.filter-card-delete:active { color: var(--danger); }
.filter-card-actions { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.filter-card-export {
  padding: 4px 10px;
  background: none; color: var(--fg);
  border: 1px solid rgba(230, 247, 249, 0.18); border-radius: 2px;
  font: inherit; font-size: 0.78rem; cursor: pointer;
}
.filter-card-export:active { background: rgba(230, 247, 249, 0.08); }
.filter-hide {
  margin-left: auto; display: flex; align-items: center; gap: 6px;
  font-size: 0.78rem; color: var(--fg-dim); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.filter-hide input { width: 16px; height: 16px; accent-color: var(--accent); margin: 0; }
.filter-card.is-hidden .filter-card-info,
.filter-card.is-hidden .filter-thumb { opacity: 0.45; }

/* Bottom export sheet. Overlays the nav bar so it reads as a modal
   action sheet, not another row in the controls column. */
.sheet-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity 0.18s ease;
  z-index: 50;
}
.sheet-overlay.visible { opacity: 1; }
.sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--surface);
  border-top: 1px solid rgba(230, 247, 249, 0.12);
  border-radius: 16px 16px 0 0;
  transform: translateY(100%);
  transition: transform 0.22s cubic-bezier(0.2, 0.8, 0.2, 1);
  z-index: 51;
  padding: 8px 0 16px;
  max-height: 80vh;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.sheet.visible { transform: translateY(0); }
.sheet-handle {
  width: 36px;
  height: 4px;
  background: var(--fg-dim);
  opacity: 0.4;
  border-radius: 2px;
  margin: 4px auto 8px;
}
.sheet-heading {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--fg-dim);
  padding: 4px 20px 8px;
}
.sheet-row {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 14px 20px;
  background: transparent;
  border: none;
  color: var(--fg);
  font-size: 0.95rem;
  text-align: left;
  -webkit-tap-highlight-color: transparent;
}
.sheet-row:active { background: var(--surface-2); }
.sheet-row[hidden] { display: none; }
.sheet-row .row-ico {
  flex-shrink: 0;
  width: 24px;
  text-align: center;
  font-size: 1.15em;
  color: var(--fg-dim);
}
.sheet-row .row-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sheet-row .row-title { font-weight: 500; }
.sheet-row .row-sub { font-size: 0.78rem; color: var(--fg-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (prefers-reduced-motion: reduce) {
  .sheet-overlay, .sheet { transition: none; }
}

/* --- Focused walk state: everything but the compass fades out and
   becomes unresponsive, so pocket taps cannot end the walk --- */
body > header, body > nav, .walk-header, #stop-counter, #card-display,
#screen-walk .walk-actions, #walk-status {
  transition: opacity 0.4s;
}
body.walk-focused > header, body.walk-focused > nav,
body.walk-focused .walk-header, body.walk-focused #stop-counter,
body.walk-focused #card-display,
body.walk-focused #screen-walk .walk-actions, body.walk-focused #walk-status {
  opacity: 0;
  pointer-events: none;
}
/* Focused walk: pure black so OLED pixels are fully off (battery). */
body.walk-focused { background: #000; }
#compass-view { cursor: pointer; }

/* --- Info screen --- */
.info-content { display: flex; flex-direction: column; gap: 8px; }
.info-content h2 { font-size: 1.05rem; margin-top: 16px; color: var(--accent); }
.info-content h2:first-child { margin-top: 0; }
.info-content p { color: var(--fg-dim); font-size: 0.95rem; }
.info-content details { border-bottom: 1px solid var(--surface); padding: 6px 0; }
.info-content summary { cursor: pointer; font-size: 0.95rem; font-weight: 600; padding: 4px 0; }
.info-content a { color: var(--accent); }
.info-content details p { margin: 6px 0; }
.info-content code { color: var(--fg); }
.info-content details ul { color: var(--fg-dim); font-size: 0.95rem; padding-left: 20px; margin: 6px 0; }

/* --- Bottom nav --- */
body > nav {
  display: flex;
  border-top: 1px solid var(--surface);
  /* safe-area inset inside the bar: the nav reaches the screen edge while
     the buttons stay above the home indicator */
  padding-bottom: var(--safe-bottom);
  flex-shrink: 0;
}
body > nav button {
  flex: 1;
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 12px 0;
  font-size: 0.8rem;
  color: var(--fg-dim);
  border-top: 2px solid transparent;
}
body > nav button.active {
  color: var(--accent);
  border-top-color: var(--accent-large);
}

/* --- Storage warning banner --- */
.storage-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--danger);
  font-size: 0.85rem;
  flex-shrink: 0;
}
.storage-banner[hidden] { display: none; }
.storage-banner button {
  background: none;
  border: none;
  color: var(--fg-dim);
  font-size: 1.1rem;
  cursor: pointer;
  padding: 0 4px;
  flex-shrink: 0;
}

/* --- Status / error --- */
.status-msg {
  text-align: center;
  color: var(--fg-dim);
  font-size: 0.9rem;
  padding: 8px;
}
.error-msg {
  color: var(--danger);
  text-align: center;
  font-size: 0.9rem;
  padding: 8px;
}

/* --- Toast (update notification etc.) --- */
#toast {
  position: fixed;
  left: 50%;
  bottom: calc(64px + var(--safe-bottom));
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--surface);
  border: 1px solid var(--surface-2);
  border-radius: 10px;
  padding: 10px 14px;
  font-size: 0.85rem;
  box-shadow: 0 6px 24px rgba(0,0,0,0.45);
  z-index: 80;   /* above the modal overlays (70) - held toasts report progress over them */
  max-width: calc(100vw - 32px);
}
#toast[hidden] { display: none; }

/* --- Confirm dialog (destructive actions) + filename + publish dialogs --- */
#confirm-overlay, #filename-overlay, #photo-hint-overlay, #publish-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  /* Top half, not centred: the mobile keyboard covers the lower half of
     the screen, so a centred input dialog sits behind it. svh over vh:
     the small viewport is the visible area on iOS/Android (fallback
     keeps the same value where svh is unsupported). */
  align-items: flex-start;
  justify-content: center;
  z-index: 70;   /* above bottom sheets (51); toast sits higher again (80) for held progress toasts */
  padding: 15vh 24px 24px;
  padding-top: 15svh;
}
#confirm-overlay[hidden], #filename-overlay[hidden], #photo-hint-overlay[hidden], #publish-overlay[hidden] { display: none; }
#confirm-box, #filename-box, #photo-hint-box, #publish-box {
  background: var(--surface);
  border: 1px solid var(--surface-2);
  border-radius: 12px;
  padding: 18px;
  max-width: 340px;
  width: 100%;
  box-shadow: 0 8px 32px rgba(0,0,0,0.5);
}
#publish-box { max-width: 380px; }
#confirm-text, #photo-hint-text { margin-bottom: 16px; font-size: 0.95rem; }
#filename-label { margin-bottom: 10px; font-size: 0.95rem; }
#filename-input, #neocities-sitename, #publish-desc {
  width: 100%;
  box-sizing: border-box;
  margin-bottom: 16px;
  padding: 10px 12px;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--surface-2);
  border-radius: var(--radius);
  font: inherit;
}
#filename-input:focus, #neocities-sitename:focus, #publish-desc:focus { border-color: var(--accent); outline: none; }
#publish-desc { resize: vertical; margin-bottom: 4px; }
.publish-heading { font-size: 0.95rem; font-weight: 600; margin-bottom: 12px; }
.publish-site-row { display: flex; align-items: center; gap: 6px; margin-bottom: 12px; }
.publish-site-row #neocities-sitename { flex: 1; margin-bottom: 0; }
.publish-suffix { color: var(--fg-dim); font-size: 0.85rem; white-space: nowrap; }
.publish-note { font-size: 0.85rem; color: var(--fg-dim); margin: 8px 0 14px; }
.publish-note a { color: var(--accent); }
.publish-error { font-size: 0.85rem; color: var(--danger); margin: -6px 0 10px; }
.publish-error[hidden] { display: none; }
.publish-url { font-size: 0.85rem; color: var(--accent); word-break: break-all; margin-bottom: 4px; }
.publish-url-index { font-size: 0.75rem; color: var(--fg-dim); }
.publish-check { display: flex; align-items: center; gap: 8px; font-size: 0.85rem; color: var(--fg-dim); margin-bottom: 10px; }
.publish-check input { accent-color: var(--accent); }
.info-version { font-size: 0.7rem; color: var(--fg-dim); text-align: center; margin-top: 32px; opacity: 0.65; cursor: pointer; }
.link-btn { background: none; border: none; padding: 0; color: var(--fg-dim); font-size: 0.8rem; text-decoration: underline; cursor: pointer; margin-bottom: 12px; }
.publish-contents { margin: 0 0 14px 18px; padding: 0; font-size: 0.85rem; color: var(--fg-dim); }
.publish-contents li { margin-bottom: 2px; }
.publish-label { display: block; font-size: 0.85rem; color: var(--fg-dim); margin-bottom: 6px; }
.publish-count { font-size: 0.75rem; color: var(--fg-dim); text-align: right; margin-bottom: 12px; }
.publish-files { list-style: none; margin: 0 0 14px; padding: 0; font-size: 0.85rem; }
.publish-files li { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 4px; }
.publish-files .file-name { word-break: break-all; }
.publish-files .file-size { color: var(--fg-dim); white-space: nowrap; }
.publish-steps { margin: 0 0 14px 18px; padding: 0; font-size: 0.85rem; color: var(--fg-dim); }
.publish-steps li { margin-bottom: 4px; }
.publish-steps code { color: var(--fg); }
#publish-download { width: 100%; margin-bottom: 10px; }
#publish-open-dashboard { width: 100%; margin-bottom: 14px; }
.publish-actions-col { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
.publish-actions-col button { width: 100%; }
.confirm-actions { display: flex; gap: 10px; justify-content: flex-end; }
.confirm-actions button { min-width: 76px; }
.confirm-actions button[disabled] { opacity: 0.45; }
#photo-hint-box .hint-never {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 12px;
  font-size: 0.8rem;
  color: var(--fg-dim);
  cursor: pointer;
}
#photo-hint-box .hint-never input { accent-color: var(--accent); margin: 0; }
#toast .toast-action {
  background: var(--accent);
  color: var(--bg);
  border: none;
  border-radius: 7px;
  padding: 5px 12px;
  font-size: 0.8rem;
  font-weight: 600;
  flex-shrink: 0;
}
.approx-btn {
  background: none;
  border: 1px solid var(--accent-dim);
  color: var(--fg);
  padding: 4px 12px;
  border-radius: 6px;
  font-size: 0.85rem;
  cursor: pointer;
  margin: 0 4px;
}
.approx-btn:active { background: var(--accent-dim); }

/* --- First-visit welcome modal --- */
.welcome-overlay {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.7);
  padding: 24px;
}
.welcome-overlay[hidden] { display: none; }
.welcome-card {
  background: var(--surface);
  border: 1px solid var(--accent-dim);
  border-radius: var(--radius);
  padding: 28px 24px;
  max-width: 400px;
  width: 100%;
  text-align: left;
}
.welcome-card h2 {
  margin-bottom: 16px;
  font-size: 1.3rem;
  color: var(--fg);
}
.welcome-card p {
  font-size: 0.92rem;
  line-height: 1.55;
  color: var(--fg-dim);
  margin-bottom: 14px;
}
.welcome-card strong { color: var(--fg); }
.welcome-card a { color: var(--accent); text-decoration: underline; }
.welcome-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 20px;
}
.welcome-never {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 0.82rem;
  color: var(--fg-dim);
  cursor: pointer;
}
.welcome-never input { accent-color: var(--accent); margin: 0; }
.welcome-btn {
  flex: 0 0 auto;
  min-width: 76px;
  padding: 12px;
  border: 1px solid var(--accent-dim);
  border-radius: var(--radius);
  background: none;
  color: var(--fg);
  font-size: 1rem;
  cursor: pointer;
}
.welcome-btn.primary {
  background: var(--accent);
  color: var(--bg);
  border-color: var(--accent);
  font-weight: 600;
}
.welcome-btn:active { background: var(--accent-dim); color: var(--fg); }
.welcome-btn.primary:active { background: var(--accent-dim); color: var(--fg); }

/* --- Flash for arrival --- */
#arrival-flash {
  position: fixed;
  inset: 0;
  background: var(--accent-large);
  opacity: 0;
  pointer-events: none;
  z-index: 100;
  transition: opacity 0.3s;
}
#arrival-flash.flash { opacity: 0.3; }

/* --- Done screen --- */
#screen-done { gap: 16px; }
.done-view {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.done-view h2 {
  text-align: center;
  font-size: 1.5rem;
}
.done-trace {
  background: var(--surface);
  border: 1px solid var(--surface-2);
  border-radius: var(--radius);
  padding: 16px;
  display: flex;
  justify-content: center;
}
.done-trace svg {
  max-width: 100%;
  height: auto;
}
.done-summary {
  font-size: 0.95rem;
  color: var(--fg-dim);
  line-height: 1.6;
}
.done-summary b { color: var(--fg); }

/* --- Detail screen --- */
/* The Walk result view carries NO decoration of its own: the base styles
   and the active skin are injected from lib/skins.js (scoped to
   #detail-content), exactly as the HTML export embeds them, so a skin
   applies fully here rather than fighting hard-coded dark card styles. */
#screen-detail { gap: 12px; overflow: hidden; }
/* The walk result scrolls; the control block under it stays put. */
#detail-content { flex: 1; min-height: 0; overflow-y: auto; }
#detail-content img { max-width: 100%; }
/* Same .photo-frame rules the export embeds — baked pixels, no filter markup. */
.photo-frame {
  margin-top: 8px;
  border-radius: 8px;
  overflow: hidden;
  /* Long-press selects photos; suppress the OS image sheet/callout and
     the native tap/selection highlight (it paints blue over the photo). */
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
}
.photo-frame img, .photo-frame canvas {
  display: block;
  width: 100%;
  height: auto;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  pointer-events: none;   /* gestures belong to the frame, not the child */
}
/* Selection ring: box-shadow draws outside the frame without touching
   the image or layout. #detail-content prefix keeps it ahead of scoped
   skin rules on the same element. Fixed app blue, not --accent: the
   selection affordance must read as a system-standard colour regardless
   of which skin is showing. */
#detail-content .photo-frame.selected { box-shadow: 0 0 0 4px #7ab8ff; }
/* Skins can use the emitted radio hooks (.stop-open/.stop-shut per
   stop, .zoom-open/.zoom-shut per photo frame) as CSS-only expansion
   state — in the script-free export they are the tap surfaces
   themselves. In-app they must stay out of the way: the long-press
   photo selection lives on .photo-frame, and an invisible overlay
   would swallow its pointerdown. So in-app the inputs stay hidden and
   JS flips .checked instead; the skin's :has(:checked) rules work
   identically. !important because a skin's :has() compound selector
   would otherwise outrank this on an expanded card's .stop-shut. */
#detail-content .stop-open, #detail-content .stop-shut,
#detail-content .zoom-open, #detail-content .zoom-shut,
#detail-content .stop-face, #detail-content .stop-back,
#detail-content .zoom-face, #detail-content .zoom-back {
  display: none !important;
}
/* In-app the artifact's viewport is the detail frame, not the screen.
   Skin overlays (Contact Sheet's lightbox, a zoomed photo, the
   tap-to-close surfaces) use position:fixed + inset:0 — the viewport
   in the export. Pinning them to the frame's rect via --dc-* insets
   (set in JS, refreshed on resize) keeps the same skin rules while
   the rail stays reachable. The [data-seq]/[data-stopseq] attributes
   keep these rules ahead of the scoped skin's identical selectors. */
#detail-content .stop[data-seq] > input.stop-open:checked ~ .stop-body,
#detail-content .stop[data-seq] > input.stop-open:checked ~ .stop-back,
#detail-content .photo-frame[data-stopseq] > input.zoom-open:checked ~ :not(input):not(label),
#detail-content .photo-frame[data-stopseq] > input.zoom-open:checked ~ .zoom-back {
  top: var(--dc-top, 0px);
  right: var(--dc-right, 0px);
  bottom: var(--dc-bottom, 0px);
  left: var(--dc-left, 0px);
}
/* The expanded card's frame number goes fixed too — pin its corner. */
#detail-content .stop[data-seq] > input.stop-open:checked ~ .stop-num {
  top: calc(var(--dc-top, 0px) + 16px);
  left: calc(var(--dc-left, 0px) + 20px);
}
/* The last card's My Voice tail is fixed too — keep it inside the
   frame, clear of the rail. */
#detail-content .myvoice-tail {
  right: calc(var(--dc-right, 0px) + 20px) !important;
  bottom: calc(var(--dc-bottom, 0px) + 20px) !important;
}
/* In-app the trace draw-on is JS-gated: the scroll-centre check in
   showWalkDetail releases the emitted (paused) animation once the
   slide is firmly centred on the snap axis. The skin's own release
   paths — scroll-state queries, the view() scrub, the no-support
   unpause — would fire too early or spend the draw at load, so the
   timeline and play-state are pinned here until JS releases them.
   releaseTrace uses inline !important, the only thing that outranks
   this. Exports have no such gate; the skin CSS handles them. */
#detail-content .tr-line, #detail-content .tr-dot {
  animation-timeline: auto !important;
  animation-range: normal !important;
  animation-play-state: paused !important;
}
.photo-loading {
  height: 120px;
  border-radius: 8px;
  background: linear-gradient(100deg, rgba(255,255,255,0.04) 40%, rgba(255,255,255,0.10) 50%, rgba(255,255,255,0.04) 60%);
  background-size: 200% 100%;
  animation: photoShimmer 1.2s linear infinite;
}
@keyframes photoShimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* --- Portrait nudge overlay --- */
/* iOS Safari does not implement the manifest "orientation" field or
   screen.orientation.lock(), so the only universal way to keep a phone
   in portrait is a soft overlay shown when a touch device is in
   landscape. Desktops (pointer: fine) never see it. */
#portrait-nudge {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  background: var(--bg);
  color: var(--fg);
  padding: 24px;
  text-align: center;
}
#portrait-nudge .nudge-icon {
  width: 64px;
  height: 64px;
  opacity: 0.85;
  animation: nudge-rotate 2.4s ease-in-out infinite;
}
@keyframes nudge-rotate {
  0%, 100% { transform: rotate(0deg); }
  50%      { transform: rotate(-90deg); }
}
#portrait-nudge .nudge-text {
  font-size: 17px;
  letter-spacing: 0.02em;
  color: var(--fg-dim);
}

@media print {
  html, body { height: auto; overflow: visible; }
  body { background: white; color: black; }
  body > header, body > nav, .walk-actions, .detail-controls,
  .sheet-overlay, .sheet,
  #portrait-nudge, #welcome-overlay,
  #screen-go, #screen-walk, #screen-archive, #screen-info { display: none !important; }
  #screen-detail { display: flex !important; overflow: visible; }
  #detail-content { overflow: visible; }
  #detail-content, #detail-content .trace {
    background: white !important; color: black !important; border-color: #ccc !important;
  }
  #detail-content * { color: black !important; }
}

/* --- Desktop landing page ---
   The app is phone software. On devices whose primary pointer is not
   coarse the head script leaves <html> without .app, every top-level app
   element is hidden, and this page shows instead. With no JS at all the
   visitor still gets a readable page, which beats a dead app shell. */
html:not(.app) body > :not(.desktop-page) { display: none !important; }
.desktop-page { display: none; }
html:not(.app) .desktop-page {
  display: flex;
  min-height: 100svh;
  align-items: center;
  justify-content: center;
}
/* Editorial two-column: the words on the left, the walk drawing itself on
   the right. Serif/sans contrast and the delayed second line carry the
   typography — standard fonts only. */
.dp {
  display: flex; align-items: center; gap: clamp(48px, 9vw, 140px);
  max-width: 1080px; padding: 56px 48px;
}
.dp-text { flex: 1 1 auto; min-width: 0; }
.dp-logo { width: 30px; height: 30px; vertical-align: -5px; margin-right: 10px; }
.dp-word { font-size: 1.35rem; font-weight: 600; letter-spacing: 0.03em; margin-bottom: 34px; }
.dp-accent { color: var(--accent); }
.dp-lines {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: clamp(2.75rem, 7vw, 5.25rem);
  line-height: 1.02; letter-spacing: -0.01em;
  margin-bottom: 44px;
}
.dp-lines span { display: block; }
/* The turn lands as the trace finishes drawing: italic, accent-coloured,
   stair-stepped right — choreography borrowed from the app's own SVG. */
.dp-turn {
  font-style: italic; color: #7ab8ff; margin-left: 0.9em;
  opacity: 0; animation: dp-turn-in 0.9s ease-out 5.35s forwards;
}
@keyframes dp-turn-in { to { opacity: 1; } }
.dp-trace svg { display: block; width: clamp(240px, 26vw, 380px); height: auto; cursor: pointer; }
.dp-pitch { max-width: 33em; font-size: 1.02rem; line-height: 1.6; margin-bottom: 12px; }
.dp-calm { color: var(--fg-dim); font-style: italic; margin-bottom: 40px; }
.dp-cta { font-size: 0.95rem; margin-bottom: 52px; }
.dp-cta b {
  font-family: Georgia, 'Times New Roman', serif; font-style: italic;
  font-weight: 400; font-size: 1.2em; color: #7ab8ff;
}
.dp-links { display: flex; gap: 30px; font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase; }
.dp-links a { color: var(--fg-dim); text-decoration: none; }
.dp-links a:hover { color: var(--fg); }
@media (max-width: 720px) {
  .dp { flex-direction: column; align-items: flex-start; gap: 40px; }
}
@media (prefers-reduced-motion: reduce) {
  .dp-turn { opacity: 1; animation: none; }
}
