/* ============================================================================
 * app.css — Wander's own components: the deck and its card, the shelf rows,
 * the trip planner, and the sheets' insides.
 *
 * Shell vocabulary (.topbar, .tabbar, .view, .sheet, .btn, .chip, .badge,
 * .empty-state) lives in components.css and is not redefined here. Naming
 * is flat kebab-case with a component prefix: place-card, place-row,
 * trip-card, booking-row, shelf-head.
 * ========================================================================= */

/* ---------- section heads ------------------------------------------------ */

.section-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin: 2px 0 12px;
}
.section-title { margin: 0; font-size: 1.35rem; font-weight: 800; letter-spacing: -0.01em; }
.section-count { color: var(--ink-faint); font-size: 0.85rem; font-weight: 700; }

/* ---------- deck ---------------------------------------------------------- */

.deck-toolbar { margin-bottom: 10px; }
/* One row that scrolls sideways, never two rows. The deck's height is
 * computed from what is left after the toolbar, so a chip row that wraps on
 * a narrow phone would silently push the Save and Skip buttons under the
 * tab bar. Scrollbars are hidden; the row is short enough to thumb. */
.deck-toolbar .chip-row {
  gap: 6px; flex-wrap: nowrap;
  overflow-x: auto; scrollbar-width: none;
  margin: 0 -14px; padding: 0 14px;
}
.deck-toolbar .chip-row::-webkit-scrollbar { display: none; }
.deck-toolbar .chip { flex: none; }
.chip-gap { flex: none; width: 6px; }
.deck-count {
  margin: 8px 2px 0;
  color: var(--ink-faint);
  font-size: 0.78rem; font-weight: 700;
}

/* The deck is a fixed-aspect stage: the card fills it, and the card behind
 * peeks out by being scaled down and nudged. Height is derived from the
 * viewport so on a short phone (667px) the card, its buttons and the chips
 * all fit above the tab bar without scrolling — a deck you have to scroll
 * to swipe is not a deck. On a tall phone it stops growing at 560px so the
 * photo never becomes a wall. */
.deck {
  position: relative;
  /* 180px is the toolbar (one chip row + count), the button row and the
   * container's own padding, measured. The 340px floor is where a 375x667
   * phone lands with a hair to spare; below it the page scrolls, which is
   * survivable, but the buttons must never sit under the tab bar. */
  height: clamp(340px, calc(100dvh - var(--topbar-h) - var(--tabbar-h) - var(--safe-t) - var(--safe-b) - 180px), 560px);
  touch-action: pan-y;    /* vertical scroll stays with the page; horizontal drag is ours */
}

.deck-empty { position: absolute; inset: 0; display: grid; place-content: center; }

.place-card {
  position: absolute; inset: 0;
  border-radius: var(--radius);
  cursor: grab;
  user-select: none;
  will-change: transform;
  /* perspective on the card, so the flip has depth */
  perspective: 1400px;
  --stamp-save: 0;
  --stamp-skip: 0;
}
.place-card.is-top { z-index: 2; }
.place-card.is-next {
  z-index: 1;
  transform: scale(0.95) translateY(14px);
  opacity: 0.9;
  pointer-events: none;
}
.place-card.is-leaving { pointer-events: none; }
.place-card:active { cursor: grabbing; }

