/* Palette carried over from trips v1 so the two sites read as one thing. */
/* Palette carried over from trips v1 so the two sites read as one thing.
   Preserved deliberately: this is a facelift, not a rebrand. */
/* ---------------------------------------------------------------------------
   October. Warm near-black, ember and pine, paper grain.
   Replaces the cool blue-grey inherited from trips v1: that palette was right
   for a Chicago wedding in August and wrong for a foliage weekend in Vermont.
   The point of this page is to make people want to come.
   --------------------------------------------------------------------------- */

/* Bricolage Grotesque, SIL OFL 1.1, self-hosted. One variable display face at
   77 KB, used for headings only; body text stays on the system stack so the
   page still paints instantly on a phone. */
@font-face {
  font-family: "Bricolage";
  src: url("/assets/bricolage-grotesque-78692770.woff2") format("woff2-variations");
  font-weight: 400 800;
  font-display: swap;
  font-style: normal;
}

:root {
  color-scheme: dark;

  /* Warm dark. Never pure black: #0f0b08 has red in it, which is what stops the
     page reading as a terminal. */
  --bg: #0f0b08;
  --bg-deep: #0a0705;
  --panel: #17110d;
  --panel-2: #1f1712;
  --line: #2e231b;
  --line-soft: #241b15;

  --text: #f2e9dc;      /* oat */
  --text-dim: #cbbca9;
  --muted: #9a8974;

  /* Ember is the single accent. Pine is semantic-adjacent (confirmed, in) and
     harvest is the caution hue. Three warm hues, one cool, all in the same
     family so nothing looks pasted in. */
  --accent: #e0672a;    /* ember */
  --accent-soft: rgba(224, 103, 42, 0.14);
  --accent-line: rgba(224, 103, 42, 0.42);
  --accent-glow: rgba(224, 103, 42, 0.24);

  --ok: #6f9f74;        /* pine */
  --warn: #d99a3c;      /* harvest */
  --bad: #c8543f;       /* rust */

  --k-travel: #c4a678;
  --k-lodging: #b98b5e;
  --k-food: #d99a3c;
  --k-sight: #6f9f74;
  --k-event: #c8543f;
  --k-free: #9a8974;

  /* Squircle radii, concentric for the double-bezel. */
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 26px;
  --r-shell: 30px;
  --r-core: 22px;      /* r-shell minus the shell padding */
  --radius: var(--r-md);

  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 36px; --s-7: 56px; --s-8: 88px;
  --s-9: 128px;

  --font-display: "Bricolage", ui-sans-serif, -apple-system, system-ui, sans-serif;
  --font-sans: ui-sans-serif, -apple-system, "SF Pro Text", system-ui, sans-serif;
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, monospace;

  --t-hero: clamp(2.35rem, 1.3rem + 5vw, 4.6rem);
  --t-h2:   clamp(1.35rem, 1.1rem + 1.1vw, 1.95rem);
  --t-h3:   1.06rem;
  --t-body: 0.97rem;
  --t-sm:   0.86rem;
  --t-xs:   0.785rem;

  /* One spring-ish curve, no linear, no ease-in-out. */
  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --fast: 180ms;
  --mid: 380ms;
  --slow: 760ms;

  /* Warm shadows. A neutral black shadow on a warm surface looks like a hole. */
  --shadow-soft: 0 1px 2px rgba(20, 10, 4, 0.4), 0 12px 34px rgba(20, 10, 4, 0.34);
  --shadow-lift: 0 2px 4px rgba(20, 10, 4, 0.44), 0 26px 60px rgba(20, 10, 4, 0.42);
}

* { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* Paper grain. Fixed and non-interactive so it is composited once and never
   repaints while scrolling, which is the difference between texture and jank. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  opacity: 0.05;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* A low warm wash behind everything, so the background is not a flat fill. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(1100px 620px at 12% -10%, rgba(224, 103, 42, 0.13), transparent 62%),
    radial-gradient(900px 520px at 96% 4%, rgba(111, 159, 116, 0.09), transparent 58%),
    linear-gradient(180deg, var(--bg) 0%, var(--bg-deep) 100%);
}