.place-card-inner {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transition: transform 480ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.place-card.is-flipped .place-card-inner { transform: rotateY(180deg); }

.place-face {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  border-radius: var(--radius);
  background: var(--bg-raised);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.place-back { transform: rotateY(180deg); }

/* The photo frame. Three states, set by images.js on the frame:
 *   loading — gradient + faint glyph while the lookup runs
 *   ready   — the photo, full bleed
 *   none    — gradient + glyph, permanently (offline, or no image exists)
 * The gradient is the two sky tints, so a card without a photo still looks
 * like Wander rather than like a broken image. */
/* The photo takes whatever the text does not. The text block below is
 * capped (two lines of name, three of blurb), so on a short card the photo
 * shrinks rather than the copy clipping; on a tall one it grows. */
.place-photo {
  position: relative;
  flex: 1 1 0;
  min-height: 120px;
  background: linear-gradient(160deg, var(--sky) 0%, var(--sky-deep) 100%);
  overflow: hidden;
}
.place-img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  transition: opacity 300ms ease;
  pointer-events: none;
}
[data-photo="ready"] .place-img { opacity: 1; }
.place-glyph {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-size: 4rem;
  opacity: 0.85;
  filter: drop-shadow(0 4px 10px rgb(16 37 64 / 0.18));
  transition: opacity 300ms ease;
  pointer-events: none;
}
[data-photo="loading"] .place-glyph { opacity: 0.35; }
[data-photo="ready"] .place-glyph { opacity: 0; }

.place-badges {
  position: absolute; top: 12px; left: 12px; right: 12px;
  display: flex; gap: 6px; flex-wrap: wrap;
}
.place-badges .badge {
  background: rgb(255 255 255 / 0.88);
  border-color: transparent;
  color: var(--ink);
  backdrop-filter: blur(6px);
}
.badge-natural { color: var(--good) !important; }
.badge-manmade { color: var(--accent) !important; }

.place-front-body {
  flex: 0 0 auto;
  padding: 14px 16px 12px;
  display: flex; flex-direction: column;
  gap: 4px;
}
.place-name {
  margin: 0;
  font-size: 1.3rem; line-height: 1.15;
  font-weight: 800; letter-spacing: -0.01em;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.place-where {
  margin: 0;
  display: flex; align-items: center; gap: 4px;
  color: var(--ink-soft);
  font-size: 0.85rem; font-weight: 700;
}
.place-pin { font-size: 0.85em; }
.place-blurb {
  margin: 4px 0 0;
  color: var(--ink);
  font-size: 0.95rem; line-height: 1.4;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
}
.place-hint {
  margin: 6px 0 0;
  color: var(--ink-faint);
  font-size: 0.72rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
}

/* The back is a page of paper, not a photo: pale sky, more text, room to
 * breathe. Four sentences at 0.95rem fit a 375px card with the head above. */
.place-back {
  background: linear-gradient(180deg, #ffffff 0%, var(--bg) 100%);
  padding: 18px 18px 14px;
  gap: 10px;
}
.place-back-head { display: flex; flex-direction: column; gap: 4px; }
.place-about {
  margin: 0;
  font-size: 0.95rem; line-height: 1.5;
  color: var(--ink);
  overflow-y: auto;
  flex: 1 1 auto; min-height: 0;
}
.place-back-foot {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}
.place-back-foot .place-hint { margin-left: auto; }

/* Stamps: fade in with the drag so you know what letting go will do. The
 * opacity is a CSS variable the drag handler writes, so the stamp tracks the
 * finger with no JS on the paint path. */
.place-stamp {
  position: absolute; top: 22px;
  padding: 6px 14px;
  border: 3px solid;
  border-radius: 10px;
  font-family: var(--font-display);
  font-size: 1.6rem; font-weight: 900; letter-spacing: 0.08em;
  background: rgb(255 255 255 / 0.9);
  pointer-events: none;
  z-index: 3;
}
.place-stamp-save { left: 18px; color: var(--accent); border-color: var(--accent); transform: rotate(-14deg); opacity: var(--stamp-save); }
.place-stamp-skip { right: 18px; color: var(--ink-soft); border-color: var(--ink-soft); transform: rotate(14deg); opacity: var(--stamp-skip); }

/* Save is blue, Skip is white — see tokens.css for why. */
.deck-actions {
  display: grid;
  grid-template-columns: 1fr 44px 1fr;
  gap: 10px;
  align-items: center;
  margin-top: 14px;
}
.deck-actions .btn { min-height: 52px; font-size: 1rem; }
.btn-skip { background: var(--bg-raised); border-color: var(--line-strong); color: var(--ink); }
.btn-save { box-shadow: 0 6px 16px -6px rgb(47 128 237 / 0.6); }
.undo-btn { justify-self: center; font-size: 1.2rem; }
.undo-btn:disabled { opacity: 0.35; cursor: default; }

/* ---------- shelf rows (Explore, Trips) ---------------------------------- */

.search {
  width: 100%;
  min-height: 44px;
  padding: 10px 14px;
  margin-bottom: 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--bg-raised);
  color: var(--ink);
  font-size: 1rem;       /* 16px: under that iOS zooms the page on focus */
}
.explore-filters { margin-bottom: 12px; }

.place-list { display: flex; flex-direction: column; gap: 8px; }

.place-row, .trip-card {
  display: flex; align-items: center; gap: 12px;
  width: 100%;
  padding: 8px;
  text-align: left;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--bg-raised);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  font: inherit;
}
.place-thumb {
  position: relative;
  flex: none;
  width: 64px; height: 64px;
  border-radius: 10px;
  overflow: hidden;
  background: linear-gradient(160deg, var(--sky) 0%, var(--sky-deep) 100%);
}
.place-thumb .place-glyph { font-size: 1.6rem; }
.place-row-body { flex: 1 1 auto; min-width: 0; }
.place-row-name { font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.place-row-where { color: var(--ink-soft); font-size: 0.8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.place-row-action { flex: none; min-height: 36px; padding: 6px 10px; font-size: 0.8rem; color: var(--accent); }

.skipped-drawer { margin-top: 20px; }
.skipped-drawer summary {
  cursor: pointer;
  font-weight: 800; color: var(--ink-soft);
  padding: 10px 0;
  min-height: 44px;
}
.skipped-drawer .panel-sub { margin-bottom: 8px; }

/* ---------- place detail sheet ------------------------------------------ */

.sheet-tall { max-height: 92dvh; }
.detail-photo {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: linear-gradient(160deg, var(--sky) 0%, var(--sky-deep) 100%);
  margin-bottom: 12px;
}
.detail-photo .place-glyph { font-size: 3rem; }
.detail-where { margin-bottom: 8px; }
.detail-badges { position: static; margin-bottom: 10px; }
.detail-badges .badge { background: var(--bg-sunken); }
.detail-blurb { margin: 0 0 8px; font-weight: 700; line-height: 1.4; }
.detail-about { margin: 0 0 16px; line-height: 1.55; color: var(--ink); }
.detail-head { margin: 0 0 8px; font-size: 0.8rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-faint); }
.detail-credit { margin: 10px 0 0; color: var(--ink-faint); font-size: 0.75rem; }
.detail-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }

.link-list { display: flex; flex-wrap: wrap; gap: 8px; }
.link-btn { min-height: 40px; padding: 8px 14px; font-size: 0.85rem; text-decoration: none; }
.link-btn::after { content: "↗"; font-size: 0.8em; opacity: 0.6; }

/* ---------- trips -------------------------------------------------------- */

.trip-card-meta { color: var(--ink-faint); font-size: 0.75rem; font-weight: 700; margin-top: 2px; }

.detail-bar { display: flex; justify-content: space-between; align-items: center; margin: -4px 0 8px; }
.btn-danger-text { color: var(--bad); }

.trip-head { margin-bottom: 12px; }
.input {
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--bg-raised);
  color: var(--ink);
  font-size: 1rem;
}
textarea.input { resize: vertical; min-height: 72px; line-height: 1.4; }
.input-title { font-size: 1.25rem; font-weight: 800; border-color: transparent; padding-left: 0; background: transparent; }
.trip-head .place-where { margin: 2px 0 10px; }
.field { display: flex; flex-direction: column; gap: 4px; flex: 1 1 0; min-width: 0; }
.field-label { font-size: 0.72rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-faint); }
.field-row { display: flex; gap: 10px; }
.trip-dates-summary { margin: 8px 0 12px; color: var(--ink-soft); font-size: 0.85rem; font-weight: 700; min-height: 1em; }
.form { display: flex; flex-direction: column; gap: 12px; }
.form-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }

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

/* ---------- the four categories ------------------------------------------
 * Collapsed, each is one 60px row: icon, name, and what is in it. That is
 * the trip screen — four rows and nothing to scroll past. Everything else
 * lives inside and only appears when asked for. */
.cat {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.cat-head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 14px;
  min-height: 60px;                 /* thumbs, not cursors */
  cursor: pointer;
  list-style: none;                 /* kill the default disclosure triangle */
  user-select: none;
}
/* Safari draws its own marker and ignores list-style on a summary. */
.cat-head::-webkit-details-marker { display: none; }
/* Nudged down two pixels, and it is a real correction rather than a fudge.
 * `align-items: center` centres the icon's LINE BOX against the two-line text
 * block, but an emoji glyph carries its visual mass above the baseline and
 * leaves the descender space empty — so a mathematically centred emoji reads
 * as floating high next to text. Two pixels puts the optical centres level.
 * Measure from the picture, not from the box model. */
.cat-icon {
  font-size: 1.35rem;
  line-height: 1;
  flex: none;
  transform: translateY(2px);
}
.cat-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.cat-title { font-weight: 800; font-size: 1rem; }
.cat-sub {
  color: var(--ink-faint);
  font-size: 0.8rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Named bookings read as content, not as a hint. */
.cat-sub.booked { color: var(--ink-soft); font-weight: 600; }
.cat-count {
  flex: none;
  min-width: 22px; height: 22px;
  padding: 0 6px;
  display: grid; place-items: center;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--accent-contrast);
  font-size: 0.72rem; font-weight: 800;
}
.cat-chevron {
  flex: none;
  color: var(--ink-faint);
  font-size: 1.3rem;
  transform: rotate(90deg);
  transition: transform 180ms ease;
}
.cat[open] .cat-chevron { transform: rotate(-90deg); }
.cat-body { padding: 0 14px 14px; display: flex; flex-direction: column; gap: 8px; }
.cat-group { margin-top: 4px; }
.cat-group-title {
  margin: 0 0 6px;
  font-size: 0.72rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-faint);
}
.booking-list { display: flex; flex-direction: column; gap: 6px; }
.booking-row {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 10px 12px;
  text-align: left; font: inherit;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--bg-sunken);
  color: var(--ink);
  cursor: pointer;
}
.booking-body { flex: 1 1 auto; min-width: 0; }
.booking-title { font-weight: 800; }
.booking-meta { color: var(--ink-soft); font-size: 0.8rem; margin-top: 2px; }
.booking-notes { color: var(--ink-faint); font-size: 0.8rem; margin-top: 2px; white-space: pre-wrap; }
.booking-link { min-height: 36px; padding: 6px 10px; font-size: 0.8rem; text-decoration: none; color: var(--accent); }
.add-booking-btn { border-style: dashed; color: var(--ink-soft); }