html, body {
  margin: 0;
  min-height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-feature-settings: "kern" 1, "liga" 1;
  font-size: var(--t-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* Removes the 300ms double-tap delay on touch devices. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(110, 168, 254, 0.18);
}

/* Keyboard users get a visible ring; mouse users do not get one on click. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}
:focus:not(:focus-visible) { outline: none; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.skip-link {
  position: absolute;
  left: var(--s-3);
  top: calc(-1 * var(--s-8));
  z-index: 100;
  background: var(--accent);
  color: #0b1017;
  font-weight: 650;
  padding: 10px 14px;
  border-radius: var(--r-sm);
  transition: top var(--fast) var(--ease);
}
.skip-link:focus-visible { top: var(--s-3); text-decoration: none; }

.wrap {
  max-width: 60rem;
  margin: 0 auto;
  /* Safe-area padding so content clears the notch and home indicator. */
  padding:
    0
    max(var(--s-4), env(safe-area-inset-right))
    calc(var(--s-8) + env(safe-area-inset-bottom))
    max(var(--s-4), env(safe-area-inset-left));
}
@media (min-width: 640px) { .wrap { padding-left: var(--s-5); padding-right: var(--s-5); } }

/* ---------- header ---------- */

.topbar {
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  backdrop-filter: blur(10px);
  position: sticky;
  top: 0;
  z-index: 10;
  padding-top: env(safe-area-inset-top);
}
@supports not (backdrop-filter: blur(10px)) { .topbar { background: var(--panel); } }
.topbar-inner {
  max-width: 60rem;
  margin: 0 auto;
  padding: var(--s-3) max(var(--s-4), env(safe-area-inset-left));
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
}
.topbar .brand {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.14rem;
  font-weight: 640;
  letter-spacing: -0.035em;
}
.topbar .brand a { color: var(--text); }
.topbar .brand a:hover { color: var(--accent); text-decoration: none; }
.topbar .dates {
  color: var(--muted);
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
}
.topbar .spacer { flex: 1; }
.topbar .who {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--t-sm);
  color: var(--muted);
}

/* On a phone the title, the identity row and a 7-item tab strip stacked into
   three rows and ate a third of the viewport before any content. Two rows is the
   floor for a tabbed app at this width, so the redundant parts go: the date is
   repeated in the hero, and the avatar already carries the identity. */
@media (max-width: 560px) {
  .topbar-inner {
    flex-wrap: nowrap;
    padding-top: var(--s-2);
    padding-bottom: var(--s-2);
    gap: var(--s-2);
  }
  .topbar .dates, .topbar .who-name { display: none; }
  .topbar .brand { font-size: 1.02rem; }
  .topbar .brand a { white-space: nowrap; }
}