.trip-calendar { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.trip-calendar .btn { font-size: 0.85rem; padding: 8px 12px; min-height: 40px; }
.trip-calendar .btn { flex: 1 1 auto; }
/* Notes fold away. Most trips have none, and an empty textarea taking a
 * third of the screen above your bookings is the opposite of what this
 * screen is for. */
.trip-notes { margin-top: 10px; }
.trip-notes-head {
  display: flex; align-items: center; gap: 8px;
  min-height: 44px;
  cursor: pointer; list-style: none;
  font-size: 0.72rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-faint);
}
.trip-notes-head::-webkit-details-marker { display: none; }
.trip-notes-peek {
  flex: 1 1 auto; min-width: 0;
  text-transform: none; letter-spacing: 0; font-weight: 600;
  color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.trip-notes .input { margin-bottom: 4px; }

/* ---------- offline pill -------------------------------------------------
 * Sits in the topbar beside the install offer. Deliberately understated:
 * being offline is a normal state for this app, not a fault. */
.offline-pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 5px 10px;
  border-radius: var(--radius-pill);
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  color: var(--ink-soft);
  font-size: 0.72rem; font-weight: 800;
  white-space: nowrap;
}

/* ---------- settings sheet ---------------------------------------------- */

.settings-line { margin: 0 0 14px; color: var(--ink-soft); font-size: 0.85rem; font-weight: 700; }
.settings-group { padding: 12px 0; border-top: 1px solid var(--line); }
.settings-head { margin: 0 0 4px; font-size: 0.95rem; font-weight: 800; }
.settings-actions { display: flex; flex-wrap: wrap; gap: 8px; }