.tabs {
  max-width: 60rem;
  margin: 0 auto;
  padding: 0 max(var(--s-4), env(safe-area-inset-left));
  display: flex;
  gap: var(--s-1);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs { overscroll-behavior-x: contain; scroll-snap-type: x proximity; }
.tab {
  padding: 11px 13px;
  font-size: var(--t-sm);
  font-weight: 520;
  color: var(--muted);
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  scroll-snap-align: start;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.tab:hover { color: var(--text); text-decoration: none; }
.tab.active { color: var(--text); border-bottom-color: var(--accent); }

/* ---------- structure ---------- */

h2 {
  font-family: var(--font-display);
  font-size: var(--t-h2);
  font-weight: 620;
  margin: var(--s-8) 0 var(--s-4);
  letter-spacing: -0.025em;
  line-height: 1.08;
  text-wrap: balance;
}
h3 {
  font-family: var(--font-display);
  font-size: var(--t-h3);
  font-weight: 600;
  margin: 0 0 var(--s-1);
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.sub {
  color: var(--muted);
  font-size: var(--t-sm);
  margin: var(--s-1) 0 0;
  text-wrap: pretty;
  max-width: 68ch;
}
.muted { color: var(--muted); }
.right { text-align: right; }

.card {
  background: linear-gradient(180deg, rgba(255, 238, 220, 0.035), rgba(255, 238, 220, 0.008));
  border: 1px solid rgba(255, 232, 210, 0.08);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-soft);
  padding: var(--s-4);
  margin-bottom: var(--s-3);
}
@media (min-width: 640px) { .card { padding: var(--s-5); } }

/* Elevation only where it means something: the booked house, and options still
   in play. Everything else groups with a hairline. */
.card.booked {
  border-color: var(--ok);
  box-shadow: 0 0 0 1px rgba(95, 214, 166, 0.22), 0 12px 32px rgba(0, 0, 0, 0.28);
}
.card.rejected { opacity: 0.6; }
/* Page title with its "add a thing" action. Previously the button was floated
   inside the h2, which took it out of flow -- on a narrow screen it overlapped
   the heading text, and it could not be made a full-size CTA without pushing
   into the line above. */
/* Unread count on a nav tab. Ember fill rather than a neutral grey: the whole
   job of this badge is to pull someone back into a page they've already seen. */
.tab-new {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--accent);
  color: #17100a;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  vertical-align: 2px;
}

/* Booking countdown. Sits with the trip dates in the header area, and shifts
   from quiet to loud as the date closes in (see Trip#deadline_tone). */
.deadline {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: 4px 11px;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: var(--t-xs);
  font-weight: 600;
}
.deadline.ok   { color: var(--muted); }
.deadline.warn { color: var(--accent); border-color: var(--accent-line); background: rgba(224, 103, 42, 0.1); }
.deadline.bad  { color: #e0a08f; border-color: rgba(200, 84, 63, 0.5); background: rgba(200, 84, 63, 0.14); }

.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  flex-wrap: wrap;
}
.page-head h2 { margin: 0; }

.card-head { display: flex; gap: var(--s-3); align-items: flex-start; }
.card-head .grow { flex: 1; min-width: 0; }

.grid { display: grid; gap: 12px; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }

.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.stack > * + * { margin-top: 8px; }

/* ---------- numbers ---------- */

.stat {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
}
.stat .k { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; }
.stat .v { font-size: 22px; font-variant-numeric: tabular-nums; margin-top: 2px; }
.stat .v.small { font-size: 17px; }

.money-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.money-table td { padding: 5px 0; border-bottom: 1px solid var(--line); }
.money-table tr:last-child td { border-bottom: 0; }
.money-table td:last-child {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  letter-spacing: -0.02em;
}
.money-table .headline td { font-size: 16px; }

/* ---------- chips / badges ---------- */

.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: var(--t-xs);
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--muted);
  white-space: nowrap;
}
.badge.rsvp-in     { color: var(--ok);   border-color: rgba(95,214,166,.4); }
.badge.rsvp-maybe  { color: var(--warn); border-color: rgba(255,177,92,.4); }
.badge.rsvp-out    { color: var(--bad);  border-color: rgba(255,143,163,.4); }
.badge.status-booked   { color: var(--ok);   border-color: rgba(95,214,166,.4); }
.badge.status-proposed { color: var(--accent); border-color: rgba(110,168,254,.4); }
.badge.status-rejected { color: var(--bad);  border-color: rgba(255,143,163,.4); }
.badge.status-planned  { color: var(--ok);   border-color: rgba(95,214,166,.4); }
.badge.status-idea     { color: var(--accent); border-color: rgba(110,168,254,.4); }
.badge.status-dropped  { color: var(--muted); }
.badge.warn { color: var(--warn); border-color: rgba(255,177,92,.4); }

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--accent);
  color: #0e1116;
  font-size: 11px;
  font-weight: 650;
  flex: none;
}
.avatar-row { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; }

/* ---------- forms + buttons ---------- */

.btn {
  display: inline-flex;
  border-radius: 999px;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: 9px 18px;
  border: 1px solid rgba(255, 232, 210, 0.12);
  background: rgba(255, 238, 220, 0.05);
  color: var(--text);
  font-family: inherit;
  font-size: var(--t-sm);
  font-weight: 520;
  cursor: pointer;
  /* Listed explicitly, never `all`, and only compositor-friendly properties
     plus colour. */
  transition:
    border-color var(--fast) var(--ease),
    background-color var(--fast) var(--ease),
    color var(--fast) var(--ease),
    transform var(--fast) var(--ease);
}
.btn:hover { border-color: var(--accent-line); background: var(--panel); text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  /* Near-black on a light blue: 4.5:1 comfortably. */
  color: #0b1017;
  font-weight: 640;
}
.btn.primary:hover { filter: brightness(1.07); border-color: var(--accent); }
.btn.small { padding: 7px 14px; font-size: var(--t-xs); }

/* A real primary CTA. Everything on this page was `.btn.small`, which is fine
   for edit and delete and completely wrong for the two or three actions we
   actually want people to take. */
.btn.lg {
  padding: 13px 14px 13px 22px;
  font-size: 1rem;
  font-weight: 600;
  gap: var(--s-3);
  min-height: 52px;
}
.btn.lg.no-icon { padding-right: 22px; }

/* The trailing arrow sits in its own circle flush with the inner padding, and
   drifts on hover so the button has some kinetic tension rather than just
   changing colour. */
.btn .btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: rgba(15, 11, 8, 0.16);
  font-size: 0.95rem;
  line-height: 1;
  transition: transform var(--fast) var(--ease), background-color var(--fast) var(--ease);
}
.btn:not(.primary) .btn-icon { background: rgba(255, 238, 220, 0.09); }
.btn:hover .btn-icon { transform: translate(2px, -1px); }
.btn.primary:hover .btn-icon { background: rgba(15, 11, 8, 0.24); }

/* Ghost variant for the secondary action beside a primary. */
.btn.ghost {
  background: transparent;
  border-color: rgba(255, 238, 220, 0.18);
}
.btn.ghost:hover { background: rgba(255, 238, 220, 0.06); border-color: var(--accent-line); }

/* Card action row. The spacer pushes Edit/Delete away from the two actions
   people actually use, so a destructive button is never adjacent to a primary
   one. `.grow` is otherwise scoped to .card-head, hence the explicit rule. */
/* Hand-drawn car silhouettes (see CarsHelper). Nudged down so the wheels line up
   with the first line of the label rather than floating above it. */
/* "Since you last looked" line. Quiet by default -- it's a status line, not an
   alert -- and only picks up the accent when it has something to report. */
.catchup {
  margin: var(--s-5) 0 0;
  font-size: var(--t-sm);
  color: var(--muted);
}
.catchup strong { color: var(--accent); }
.catchup a { color: var(--text); }

.car-icon { flex: none; margin-top: 3px; }

.card-actions { margin-top: var(--s-4); }
.card-actions .grow { flex: 1; min-width: 0; }

/* Closing "what now" block. Sits apart from the option cards so it reads as the
   end of the page rather than another lodging. */
.next-step { margin-top: var(--s-6); border-color: var(--accent-line); }

.cta-row {
  display: flex;
  gap: var(--s-3);
  flex-wrap: wrap;
  align-items: center;
  margin-top: var(--s-5);
}
@media (max-width: 520px) {
  .card-actions .grow { display: none; }

  .page-head { align-items: stretch; }
  .page-head .btn.lg { width: 100%; justify-content: space-between; }

  /* Full width on a phone: a 52px pill that spans the column is a much better
     target than two half-width ones. */
  .cta-row { flex-direction: column; align-items: stretch; }
  .cta-row .btn { width: 100%; justify-content: space-between; }
}
/* Destructive actions used to be marked only on :hover, which does not exist on
   a touch screen -- on a phone "Delete" was indistinguishable from "Edit". Muted
   red at rest so it reads as destructive without shouting, full colour on hover. */