/* ---------- date range picker -------------------------------------------
 * One calendar, two taps — see js/daterange.js for the behaviour. The visual
 * job here is the one every booking site solves the same way, because it is
 * the only arrangement that reads at a glance: the two chosen days are pills,
 * and the days between them are a flat tinted band that runs edge to edge
 * through the cells so a week looks like a continuous stretch of time rather
 * than seven separate squares.
 *
 * The band is a ::before on the day cell, inset vertically and NOT
 * horizontally, so adjacent cells' bands meet with no seam. The start cell's
 * band begins at the cell's centre and the end cell's stops there, which is
 * exactly where the pill sits — so the band appears to grow out from under
 * the pill instead of sticking out past it. */

.dr {
  display: flex;
  flex-direction: column;
  /* The band is the accent at low strength mixed into the sheet's own white,
   * not the accent at low opacity: mixing keeps it opaque, so the pill's edge
   * stays crisp where the two overlap. */
  --dr-band: color-mix(in srgb, var(--accent) 12%, var(--bg-raised));
  /* 46px, not 44: the cell is the touch target and it needs to still clear 44
   * after the grid's own rounding on a 375px phone. */
  --dr-cell: 46px;
}

.dr-weekhead {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}
.dr-weekhead span {
  text-align: center;
  font-size: 0.72rem; font-weight: 800;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
}

/* Its own scroller rather than letting .sheet-body scroll, so the summary and
 * Done stay on screen while the months move. Height is viewport-derived and
 * capped: about a month and a half is visible on a tall phone, which is what
 * makes a range across a month boundary one gesture. overscroll-behavior
 * stops a flick at the end of the list from dragging the sheet down with it. */
.dr-scroll {
  overflow-y: auto;
  overscroll-behavior: contain;
  height: clamp(220px, 52dvh, 480px);
  /* Bleed to the sheet's padding edge so the band reaches the full width of
   * the grid, then put the padding back inside. */
  margin: 0 -2px;
  padding: 0 2px;
}

.dr-earlier { min-height: 44px; color: var(--ink-faint); font-size: 0.85rem; }
/* .btn sets a display, which beats the [hidden] attribute's UA rule. */
.dr-earlier[hidden] { display: none; }

.dr-month { padding-bottom: 12px; }
.dr-month-name {
  position: sticky; top: 0; z-index: 1;
  margin: 0;
  padding: 12px 2px 8px;
  background: var(--bg-raised);
  font-size: 0.95rem; font-weight: 800;
}

.dr-grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.dr-pad { min-height: var(--dr-cell); }

.dr-day {
  position: relative;
  height: var(--dr-cell);
  min-height: 44px;              /* thumbs, not cursors */
  display: grid; place-items: center;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  /* Only ever seen as the shape of the focus ring — the cell itself has no
   * background. A rounded rectangle around the cell reads better here than
   * base.css's 4px, which looks like a mistake against a round pill. */
  border-radius: var(--radius-sm);
  /* Clears the sticky month heading when a key press scrolls a day into view. */
  scroll-margin: 44px 0 12px;
  -webkit-tap-highlight-color: transparent;
}
.dr-day:disabled { color: var(--ink-faint); opacity: 0.35; cursor: default; }

.dr-day::before {
  content: "";
  position: absolute;
  top: 3px; bottom: 3px; left: 0; right: 0;
  background: var(--dr-band);
  display: none;
}
.dr-day.in-range::before { display: block; }
.dr-day.is-start::before { left: 50%; }
.dr-day.is-end::before   { right: 50%; }
/* A single day picked, or a one-day trip: a pill and nothing to join it to. */
.dr-day.is-start.is-end::before { display: none; }

/* position: relative puts the number above the band — both are positioned, so
 * document order decides, and ::before is the first child. */
.dr-day-n {
  position: relative;
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: var(--radius-pill);
  font-size: 0.95rem; font-weight: 700;
}
.dr-day.is-start .dr-day-n,
.dr-day.is-end .dr-day-n {
  background: var(--accent);
  color: var(--accent-contrast);
  font-weight: 800;
}

/* Today is a dot under the numeral, not a ring: a ring reads as "selected" on
 * a calendar and there is already a selection language in play. */