.btn.danger { color: #c9857a; }
.btn.danger:hover { border-color: var(--bad); color: var(--bad); }
.btn[disabled] { opacity: 0.45; cursor: not-allowed; transform: none; }

label {
  display: block;
  font-size: var(--t-sm);
  color: var(--text-dim);
  margin-bottom: var(--s-1);
  font-weight: 500;
}

input[type=text], input[type=password], input[type=email], input[type=url],
input[type=number], input[type=date], input[type=datetime-local], select, textarea {
  width: 100%;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
/* A native select inherits the OS palette on Windows dark mode unless both are
   set explicitly, which is how you get black text on a black dropdown. */
select {
  background-color: var(--bg);
  color: var(--text);
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 18px) calc(50% + 2px), calc(100% - 13px) calc(50% + 2px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 34px;
}
select option { background: var(--panel); color: var(--text); }

input::placeholder, textarea::placeholder { color: #6f7d8f; }

input:focus-visible, select:focus-visible, textarea:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
  outline: none;
}
textarea { resize: vertical; min-height: 72px; }
.field { margin-bottom: var(--s-3); }
.field-row { display: flex; gap: var(--s-3); flex-wrap: wrap; }
.field-row > .field { flex: 1; min-width: 8rem; }
.check { display: flex; align-items: center; gap: var(--s-2); }
.check input { width: auto; }
.check label { margin: 0; cursor: pointer; }

.thumb {
  width: 132px;
  height: 99px;
  object-fit: cover;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  transition: border-color var(--fast) var(--ease);
}
a:hover > .thumb { border-color: var(--accent-line); }

/* ---------- rooms table ---------- */

.rooms { width: 100%; border-collapse: collapse; font-size: 14px; margin-top: 10px; }
.rooms td { padding: 6px 0; border-bottom: 1px solid var(--line); vertical-align: top; }
.rooms .room-name { color: var(--muted); width: 38%; }
.rooms .room-beds { width: 40%; }
.rooms .room-sleeps {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  white-space: nowrap;
}
.rooms .rooms-total td { border-bottom: 0; border-top: 1px solid var(--line); padding-top: 8px; }

/* ---------- verdict + bullets ---------- */

.verdict {
  margin: 10px 0 4px;
  font-size: 15px;
  line-height: 1.5;
  border-left: 2px solid var(--accent);
  padding-left: 11px;
}
.open-q { margin-top: 8px; }

.bullets { margin: 0; padding-left: 20px; font-size: 14px; line-height: 1.55; }
.bullets li { margin-bottom: 3px; }
.bullets.good li::marker { color: var(--ok); content: "+ "; }
.bullets.bad li::marker { color: var(--bad); content: "− "; }
.bullets.good, .bullets.bad { list-style-position: outside; }

/* ---------- hero + day timeline ---------- */

.hero { padding: var(--s-8) 0 var(--s-6); }
.hero + h2 { margin-top: var(--s-6); }

/* Editorial split: type carries the left, the image plate the right. Collapses
   to a single column under 900px with the plate on top. */
@media (min-width: 900px) {
  .hero {
    display: grid;
    grid-template-columns: 1.05fr 0.95fr;
    gap: var(--s-7);
    align-items: center;
  }
  .hero-plate { order: 2; }
}

.hero-line {
  font-family: var(--font-display);
  font-size: var(--t-hero);
  font-weight: 700;
  line-height: 0.96;
  margin: 0 0 var(--s-4);
  letter-spacing: -0.045em;
  text-wrap: balance;
  max-width: 18ch;
}
.hero-line em {
  font-style: italic;
  font-weight: 640;
  color: var(--accent);
  /* Italic descenders clip at tight leading, so this reserves room. */
  line-height: 1.1;
  padding-bottom: 2px;
}
.hero-body {
  margin: 0 0 var(--s-3);
  font-size: 1.02rem;
  line-height: 1.65;
  color: var(--text-dim);
  max-width: 58ch;
  text-wrap: pretty;
}

/* The plate uses the same double-bezel language as the day cards. */
.hero-plate {
  padding: 6px;
  border-radius: var(--r-shell);
  border: 1px solid rgba(255, 232, 210, 0.09);
  background: linear-gradient(180deg, rgba(255, 238, 220, 0.05), rgba(255, 238, 220, 0.012));
  box-shadow: var(--shadow-lift);
  margin-bottom: var(--s-5);
}
.hero-plate-core {
  position: relative;
  border-radius: var(--r-core);
  overflow: hidden;
  /* Matches the bundled photograph (2160x1320) so it is not cropped. */
  aspect-ratio: 16 / 10;
  background:
    radial-gradient(130% 120% at 22% 8%, rgba(224, 103, 42, 0.42), transparent 58%),
    radial-gradient(100% 110% at 88% 92%, rgba(111, 159, 116, 0.24), transparent 60%),
    linear-gradient(158deg, #33200f, #120d09);
  box-shadow: inset 0 1px 0 rgba(255, 238, 220, 0.09);
  display: grid;
  place-items: end start;
}
.hero-plate-core picture { display: block; width: 100%; height: 100%; }
.hero-plate-core img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* A warm grade so any photo sits inside the October palette instead of
     fighting it. Whatever people paste in will be shot in different light; this
     pulls it toward ember and lifts contrast a little. */
  filter: saturate(0.82) contrast(1.08) brightness(0.94) sepia(0.14) hue-rotate(-8deg);
}
/* Ember scrim over the top, multiplied so highlights stay bright and the shadows
   pick up the warmth. The bottom fade keeps the plate anchored to the page. */
.hero-plate-core:has(img)::after,
.hero-plate-core:has(picture)::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(200deg, rgba(224, 103, 42, 0.26), rgba(111, 159, 116, 0.10) 58%, transparent),
    linear-gradient(180deg, transparent 62%, rgba(15, 11, 8, 0.55));
  mix-blend-mode: multiply;
}
/* Warmth on the day bands too, for the same reason. */
.day-band img {
  filter: saturate(0.8) contrast(1.06) brightness(0.9) sepia(0.16) hue-rotate(-8deg);
}
.hero-plate-empty {
  padding: var(--s-5);
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.1rem + 1.8vw, 2.3rem);
  font-weight: 640;
  letter-spacing: -0.035em;
  line-height: 1.05;
  color: rgba(242, 233, 220, 0.9);
  text-wrap: balance;
}
.hero-plate-empty span { display: block; color: var(--muted); font-size: var(--t-sm);
  font-family: var(--font-sans); font-weight: 400; letter-spacing: 0; margin-top: var(--s-2); }

.days { display: grid; gap: var(--s-5); }

/* Double-bezel: an outer shell holding an inner core, concentric radii, a hairline
   highlight along the top edge so it reads as a machined tray rather than a div. */
.day {
  background: linear-gradient(180deg, rgba(255, 238, 220, 0.045), rgba(255, 238, 220, 0.012));
  border: 1px solid rgba(255, 232, 210, 0.09);
  border-radius: var(--r-shell);
  padding: 6px;
  box-shadow: var(--shadow-soft);
  transition: transform var(--mid) var(--ease), box-shadow var(--mid) var(--ease);
}
.day:hover { transform: translateY(-2px); box-shadow: var(--shadow-lift); }

.day-core {
  background: var(--panel);
  border-radius: var(--r-core);
  padding: var(--s-5) var(--s-5) var(--s-4);
  box-shadow: inset 0 1px 0 rgba(255, 238, 220, 0.07);
  overflow: hidden;
}

/* Per-day imagery. When there is no photo the band is a warm gradient plus the
   grain that already sits over everything, which reads as intentional rather
   than as a missing asset. */
.day-band {
  position: relative;
  margin: calc(-1 * var(--s-5)) calc(-1 * var(--s-5)) var(--s-4);
  height: 128px;
  border-radius: var(--r-core) var(--r-core) 0 0;
  overflow: hidden;
  background:
    radial-gradient(120% 140% at 18% 0%, rgba(224, 103, 42, 0.34), transparent 60%),
    linear-gradient(160deg, #2a1a10, #14100c);
}
.day-band img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0.82;
}
.day-band::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 34%, var(--panel) 100%);
}
.day-band .band-label {
  position: absolute;
  left: var(--s-5);
  bottom: var(--s-3);
  z-index: 1;
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 1rem + 1vw, 1.6rem);
  font-weight: 640;
  letter-spacing: -0.03em;
  color: var(--text);
}
.day-band .band-label .dim { color: var(--muted); font-weight: 450; }