.dr-day.is-today .dr-day-n::after {
  content: "";
  position: absolute;
  bottom: 4px; left: 50%;
  width: 4px; height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: var(--accent);
}
.dr-day.is-today.is-start .dr-day-n::after,
.dr-day.is-today.is-end .dr-day-n::after { background: var(--accent-contrast); }

.dr-foot {
  border-top: 1px solid var(--line);
  padding-top: 12px;
  display: flex; flex-direction: column; gap: 10px;
}
.dr-summary {
  margin: 0;
  min-height: 1.3em;
  font-size: 0.9rem; font-weight: 800;
  color: var(--ink);
}
.dr-summary.is-empty { color: var(--ink-faint); font-weight: 700; }
.dr-foot-actions { display: flex; gap: 8px; }
.dr-foot-actions .btn { flex: 1 1 0; }

/* ---------- pointer-only affordances -------------------------------------
 * EVERY :hover rule in this file lives here — see components.css for why. */
@media (hover: hover) {
  .place-row:hover, .trip-card:hover { border-color: var(--line-strong); }
  .dr-day:not(:disabled):hover .dr-day-n { background: var(--bg-sunken); }
  .dr-day.is-start:hover .dr-day-n,
  .dr-day.is-end:hover .dr-day-n { background: var(--accent-soft); }
  .dr-earlier:hover { color: var(--accent); }
  .booking-row:hover { border-color: var(--line-strong); }
  .cat-head:hover { background: var(--bg-sunken); }
  .date-range-btn:hover { border-color: var(--accent); }
  .btn-skip:hover { border-color: var(--ink-soft); color: var(--ink); }
  .link-btn:hover { border-color: var(--accent); color: var(--accent); }
  .add-booking-btn:hover { border-color: var(--accent); color: var(--accent); }
}

/* Motion is opt-in. The flip and the fly-out are transitions set inline or
 * above; the blanket kill-switch in base.css already zeros them under
 * prefers-reduced-motion, so nothing extra is needed here. */

/* ---------- gallery (place sheet) ----------------------------------------
 * A horizontal scroll-snap strip rather than a carousel with arrows: it is
 * the gesture people already use for photos on a phone, it needs no JS to
 * animate, and it degrades to a plain scrollable row if anything fails. */
.gallery { margin-bottom: 12px; }
.gallery-strip {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  /* The strip bleeds to the sheet edges so a photo can be full width, while
   * the padding keeps the first and last from touching the sides. */
  margin: 0 -16px;
  padding: 0 16px;
  -webkit-overflow-scrolling: touch;
}
.gallery-strip::-webkit-scrollbar { display: none; }
.gallery-strip .detail-photo {
  flex: 0 0 100%;
  scroll-snap-align: center;
  margin-bottom: 0;
}
.gallery:not(.has-gallery) .gallery-meta { display: none; }
.gallery-meta {
  display: flex; align-items: center; gap: 10px;
  margin-top: 8px;
  min-height: 18px;
}
.gallery-dots { display: flex; gap: 5px; flex: none; }
.gallery-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--line-strong);
  transition: background-color 150ms ease;
}
.gallery-dot.active { background: var(--accent); }
.gallery-credit {
  margin: 0;
  flex: 1 1 auto; min-width: 0;
  color: var(--ink-faint);
  font-size: 0.7rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The range control in a form: looks like the inputs beside it, reads like a
 * value when set and like a prompt when not. */
.date-range-btn {
  text-align: left;
  font-weight: 700;
  cursor: pointer;
  display: flex; align-items: center;
}
.date-range-btn.is-empty { color: var(--ink-faint); font-weight: 600; }

/* The photo self-test's verdict. Coloured, because the whole point is to say
 * at a glance whether this is a problem with the device or with the data. */
.photo-verdict {
  margin-top: 8px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--bg-sunken);
  line-height: 1.45;
}
.photo-verdict.is-good { background: var(--good-bg); border-color: color-mix(in srgb, var(--good) 30%, transparent); color: var(--good); }
.photo-verdict.is-bad { background: var(--bad-bg); border-color: color-mix(in srgb, var(--bad) 30%, transparent); color: var(--bad); }