.day-head {
  font-family: var(--font-display);
  font-size: var(--t-h3);
  font-weight: 600;
  margin: 0 0 var(--s-3);
  display: flex;
  gap: var(--s-2);
  align-items: baseline;
  flex-wrap: wrap;
  letter-spacing: -0.02em;
}

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline > li {
  display: flex;
  gap: var(--s-3);
  padding: var(--s-2) 0;
  border-top: 1px solid var(--line-soft);
  align-items: baseline;
}
.timeline > li:first-child { border-top: 0; }
.timeline .when {
  flex: 0 0 7rem;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.timeline .what { flex: 1; min-width: 0; }
.timeline > li.nested { padding-left: 18px; border-top-style: dashed; }
.timeline > li.nested .when, .timeline > li.fixture .when { opacity: 0.72; }
.timeline > li.fixture .what { color: var(--muted); }
.timeline > li.clash .what { color: var(--bad); }

.big-number {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 1.3rem + 2.4vw, 2.9rem);
  font-weight: 660;
  margin: var(--s-3) 0 2px;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.big-number .muted { font-size: var(--t-body); font-weight: 400; letter-spacing: 0; }

/* ---------- pick-one options ---------- */

.options { list-style: none; margin: 8px 0 4px; padding: 0; display: grid; gap: 8px; }
.options > li {
  display: block;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-left: 2px solid var(--k-free);
  border-radius: 8px;
  padding: 10px 12px;
}
/* Title first, votes immediately after it -- not shoved to the far edge, which
   left a ragged gap that varied with the length of every title. */
.option-head { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.option-head strong { font-size: 15px; }
.options > li .sub { margin-top: 5px; max-width: 68ch; }

/* ---------- press to copy ---------- */

.copyable {
  display: flex;
  align-items: stretch;
  gap: 8px;
  flex-wrap: wrap;
}
.copyable code {
  flex: 1;
  min-width: 0;
  background: var(--panel-2);
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--line);
  word-break: break-all;
  font-size: 13px;
  line-height: 1.4;
  /* One tap selects the whole thing if the copy button ever fails. */
  user-select: all;
}
.copy-btn { flex: 0 0 auto; align-self: stretch; min-width: 92px; }
.copy-btn.copied {
  color: var(--ok);
  border-color: rgba(95, 214, 166, 0.5);
  background: rgba(95, 214, 166, 0.1);
}

@media (max-width: 520px) {
  /* No font-size here: it was pinning the hero to 21px and overriding the
     clamp(), which is why the display face never showed at its real scale
     on a phone. */
  .timeline > li { flex-direction: column; gap: 2px; }
  .timeline .when { flex: none; }
  .hero { padding-top: var(--s-6); }
  .hero-line { max-width: 100%; }
}

/* ---------- votes ---------- */

.votes { display: inline-flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.vote-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--muted);
  border-radius: 999px;
  padding: 4px 11px 4px 9px;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: transform .18s cubic-bezier(.32,.72,0,1),
              border-color .18s ease, background-color .18s ease, color .18s ease;
}
.vote-btn:hover { border-color: var(--accent); color: var(--text); }
/* Reads as a press rather than a page jump. */
.vote-btn:active { transform: scale(.94); }

/* Emoji render flat grey until picked, so an unreacted row does not look like a
   row of confetti competing with the lodging photos for attention. */
.reaction-emoji { font-size: 15px; line-height: 1; filter: saturate(.4) opacity(.8); transition: filter .18s ease; }
.vote-btn:hover .reaction-emoji { filter: none; }
.reaction-count { min-width: 7px; text-align: left; }
/* A zero count is noise on a fresh option; the emoji alone still reads. */
.vote-btn .reaction-count:empty { display: none; }

.vote-btn.picked { color: var(--text); }
.vote-btn.picked .reaction-emoji { filter: none; }
.vote-btn.reaction-fire.picked  { border-color: rgba(224,103,42,.55);  background: rgba(224,103,42,.14); }
.vote-btn.reaction-heart.picked { border-color: rgba(214,88,102,.55);  background: rgba(214,88,102,.14); }
.vote-btn.reaction-goat.picked  { border-color: rgba(199,161,74,.55);  background: rgba(199,161,74,.14); }
.vote-btn.reaction-wilt.picked  { border-color: rgba(126,132,140,.55); background: rgba(126,132,140,.14); }

@media (prefers-reduced-motion: reduce) {
  .vote-btn { transition: none; }
  .vote-btn:active { transform: none; }
}

/* ---------- comments ---------- */

.comments { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 12px; }
.comment { display: flex; gap: 9px; padding: 7px 0; }
.comment .body { flex: 1; min-width: 0; }
.comment .meta { font-size: 12px; color: var(--muted); }
.comment .text { white-space: pre-wrap; overflow-wrap: anywhere; }
.comment-form { display: flex; gap: 8px; margin-top: 8px; }
.comment-form textarea { min-height: 38px; }

/* ---------- seats ---------- */

.seats { display: flex; gap: 5px; flex-wrap: wrap; margin: 10px 0; }
.seat {
  width: 34px; height: 34px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 650;
}
.seat.empty { border-style: dashed; color: var(--muted); font-weight: 400; }
.seat.driver { box-shadow: inset 0 0 0 2px var(--accent); }

/* ---------- flash / auth ---------- */

.flash { padding: 10px 14px; border-radius: 8px; margin: 14px 0; font-size: 14px; border: 1px solid; }
.flash-ok  { border-color: rgba(95,214,166,.4);  background: rgba(95,214,166,.08); color: var(--ok); }
.flash-bad { border-color: rgba(255,143,163,.4); background: rgba(255,143,163,.08); color: var(--bad); }

.auth { max-width: 380px; margin: 8vh auto; padding: 0 20px; }
.auth h1 { font-size: 21px; margin: 0 0 4px; }
.auth .card { padding: 20px; }

.roster-pick { display: grid; gap: 8px; }
.roster-pick a, .roster-pick .taken {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel-2);
  color: var(--text);
}
.roster-pick a:hover { border-color: var(--accent); text-decoration: none; }
.roster-pick .taken { opacity: .5; }

.empty {
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  padding: 20px;
  text-align: center;
  color: var(--muted);
  font-size: 14px;
}

.ext { font-size: 13px; }
.inline-form { display: inline; }

/* The headcount picker is the main control on the Stay page. On a phone the
   inline label stole enough width to wrap the buttons onto three lines, so the
   label gets its own row and the buttons stay together. */
.tier-picker { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 10px 0 4px; }
.tier-label { margin: 0; }
@media (max-width: 520px) {
  .tier-label { flex: 0 0 100%; margin-bottom: 2px; }
}

/* Phones: 26-30px buttons are hard to hit. Apple's guidance is 44px, so grow
   every tap target on touch devices without changing the desktop layout. */
@media (hover: none) and (pointer: coarse) {
  .btn, .vote-btn { min-height: 44px; display: inline-flex; align-items: center; }
  .btn.small, .vote-btn { padding: 10px 14px; font-size: 14px; }
  .tab { padding: 14px 15px; }
  input[type=text], input[type=password], input[type=email], input[type=url],
  input[type=number], input[type=date], input[type=datetime-local], select, textarea {
    min-height: 44px;
    font-size: 16px; /* under 16px, iOS Safari zooms the page on focus */
  }
  .badge { font-size: 13px; padding: 3px 10px; }
  .comment-form textarea { min-height: 44px; }
}

@media (max-width: 620px) {
  .topbar-inner { padding: 12px 16px; }
  .wrap { padding: 0 16px 48px; }
  .card-head { flex-direction: column; }
}


/* ---------- motion ----------
   MOTION_INTENSITY 3: an entry reveal that establishes reading order on a page
   which is mostly a list of days, plus feedback on interaction. Nothing loops,
   nothing parallaxes, nothing hijacks scroll. */

@media (prefers-reduced-motion: no-preference) {
  /* A CSS keyframe with fill-mode `both`, NOT a JS-driven reveal.
     The first version put `opacity: 0` on the cards in CSS and made an
     IntersectionObserver responsible for adding the class that revealed them.
     The observer did not fire and all five days rendered invisible on the live
     site. Never make content visibility depend on JS running: an animation that
     merely plays cannot hide anything if it never starts. */
  .day, .options > li {
    animation: rise var(--slow) var(--ease) both;
    animation-delay: calc(var(--i, 0) * 70ms);
  }
  @keyframes rise {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: none; }
  }
}

/* Collapses everything above to static. Mandatory, not a nicety. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}
