@layer components {
  /* Prep — three stacked bands inside the beige board:
     1. Identity (gathering, dates, hosts, travel placeholders)
     2. Todos    (accordion on lined-paper bg)
     3. Folders  (simple labeled tiles)
     Cohort sits below folders, gated on @show_cohort. */

  /* ── 1. Identity band ─────────────────────────────── */
  .prep-identity { margin-bottom: var(--space-8); }

  /* Title is the headline; the meta row (your stay · dates · countdown)
     sits beneath it as a smaller, calmer sub-line. */
  .prep-identity-title {
    font-size: 36px;
    line-height: 1.05;
    margin: 0 0 12px;
    color: var(--ink);
  }

  /* Statement headline: "You're attending [Name] in 3 weeks." The name is the
     visual anchor; the lead and countdown frame it in a calmer weight/colour. */
  .prep-attending { margin: 0 0 12px; }
  .prep-attending-lead {
    display: block;
    font-family: var(--sans);
    font-size: 15px; font-weight: var(--weight-medium);
    color: var(--ink-soft);
    margin-bottom: 3px;
  }
  .prep-attending-name {
    display: block;
    font-size: 36px; line-height: 1.05; color: var(--ink);
  }
  .prep-attending-when {
    display: block;
    font-family: var(--sans);
    font-size: 19px; font-weight: var(--weight-medium);
    color: var(--ink-soft);
    margin-top: 5px;
  }
  .prep-identity-meta {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin-bottom: var(--space-5);
  }
  .prep-identity-divider {
    width: 1px;
    height: 14px;
    background: rgba(0,0,0,0.18);
  }

  .prep-dates {
    font-family: var(--display);
    color: var(--ink);
    line-height: 1.1;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
  }
  .prep-dates-range {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-soft);
    font-weight: var(--weight-semibold);
    white-space: nowrap;
  }
  /* Arrival deadline — the "be here by …" the host sets (transportation phase 1). */
  .prep-arrive-by {
    font-family: var(--sans);
    font-size: 13px;
    color: var(--ink-soft);
    margin-top: 6px;
  }
  .prep-arrive-by strong { color: var(--ink); font-weight: var(--weight-semibold); }
  .prep-dates-countdown {
    display: inline-block;
    padding: 3px 9px;
    background: rgba(0, 0, 0, 0.06);
    color: var(--ink-soft);
    font-family: var(--sans);
    font-size: 10px;
    letter-spacing: 0.06em;
    font-weight: var(--weight-semibold);
    border-radius: 999px;
    text-transform: none;
    white-space: nowrap;
  }

  /* Hosts row — inline by default (home cards, the folder, and the stay page
     when the guest list is hidden): avatars and "Hosted by" on one line. */
  .prep-hosts {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: var(--space-6);
  }
  /* Roll variant — only on the stay page when the full guest list is shared:
     host cluster + separator + guest preview stacked above "Hosted by". */
  .prep-hosts.prep-hosts--roll {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
  .prep-roll { display: flex; align-items: center; }
  .prep-roll-cluster { display: flex; }
  .prep-roll-sep {
    width: 1px;
    height: 22px;
    background: rgba(0, 0, 0, 0.15);
    margin: 0 14px;
    flex-shrink: 0;
  }
  .prep-hosts-avatars { display: flex; }
  .prep-host {
    width: 36px; height: 36px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--paper-edge);
    border: 2px solid var(--paper);
    margin-left: -8px;
    display: flex; align-items: center; justify-content: center;
    font-size: 10px; letter-spacing: 0.1em;
    color: var(--ink-soft);
    box-shadow: 0 1px 2px rgba(0,0,0,0.08);
  }
  /* First avatar in each cluster sits flush; the rest overlap. */
  .prep-host:first-child { margin-left: 0; }
  /* Hosts get a special dark ring to set them apart from guests. */
  .prep-host--lead { border-color: var(--ink); }
  /* The "+N others" avatar — a quiet filled count. */
  .prep-host--more {
    background: var(--paper-warm-2);
    color: var(--ink-soft);
    font-weight: var(--weight-semibold);
  }
  .prep-hosts-label {
    font-size: 13px;
    color: var(--ink-soft);
    font-family: var(--display);
  }

  .prep-travel {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
  }
  /* Each travel card is its own standalone object with its own paper,
     shadow, and color stripe — not a panel within a band. */
  .prep-travel-card {
    position: relative;
    display: block;
    padding: 24px 26px 26px;
    border-radius: 0;
    text-decoration: none;
    color: inherit;
    background: var(--paper);
    border: 1px solid var(--hover-edge);
    box-shadow: none;
    transition: border-color .12s ease, box-shadow .12s ease;
  }
  .prep-travel-card:hover {
    border-color: var(--ink-faint);
    box-shadow: var(--shadow-card);
  }
  .prep-travel-card.arrive { background: var(--arrive-paper); }
  .prep-travel-card.depart { background: var(--depart-paper); }

  /* Coherence pass: the printed-paper inner frame retires. */
  .prep-travel-card::before {
    content: none;
    position: absolute;
    top: 8px; right: 8px; bottom: 8px; left: 8px;
    border: 0;
    border-radius: 0;
    pointer-events: none;
    color: rgba(0,0,0,0.10);
  }
  .prep-travel-card.arrive::before,
  .prep-travel-card.depart::before,
  .prep-lodging-card::before { color: rgba(0, 0, 0, 0.14); }

  .prep-travel-card-head {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: 6px 10px;
    margin-bottom: 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
  }
  .prep-travel-tag {
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
  }
  .prep-travel-card.arrive .prep-travel-tag,
  .prep-travel-card.depart .prep-travel-tag { color: var(--ink-soft); }
  .prep-travel-edit {
    font-size: 10px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin-left: auto;
  }

  /* Setup-step badge — number on the card while incomplete, filled
     check when done. Lives inside .prep-travel-card-head. */
  .prep-step-badge {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1.5px solid currentColor;
    color: var(--ink-soft);
    background: transparent;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: var(--weight-semibold);
    line-height: 1;
    flex-shrink: 0;
  }
  .prep-travel-card.arrive .prep-step-badge,
  .prep-travel-card.depart .prep-step-badge,
  .prep-stay-info-card .prep-step-badge { color: var(--ink-soft); }
  .prep-step-badge--done {
    background: currentColor;
    border-color: currentColor;
  }
  .prep-step-badge--done .prep-step-check {
    width: 12px;
    height: 12px;
    color: var(--paper);
  }

  /* Intro line above the three setup cards. */
  .prep-setup-intro {
    margin: 18px 0 14px;
    font-size: 13.5px;
    color: var(--ink-soft);
    line-height: 1.5;
  }

  /* Inline CTA pill at the bottom of an incomplete setup card. The card
     itself is the navigation target — this is a visual nudge, not a
     separate link. Tone matches the card it sits in. */
  .prep-card-cta {
    display: inline-flex;
    align-items: center;
    margin-top: 14px;
    padding: 9px 16px;
    border-radius: 999px;
    font-family: var(--sans);
    font-size: 12px;
    font-weight: var(--weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--paper);
    background: var(--ink);
    text-decoration: none;
    transition: transform .12s ease, box-shadow .12s ease;
  }
  .prep-travel-card:hover .prep-card-cta {
    box-shadow: 0 3px 8px rgba(0,0,0,0.15);
    transform: translateY(-1px);
  }
  .prep-card-cta--arrive { background: var(--arrive); }
  .prep-card-cta--depart { background: var(--depart); }
  .prep-card-cta--about  { background: var(--ink); }

  /* Inline variant — sits at the right edge of the preview row on
     desktop, drops below on narrow screens. Used by "About your stay". */
  .prep-card-cta--inline {
    margin-top: 0;
    margin-left: auto;
    align-self: center;
    flex-shrink: 0;
  }
  @media (max-width: 640px) {
    /* On phones, the preview row becomes a 2-row grid: [avatar | body]
       on top, the CTA on its own row underneath — sized to its label,
       not stretched. */
    .prep-stay-info-preview {
      display: grid;
      grid-template-columns: auto 1fr;
      grid-template-areas:
        "avatar body"
        "cta    cta";
      column-gap: 14px;
      row-gap: 12px;
    }
    .prep-stay-info-avatar       { grid-area: avatar; }
    .prep-stay-info-preview-body { grid-area: body; min-width: 0; }
    .prep-card-cta--inline {
      grid-area: cta;
      justify-self: start;
      margin-left: 0;
      margin-top: 0;
    }
    /* Same wrap behavior on the combined travel card: legs on top, CTA
       on its own row below. */
    .prep-travel-preview {
      display: grid;
      grid-template-columns: 1fr;
      grid-template-areas:
        "legs"
        "cta";
      gap: 12px;
    }
    .prep-travel-preview .prep-travel-legs { grid-area: legs; }
    .prep-travel-preview .prep-card-cta--inline { grid-area: cta; }
  }

  .prep-travel-summary {
    font-family: var(--display);
    font-style: normal;
    font-size: 19px;
    line-height: 1.25;
    color: var(--ink);
  }

  /* Combined travel card — one card showing both arrival and departure as
     two labeled rows. Replaces the side-by-side arrive/depart pair. */
  .prep-travel-card--combined { display: block; margin-top: var(--space-7); }
  /* Preview row inside the card — mirrors .prep-stay-info-preview so the
     "Add travel details" CTA inlines on the right and wraps below the
     legs on narrow widths (same physics as the About-your-stay card). */
  .prep-travel-preview {
    display: flex;
    gap: 14px;
    align-items: flex-start;
    flex-wrap: wrap;
    margin-top: 4px;
  }
  .prep-travel-preview .prep-travel-legs { flex: 1; min-width: 0; }
  .prep-travel-legs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px 32px;
  }
  .prep-travel-leg { min-width: 0; }
  .prep-travel-leg-label {
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
    color: var(--ink-soft);
    margin-bottom: 6px;
  }
  .prep-travel-leg-body { min-width: 0; }
  .prep-travel-meta {
    font-size: 11px;
    color: var(--ink-soft);
    margin-top: 4px;
    letter-spacing: 0.04em;
  }
  /* Skeleton state — when no actual value is set, the placeholder text
     reads as a much-lighter ghost so it doesn't compete with real data
     elsewhere on the card. */
  .prep-travel-summary.is-skeleton,
  .prep-travel-meta.is-skeleton {
    color: var(--ink-faint);
  }
  .prep-travel-empty {
    font-family: var(--display);
    font-style: normal;
    font-size: 16px;
    color: var(--ink-faint);
  }

  /* Lodging card — same treatment as arrive/depart, neutral paper. */
  .prep-lodging-card,
  .prep-stay-info-card {
    margin-top: 18px;
    background: var(--paper-warm);
  }
  .prep-travel-tag--lodging { color: var(--ink-soft); }
  /* "About your stay" reads in the same neutral as Arrival / Departure. */
  .prep-stay-info-card .prep-travel-tag { color: var(--ink-soft); }

  /* ── 2. Todos band ────────────────────────────────── */
  /* Cornell-page band — white, hairline grey rules, one thin magenta
     margin rule down the left. Super subtle. */
  /* Clean & solid — no cornell paper. White card, hairline-divided rows. */
  .prep-todos {
    margin: var(--space-7) 0;
    padding: 2px 16px;
    background: var(--paper);
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: var(--radius-xs);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  }
  .prep-todos .prep-todo + .prep-todo { border-top: 1px solid rgba(0, 0, 0, 0.07); }
  .prep-todos-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: var(--space-4);
    padding-left: 4px;
  }
  .prep-todos-title {
    font-family: var(--display);
    font-style: normal;
    font-size: 22px;
    color: var(--ink);
  }
  .prep-todos-count {
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-faint);
  }

  .prep-todo { /* no dividers — the lined paper provides rhythm */ }
  .prep-todo-link {
    display: block;
    text-decoration: none;
    color: inherit;
  }
  .prep-todo-link:hover .prep-todo-title { color: var(--ink); }
  .prep-todo-link:hover .prep-todo-chevron { color: var(--ink); transform: translateX(2px); }
  .prep-todo-chevron { transition: transform .12s ease, color .12s ease; }

  .prep-todo-row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 8px 4px;
    flex-wrap: wrap;
    cursor: pointer;
    user-select: none;
  }
  .prep-todo-check {
    width: 18px; height: 18px;
    border: 1.5px solid var(--ink-faint);
    border-radius: 0;
    flex-shrink: 0;
    background: var(--paper);
    display: flex; align-items: center; justify-content: center;
    font-size: 12px; line-height: 1; color: var(--ink);
  }
  .prep-todo.done .prep-todo-check::before { content: "✓"; }
  .prep-todo.done .prep-todo-title {
    text-decoration: line-through;
    color: var(--ink-faint);
  }

  .prep-todo-title {
    flex: 1;
    font-size: 14px;
    color: var(--ink);
    font-weight: var(--weight-medium);
  }
  .prep-todo-due {
    font-family: var(--display);
    font-style: normal;
    font-size: 15px;
    color: var(--ink);
    flex-shrink: 0;
    font-weight: var(--weight-semibold);
  }
  .prep-todo.due .prep-todo-due { color: var(--due); font-weight: var(--weight-bold); }
  .prep-todo.done .prep-todo-due { color: var(--ink-faint); text-decoration: line-through; }
  .prep-todo-chevron {
    width: 14px;
    color: var(--ink-faint);
    transition: transform .15s ease;
    flex-shrink: 0;
  }
  .prep-todo.expanded .prep-todo-chevron { transform: rotate(90deg); }

  .prep-todo-body {
    display: none;
    padding: 4px 4px 16px 30px;
    font-size: 13px;
    line-height: 1.55;
    color: var(--ink-soft);
  }
  .prep-todo.expanded .prep-todo-body { display: block; }
  .prep-todo-body p { margin: 0 0 10px; }

  /* ── 2b. Checklist (clean, typed) — prep-page entry to the to-dos.
     Fresh .chk-* classes so the home snapshot's .prep-todo stays as-is. */
  .chk { margin-top: var(--space-8); }
  .chk-head {
    display: flex; align-items: baseline; justify-content: space-between;
    margin-bottom: 10px; padding-left: 2px;
  }
  .chk-title {
    font-family: var(--display); font-style: normal;
    font-size: 22px; color: var(--ink);
  }
  .chk-count {
    font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--ink-faint);
  }
  .chk-progress {
    height: 6px; border-radius: 999px;
    background: rgba(0, 0, 0, 0.07);
    overflow: hidden; margin-bottom: 18px;
  }
  .chk-progress-fill {
    height: 100%; border-radius: 999px;
    background: var(--paid);
    transition: width 0.4s cubic-bezier(.4,.1,.3,1);
  }

  .chk-list { list-style: none; margin: 0; padding: 0; }
  .chk-item {
    display: flex; align-items: center; gap: 12px;
    padding: 13px 14px;
    text-decoration: none; color: inherit;
    background: var(--paper);
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: var(--radius-xs);
    transition: border-color .12s ease, box-shadow .12s ease, transform .12s ease;
  }
  .chk-list li + li { margin-top: 8px; }
  .chk-item:hover {
    border-color: var(--hover-edge);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  }
  .chk-item:hover .chk-item-chevron { transform: translateX(2px); color: var(--ink); }
  .chk-item-mark {
    flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%;
    border: 1.5px solid var(--ink-faint); background: var(--paper);
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 12px; line-height: 1; color: #fff;
  }
  .chk-item-mark--done { background: var(--paid); border-color: var(--paid); }
  .chk-item-body { flex: 1; min-width: 0; }
  .chk-item-title {
    display: block; font-size: 15px; font-weight: var(--weight-medium); color: var(--ink);
  }
  .chk-item-meta {
    display: flex; align-items: center; gap: 8px; flex-shrink: 0; margin-left: 12px;
  }
  .chk-item-chevron {
    flex-shrink: 0; font-size: 18px; color: var(--ink-faint);
    transition: transform .12s ease, color .12s ease;
  }

  .chk-tag {
    font-family: var(--sans); font-size: 10px; font-weight: var(--weight-semibold);
    letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--ink-soft); background: rgba(0, 0, 0, 0.05);
    padding: 3px 8px; border-radius: 999px;
  }
  /* PAY tag stays neutral like the other kind tags — the $600 amount is the
     money cue, so a green tag just competed with the amount and the due date. */
  .chk-amount {
    font-size: 13px; font-weight: var(--weight-semibold); color: var(--ink);
  }
  .chk-due {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: 12px; font-weight: var(--weight-semibold); color: var(--due);
  }
  /* Past due, not done — warm ochre information, never a scold. */
  .chk-due--slipping { color: var(--slipping); }

  /* Done group — quieter, collapsed visual weight. */
  .chk-done-head {
    font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--ink-faint); margin: 22px 0 10px; padding-left: 2px;
  }
  .chk-item--done { background: transparent; border-color: rgba(0, 0, 0, 0.06); }
  .chk-item--done .chk-item-title {
    color: var(--ink-faint); font-weight: var(--weight-normal);
  }

  /* ── 3. Resources band — flat files with optional host note. ── */
  /* Footer zone — note for hosts + who else is coming. Full-bleed (breaks out
     of the board's 80px side padding and its bottom padding) and slightly
     greyed, so it reads as a quiet base to the sheet. */
  .prep-footer {
    margin: var(--space-8) -80px -72px;
    padding: var(--space-8) 80px 72px;
    background: var(--paper-warm);
  }
  .prep-footer > .prep-cohort { margin-top: var(--space-8); }

  /* A note for your hosts — inline section (replaces the old "About your stay"
     modal). Reuses .stay-info-section-title/help + .nom-textarea. */
  .prep-host-note { margin-top: 0; }
  /* Read-mode note: a calm left-accented block, not an input. Click to edit. */
  .prep-host-note-display {
    display: block; width: 100%; text-align: left;
    font: inherit; line-height: 1.55; color: var(--ink);
    white-space: pre-wrap; word-break: break-word; cursor: pointer;
    margin-top: 8px; padding: 12px 14px;
    background: var(--paper-warm-2);
    border: none; border-left: 2px solid var(--paper-edge);
    transition: border-color .12s ease, background .12s ease;
  }
  .prep-host-note-display:hover { border-left-color: var(--ink-faint); }
  .prep-host-note-display.is-empty { color: var(--ink-faint); font-style: italic; }
  /* Edit form is hidden until the display is tapped (stay-info toggles .editing). */
  .prep-host-note-edit { display: none; margin-top: 8px; }
  .prep-host-note-item.editing .prep-host-note-display { display: none; }
  .prep-host-note-item.editing .prep-host-note-edit { display: block; }
  .prep-host-note-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 18px;
    margin-top: 14px;
  }

  @media (max-width: 768px) {
    /* Match the mobile board padding (0 14px 48px) for the full-bleed. */
    .prep-footer { margin: var(--space-7) -14px -48px; padding: var(--space-7) 14px 48px; }
  }

  .prep-files { margin-top: var(--space-8); }
  .prep-files-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: var(--space-4);
  }
  .prep-files-title {
    font-family: var(--display);
    font-style: normal;
    font-size: 22px;
    color: var(--ink);
  }
  .prep-files-list { list-style: none; padding: 0; margin: 0; }
  .prep-file {
    border-top: 1px solid rgba(0,0,0,0.06);
  }
  .prep-file:first-child { border-top: none; }
  .prep-file-link {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 14px 4px;
    text-decoration: none;
    color: inherit;
    transition: background 0.12s ease;
  }
  .prep-file-link:hover { background: var(--hover-wash); }
  .prep-file-icon {
    width: 26px;
    text-align: center;
    font-size: 18px;
    line-height: 1.2;
    color: var(--ink-soft);
    flex-shrink: 0;
    padding-top: 2px;
  }
  .prep-file-icon .resource-icon {
    width: 20px;
    height: 20px;
    margin: 0 auto;
    display: block;
  }
  .prep-file-title {
    font-size: 15px;
    font-weight: var(--weight-semibold);
    color: var(--ink);
  }
  .prep-file-out {
    margin-left: 6px;
    font-size: 11px;
    color: var(--ink-faint);
    font-weight: var(--weight-medium);
  }
  .prep-file-note {
    font-size: 12.5px;
    color: var(--ink-soft);
    font-style: normal;
    line-height: 1.5;
    margin-top: 4px;
    max-width: 60ch;
  }

  /* ── Cohort (below folders, gated by @show_cohort) ── */
  .prep-cohort { margin-top: var(--space-8); padding-top: var(--space-5); border-top: 1px dashed var(--hover-edge); }
  .prep-cohort-title {
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin-bottom: 10px;
  }
  .cohort {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
  }
  .cohort-photo {
    width: 38px; height: 38px;
    border-radius: 50%;
    font-size: 10px;
  }
  .cohort-photo.more {
    background: transparent;
    border: 1px dashed rgba(0,0,0,0.3);
    color: var(--ink);
  }
  .cohort-note {
    font-size: 11px;
    color: var(--ink-faint);
    margin-top: 10px;
    font-style: normal;
  }

  /* ── Logistics modal — whole-card-tinted layout ── */
  .logistics-direction-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    margin-bottom: 32px;
  }
  .logistics-direction-title { color: var(--ink);
    font-family: var(--display);
    font-style: normal;
    font-size: 52px;
    font-weight: 500;
    line-height: 0.95;
    margin: 0;
    letter-spacing: -0.01em;
  }
  .logistics-direction-title--arrive { color: var(--arrive); }
  .logistics-direction-title--depart { color: var(--depart); }
  .logistics-direction-title--sm { font-size: 32px; line-height: 1.1; }
  .logistics-direction-date {
    text-align: right;
    font-family: var(--display);
  }
  .logistics-direction-date-num {
    font-size: 32px;
    font-weight: 500;
    line-height: 1;
    margin: 4px 0;
  }
  .logistics-direction-date--arrive .logistics-direction-date-num { color: var(--arrive); }
  .logistics-direction-date--depart .logistics-direction-date-num { color: var(--depart); }

  .logistics-fields {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px 22px;
    margin-bottom: 22px;
  }
  .logistics-field { min-width: 0; }

  .logistics-upload { margin: 0 0 26px; cursor: pointer; }
  .logistics-upload--depart {
    border-color: var(--hover-edge);
    background: var(--paper-warm);
    color: var(--depart);
  }
  .logistics-upload--arrive {
    background: var(--paper-warm);
  }
  .logistics-form { margin-bottom: 24px; }

  /* ── Combined logistics modal ── */
  .logistics-combined-head {
    margin-bottom: 24px;
  }
  .logistics-combined-title {
    font-family: var(--display);
    font-style: normal;
    font-size: 52px;
    font-weight: 500;
    line-height: 0.95;
    letter-spacing: -0.01em;
    color: var(--ink);
    margin: 0;
  }

  /* Date range — two date inputs with an arrow between, visually one unit.
     Shared with the request-a-stay form (new_dates.html.erb). */
  .date-range {
    display: flex;
    align-items: end;
    gap: 10px;
  }
  .date-range__field { flex: 1; min-width: 0; }
  .date-range__arrow {
    padding-bottom: 10px;
    color: var(--ink-soft);
    font-size: 18px;
    line-height: 1;
    user-select: none;
    flex-shrink: 0;
  }

  /* ── Custom date range picker ──────────────────────────────────────── */
  .date-range-picker { position: relative; }

  /* Trigger — visually mirrors the underline-input aesthetic so the
     range field reads as one input even when nothing's picked yet. */
  .date-range-trigger {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    background: transparent;
    border: none;
    border-bottom: 1px solid var(--hover-edge);
    border-radius: 0;
    padding: 10px 2px;
    font-family: var(--sans);
    font-size: 16px;
    color: var(--ink);
    text-align: left;
    cursor: pointer;
    transition: border-color 0.15s ease;
  }
  .date-range-trigger:hover,
  .date-range-trigger:focus-visible {
    outline: none;
    border-bottom-color: var(--ink);
  }
  .date-range-trigger__half {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .date-range-trigger__half.is-placeholder { color: var(--ink-faint); }
  .date-range-trigger__arrow {
    color: var(--ink-soft);
    font-size: 16px;
    line-height: 1;
    user-select: none;
    flex-shrink: 0;
  }

  /* Popover — anchored under the trigger, floats above the form. */
  .date-range-popover {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 20;
    width: 320px;
    max-width: calc(100vw - 32px);
    background: var(--paper, #fff);
    border: 1px solid var(--hover-edge);
    border-radius: 6px;
    box-shadow:
      0 4px 12px rgba(0,0,0,0.10),
      0 10px 28px rgba(0,0,0,0.08);
    padding: 14px;
  }
  .date-range-popover[hidden] { display: none; }
  .date-range-popover__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 10px;
    gap: 8px;
  }
  .date-range-popover__title {
    font-family: var(--display);
    font-style: normal;
    font-size: 15px;
    font-weight: var(--weight-semibold);
    color: var(--ink);
    text-align: center;
    flex: 1;
  }
  .date-range-popover__nav {
    appearance: none;
    background: transparent;
    border: none;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    color: var(--ink-soft);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.12s ease, color 0.12s ease;
  }
  .date-range-popover__nav:hover {
    background: rgba(0,0,0,0.06);
    color: var(--ink);
  }
  .date-range-popover__weekdays {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    font-size: 10px;
    font-weight: var(--weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-faint);
    text-align: center;
    margin-bottom: 4px;
  }
  .date-range-popover__weekdays span { padding: 4px 0; }
  .date-range-popover__grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
  }
  .date-range-day {
    appearance: none;
    background: transparent;
    border: none;
    aspect-ratio: 1 / 1;
    border-radius: 0;
    font-family: var(--sans);
    font-size: 13px;
    color: var(--ink);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.08s ease, color 0.08s ease;
    padding: 0;
  }
  .date-range-day:hover:not(:disabled):not(.date-range-day--empty) {
    background: rgba(0,0,0,0.06);
  }
  .date-range-day--empty { cursor: default; }
  .date-range-day--disabled,
  .date-range-day:disabled {
    color: var(--ink-faint);
    cursor: not-allowed;
    opacity: 0.4;
  }
  .date-range-day--in-range {
    background: var(--paper-warm-2);
    border-radius: 50%;
    color: var(--ink);
  }
  .date-range-day--start,
  .date-range-day--end {
    background: var(--ink);
    color: var(--paper);
    border-radius: 50%;
    font-weight: var(--weight-semibold);
  }
  .date-range-day--start:hover,
  .date-range-day--end:hover { background: var(--ink); color: var(--paper); }
  .date-range-day--hover-end {
    background: var(--paper-warm-2);
    color: var(--ink);
  }
  /* Dotted outline marks the underlying gathering's window so the user
     can see which days fall inside the event when picking their stay. */
  .date-range-day--gathering {
    outline: 1px dotted var(--board);
    outline-offset: -3px;
  }
  /* Legend explaining the dotted outline. Renders only when a
     highlight_label is passed to the partial. */
  .date-range-popover__legend {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px solid rgba(0,0,0,0.08);
    font-size: 11px;
    color: var(--ink-soft);
    line-height: 1.3;
  }
  .date-range-popover__legend-swatch {
    display: inline-block;
    width: 14px;
    height: 14px;
    outline: 1px dotted var(--board);
    outline-offset: -2px;
    flex-shrink: 0;
  }

  /* ── Custom time mask — hour/minute fields with --:-- template ──── */
  .time-mask {
    display: flex;
    align-items: center;
    gap: 10px;
  }
  .time-mask-row {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 2px;
    border-bottom: 1px solid var(--hover-edge);
    padding: 10px 2px;
    transition: border-color 0.15s ease;
  }
  .time-mask-row:focus-within {
    border-bottom-color: var(--ink);
  }
  .time-mask-unit {
    border: none;
    background: transparent;
    padding: 0;
    font-family: var(--sans);
    font-size: 16px;
    color: var(--ink);
    width: 24px;
    text-align: left;
  }
  .time-mask-unit::placeholder { color: var(--ink-faint); }
  .time-mask-unit:focus { outline: none; }
  .time-mask-sep {
    color: var(--ink);
    user-select: none;
    font-size: 16px;
  }
  .time-picker-ampm {
    flex-shrink: 0;
    appearance: none;
    background: transparent;
    border: none;
    border-bottom: 1px solid var(--hover-edge);
    border-radius: 0;
    padding: 10px 16px 10px 4px;
    font-family: var(--sans);
    font-size: 14px;
    color: var(--ink);
    cursor: pointer;
    background-image:
      linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%),
      linear-gradient(-45deg, transparent 50%, var(--ink-soft) 50%);
    background-position:
      calc(100% - 8px) center,
      calc(100% - 4px) center;
    background-size: 5px 5px;
    background-repeat: no-repeat;
    transition: border-color 0.15s ease;
  }
  .time-picker-ampm:focus {
    outline: none;
    border-bottom-color: var(--ink);
  }

  /* Itinerary-table layout — each row asks one question; arrival and
     departure values sit side-by-side under a shared label.
     ─── Row structure ───
       .logistics-row        — one question, label + content
       .logistics-row--trip  — trip-level row (label + single full-width field)
       .logistics-row--headers — Arrival / Departure column captions
       .logistics-row-label  — left-column label
       .logistics-row-cells  — the paired cells (arrival | departure)
       .logistics-row-cell   — one cell (arrival or departure) */
  .logistics-row {
    display: grid;
    grid-template-columns: minmax(80px, 110px) 1fr;
    gap: 16px 20px;
    align-items: start;
    margin-bottom: 18px;
  }
  .logistics-row-label {
    margin-bottom: 0;
    padding-top: 8px;
    text-align: left;
    line-height: 1.25;
    /* Allow long labels to wrap rather than forcing the column wider. */
    word-wrap: break-word;
  }
  .logistics-row-cells {
    display: flex;
    flex-wrap: wrap;
    gap: 18px 24px;
    min-width: 0;
  }
  .logistics-row-cell {
    flex: 1 1 calc(50% - 12px);
    min-width: 0;
  }
  /* When a leg is in driving mode, the bucket toggle is too wide for a
     half-column. Push the cell to a full row of its own and reveal a
     small leg caption so the user can still tell arrival from departure. */
  [data-arrive-mode="driving"] .logistics-row-cell[data-leg="arrive"],
  [data-depart-mode="driving"] .logistics-row-cell[data-leg="depart"] {
    flex-basis: 100%;
  }
  .logistics-cell-leg-label {
    display: none;
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
    color: var(--ink-soft);
    margin-bottom: 6px;
  }
  [data-arrive-mode="driving"] .logistics-row-cell[data-leg="arrive"] .logistics-cell-leg-label,
  [data-depart-mode="driving"] .logistics-row-cell[data-leg="depart"] .logistics-cell-leg-label {
    display: block;
  }
  .logistics-row-trip-field { min-width: 0; }

  /* Small "Arrival" / "Departure" captions above the per-leg toggles when
     the user clicks "different both ways?" to split the mode toggle. */
  .logistics-leg-heading {
    font-family: var(--display);
    font-style: normal;
    font-size: 11px;
    font-weight: var(--weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--ink-soft);
    margin-bottom: 6px;
  }

  /* Traveling-by row — flex container holding the toggle(s) and the
     "different / same both ways?" link. */
  .logistics-mode-controls {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
  }
  .logistics-mode-toggles {
    display: flex;
    gap: 18px;
    align-items: flex-end;
  }
  /* In split mode, stack the two leg toggles vertically (one per row)
     so the user can compare arrival and departure top-to-bottom. The
     "Same both ways" link goes underneath the toggles, not beside. */
  [data-mode-split="true"] .logistics-mode-toggles {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
  [data-mode-split="true"] .logistics-mode-controls {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }
  .logistics-mode-leg { display: flex; flex-direction: column; min-width: 0; }
  .logistics-mode-split-link {
    font-size: 12px;
    color: var(--ink-soft);
    text-decoration: underline;
    text-decoration-style: dotted;
    text-underline-offset: 3px;
    cursor: pointer;
    white-space: nowrap;
  }
  .logistics-mode-split-link:hover { color: var(--ink); }

  /* Split-mode toggling — which extra elements show in unified vs split. */
  [data-mode-split="false"] [data-split-only]   { display: none; }
  [data-mode-split="true"]  [data-unified-only] { display: none; }
  /* In unified mode, force depart_mode to mirror arrive_mode visually:
     the departure cell in mode-conditional rows behaves as if its mode
     matches arrival's mode — the controller writes data-depart-mode on
     change, but we also override here so an initial render with equal
     modes still hides driving/flying cells consistently. */

  /* Cell-level visibility — each leg has its own mode, so each cell
     can show flying-only or driving-only content independently. */
  [data-arrive-mode="flying"]  [data-leg="arrive"] [data-leg-mode-only="driving"],
  [data-arrive-mode="driving"] [data-leg="arrive"] [data-leg-mode-only="flying"],
  [data-depart-mode="flying"]  [data-leg="depart"] [data-leg-mode-only="driving"],
  [data-depart-mode="driving"] [data-leg="depart"] [data-leg-mode-only="flying"] {
    display: none;
  }

  /* Row-level visibility — trip-level rows that only apply when at least
     one leg is flying (Airport, Need a ride?) hide when both are driving. */
  [data-arrive-mode="driving"][data-depart-mode="driving"] [data-show-when-any-flying] {
    display: none;
  }

  /* ── Per-leg blocks ── Each leg's fields live inside a tinted
     container so a glance tells you which inputs belong to arrival vs
     departure. Background is a subtle warm-grey wash from the token
     palette — visible against the modal paper without overpowering. */
  .logistics-leg-block {
    background: var(--paper-warm-2);
    border-radius: 4px;
    padding: 16px 18px;
    margin-top: 16px;
  }
  .logistics-leg-block-title {
    font-family: var(--display);
    font-style: normal;
    font-size: 11px;
    font-weight: var(--weight-bold);
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--ink-soft);
    margin: 0 0 14px;
  }
  /* Rows inside a block use a tighter label column and no bottom margin
     on the last row so the block padding controls spacing. */
  .logistics-row--in-block {
    grid-template-columns: minmax(72px, 90px) 1fr;
    margin-bottom: 12px;
  }
  .logistics-row--in-block:last-child { margin-bottom: 0; }

  /* Independent radio chips that wrap per-item (each chip is its own
     pill, no shared background). Used for rough-time-of-day buckets so
     "Tell you later" can drop to a new line cleanly when space is tight. */
  .tag-options {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }
  .tag-options input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
  }
  .tag-options label {
    padding: 6px 12px;
    font-size: 12px;
    font-weight: var(--weight-semibold);
    color: var(--ink-soft);
    border: 1px solid var(--hover-edge);
    border-radius: 999px;
    cursor: pointer;
    background: transparent;
    user-select: none;
    line-height: 1;
    white-space: nowrap;
    transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
  }
  .tag-options label:hover { border-color: rgba(0,0,0,0.4); }
  .tag-options input[type="radio"]:checked + label {
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
  }
  .tag-options input[type="radio"]:focus-visible + label {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
  }

  /* Combined Save button — neutral default tone, no arrive/depart split. */
  .logistics-save--combined { background: var(--ink); }
  .logistics-save--combined:hover { background: var(--ink); }

  /* ── Todo modal (clean task card) ──────────────────────────────
     Replaces the lined-paper treatment: structured, solid content
     that reads as robust — the payment checkout especially. */
  .todo-head { margin-bottom: 4px; }

  .todo-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.5em;
    font-family: var(--sans);
    font-size: 11px;
    font-weight: var(--weight-semibold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ink-soft);
    background: rgba(0, 0, 0, 0.05);
    padding: 0.45em 1em 0.45em 0.64em;
    border-radius: 999px;   /* the one pill, scoped to type badges */
  }
  /* Sized in em so the icon scales with the pill (px-vs-px rounding at
     fractional zoom was throwing the circle out of proportion). */
  .todo-badge-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.6em; height: 1.6em;
    border-radius: 50%;
    background: var(--ink);
    color: var(--paper);
    font-size: 0.9em; font-weight: var(--weight-bold); line-height: 1;
    flex-shrink: 0;
  }
  .todo-badge--pay .todo-badge-icon { background: var(--paid); }

  .todo-title {
    font-family: var(--display);
    font-style: normal;
    font-size: 26px;
    line-height: 1.2;
    margin: 14px 0 0;
    color: var(--ink);
  }
  .todo-title--done { color: var(--ink-faint); }

  .todo-due {
    display: inline-flex; align-items: center; gap: 5px;
    margin-top: 10px;
    font-family: var(--sans);
    font-size: 12px;
    font-weight: var(--weight-semibold);
    letter-spacing: 0.02em;
    color: var(--ink-faint);
  }
  .todo-due--flag { color: var(--due); }
  .todo-due--slipping { color: var(--slipping); }

  .todo-details { font-size: 15px; line-height: 1.6; color: var(--ink-soft); margin: 0 0 4px; }
  .todo-details p { margin: 0 0 10px; }
  .todo-details p:last-child { margin-bottom: 0; }

  /* Flash alert inside the task modal — e.g. a failed payment. Without this
     the redirect's alert was invisible and a failed pay looked like a silent reload. */
  .todo-flash-alert {
    margin: 0 0 18px;
    padding: 12px 14px;
    border: 1px solid rgba(204, 68, 68, 0.35);
    background: rgba(204, 68, 68, 0.07);
    color: var(--required);
    font-size: 13px; line-height: 1.45;
  }

  .todo-zone { margin-top: 24px; }

  /* Action rows — single CTA spans full width (.btn--block); pairs split. */
  .todo-actions { margin-top: 22px; }
  .btn--block { display: flex; width: 100%; }
  .todo-actions--split { display: flex; gap: 12px; }
  .todo-actions--split > .btn,
  .todo-actions--split > .btn-paper { flex: 1; }

  .todo-undo { margin-top: 14px; text-align: center; }
  .todo-undo-link {
    background: none; border: none; cursor: pointer;
    font-family: var(--sans); font-size: 13px; color: var(--ink-faint);
    text-decoration: underline; text-underline-offset: 2px; padding: 4px;
  }
  .todo-undo-link:hover { color: var(--ink); }
  /* Where the undo used to be, on a charge that actually went through. */
  .todo-undo-note {
    margin: 14px 0 0;
    text-align: center;
    font-size: 13px;
    line-height: 1.5;
    color: var(--ink-faint);
  }

  /* ── Payment — checkout chrome ─────────────────────────────────── */
  .pay-summary {
    border: 1px solid var(--hover-edge);
    background: var(--paper-warm);
    padding: 16px 18px;
    margin-bottom: 22px;
  }
  .pay-summary-row {
    display: flex; justify-content: space-between; align-items: baseline; gap: 16px;
    font-size: 14px; color: var(--ink-soft);
  }
  .pay-summary-label { min-width: 0; }
  .pay-summary-amount { flex-shrink: 0; color: var(--ink); }
  .pay-summary-total {
    display: flex; justify-content: space-between; align-items: baseline;
    margin-top: 12px; padding-top: 12px;
    border-top: 1px solid rgba(0, 0, 0, 0.10);
    font-size: 12px; font-weight: var(--weight-semibold);
    letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-soft);
  }
  .pay-summary-total-amount {
    font-family: var(--display);
    font-size: 23px; font-weight: var(--weight-bold);
    letter-spacing: -0.01em; color: var(--ink); text-transform: none;
  }

  .pay-card {
    border: 1px solid rgba(0, 0, 0, 0.16);
    background: var(--paper);
    padding: 14px 16px 16px;
    margin-bottom: 16px;
  }
  .pay-card-head {
    display: flex; justify-content: space-between; align-items: center;
    margin-bottom: 12px;
  }
  .pay-card-label {
    font-size: 11px; font-weight: var(--weight-semibold);
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft);
  }
  .pay-card-secure {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: 11px; font-weight: var(--weight-semibold);
    letter-spacing: 0.04em; color: var(--paid);
  }
  .pay-card-field { min-height: 44px; }  /* reserve height so the Square iframe doesn't jump */
  /* Square lays card number, expiry, CVV and postal code on ONE row and
     divides whatever width it's given. At 264px that left the postal code
     28px wide — unreadable, at the one place money changes hands. Labels
     (includeInputLabels in square_payment_controller) make Square stack the
     fields, and this floor keeps the row from being squeezed on the
     narrowest phones either way. (Aug 5) */
  @media (max-width: 420px) {
    .pay-card { padding-left: 10px; padding-right: 10px; }
    .pay-card-field { min-height: 120px; }
  }
  .pay-error { margin: 12px 0 0; font-size: 13px; line-height: 1.4; color: var(--required); }

  .pay-button {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    width: 100%;
    font-family: var(--sans); font-size: 15px; font-weight: var(--weight-semibold);
    letter-spacing: 0.02em;
    background: var(--ink); color: var(--paper);
    border: none; padding: 15px 24px; cursor: pointer;
    border-radius: 999px; /* HEY posture (phase 6 round 3) */
    transition: background 0.15s ease;
  }
  .pay-button:hover:not(:disabled) { background: var(--ink-hover); }
  .pay-button:disabled { background: var(--paper-warm-2); color: var(--ink-faint); cursor: default; }
  .pay-button-lock { font-size: 13px; }

  .pay-trust { margin: 12px 0 0; text-align: center; font-size: 12px; color: var(--ink-faint); }
  .pay-trust strong { color: var(--ink-soft); font-weight: var(--weight-semibold); }

  /* Out-of-app payment (Venmo/Cash App/PayPal/Zelle/link/manual) — the guest
     pays elsewhere, then confirms here. (Jul 30) */
  .pay-external { display: flex; flex-direction: column; gap: 14px; }
  .pay-button--link { text-decoration: none; }
  .pay-button--link:hover { background: var(--ink-hover); color: var(--paper); }
  .pay-external-handle {
    display: flex; flex-direction: column; gap: 2px;
    border: 1px solid var(--hover-edge); padding: 14px 16px;
  }
  .pay-external-label { font-size: 12px; color: var(--ink-faint); font-weight: var(--weight-semibold); }
  .pay-external-value { font-size: 18px; color: var(--ink); font-family: var(--display); }
  .pay-external-note { margin: 0; font-size: 13px; color: var(--ink-soft); line-height: 1.5; }
  .pay-proof-input { font-size: 13px; color: var(--ink-soft); }
  .pay-external form { display: flex; flex-direction: column; gap: 10px; }

  .pay-paid {
    display: flex; align-items: center; gap: 12px;
    border: 1px solid var(--paid-line); background: var(--paid-soft);
    padding: 14px 16px; margin-bottom: 8px;
  }
  .pay-paid-check {
    flex-shrink: 0; width: 26px; height: 26px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--paid); color: #fff; font-size: 14px;
  }
  .pay-paid-title { font-size: 15px; font-weight: var(--weight-semibold); color: var(--ink); }
  .pay-paid-receipt {
    display: inline-block; margin-top: 2px;
    font-size: 13px; color: var(--ink-faint);
    text-decoration: underline; text-underline-offset: 2px;
  }
  .pay-paid-receipt:hover { color: var(--ink); }

  /* Stub card form (no Square credentials) */
  .pay-stub-note {
    font-size: 11px; color: var(--ink-faint);
    letter-spacing: 0.04em; margin: 0 0 12px;
  }
  .pay-stub-field { margin-bottom: 10px; }
  .pay-stub-row { display: flex; gap: 10px; }
  .pay-stub-row .pay-stub-input { flex: 1; }
  .pay-stub-input {
    display: block; width: 100%; box-sizing: border-box;
    border: 1px solid rgba(0, 0, 0, 0.16); background: var(--paper);
    font-family: var(--sans); font-size: 14px; color: var(--ink);
    padding: 10px 12px;
    opacity: 1; -webkit-text-fill-color: var(--ink);
  }

  /* ── Upload — dropzone ─────────────────────────────────────────── */
  .up-input {
    position: absolute; width: 1px; height: 1px;
    opacity: 0; overflow: hidden; clip: rect(0 0 0 0);
  }
  .dropzone {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 6px; text-align: center;
    border: 1.5px dashed var(--hover-edge);
    background: var(--paper-warm);
    padding: 34px 24px;
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease;
  }
  .dropzone:hover { border-color: var(--ink-soft); background: var(--paper); }
  .dropzone--over { border-color: var(--ink); background: var(--paper); }
  .dropzone--filled { border-style: solid; border-color: rgba(0, 0, 0, 0.16); }
  .dropzone-icon { font-size: 22px; color: var(--ink-soft); }
  .dropzone-main { font-size: 14px; color: var(--ink); }
  /* Drag-speak for mice, tap-speak for fingers. */
  .dropzone-main--touch { display: none; }
  @media (pointer: coarse) {
    .dropzone-main--pointer { display: none; }
    .dropzone-main--touch { display: inline; }
  }
  .dropzone-browse { text-decoration: underline; text-underline-offset: 2px; }
  .dropzone-sub { font-size: 12px; color: var(--ink-faint); }

  .up-chip {
    display: flex; align-items: center; gap: 10px;
    border: 1px solid var(--hover-edge); background: var(--paper);
    padding: 10px 12px; margin-top: 12px;
  }
  .up-chip[hidden] { display: none; }  /* flex display would otherwise beat [hidden] */
  .up-chip-icon { font-size: 16px; }
  .up-chip-name {
    flex: 1; min-width: 0; font-size: 13px; color: var(--ink);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .up-chip-remove {
    background: none; border: none; cursor: pointer;
    color: var(--ink-faint); font-size: 14px; padding: 2px 4px;
  }
  .up-chip-remove:hover { color: var(--ink); }
  .up-replace { position: relative; overflow: hidden; }
  /* Optimistic uploading state — immediate feedback while a (large) file POSTs. */
  .up-chip--uploading { opacity: 0.6; }
  .dropzone--uploading { opacity: 0.55; pointer-events: none; }
  .up-error { margin: 10px 0 0; font-size: 13px; line-height: 1.4; color: var(--required); }
  /* Stays in the DOM/a11y tree always (so the live region announces); empty =
     no visual footprint. */
  .up-error:empty { margin: 0; }

  /* One-tap "Use your profile photo" — the photo Gather already has, offered
     ahead of the dropzone (Aug 3: stop asking for what's on file). */
  .up-profile { margin-bottom: 12px; }
  .up-profile-btn {
    display: flex; align-items: center; gap: 12px; width: 100%;
    border: 1px solid var(--hover-edge); background: var(--paper-warm);
    padding: 10px 12px; cursor: pointer; text-align: left;
    font-family: var(--sans);
    transition: border-color 0.15s ease, background 0.15s ease;
  }
  .up-profile-btn:hover { border-color: var(--ink-soft); background: var(--paper); }
  .up-profile-thumb {
    width: 40px; height: 40px; border-radius: 50%;
    object-fit: cover; flex-shrink: 0;
    border: 1px solid var(--hover-edge);
  }
  .up-profile-body { flex: 1; min-width: 0; }
  .up-profile-title { display: block; font-size: 14px; font-weight: var(--weight-semibold); color: var(--ink); }
  .up-profile-sub { display: block; font-size: 12px; color: var(--ink-faint); margin-top: 1px; }
  .up-profile-go { color: var(--ink-faint); }
  .up-or { margin: 0 0 12px; text-align: center; font-size: 12px; color: var(--ink-faint); }

  .up-attached {
    display: flex; align-items: center; gap: 12px;
    border: 1px solid var(--paid-line); background: var(--paid-soft);
    padding: 14px 16px; margin-bottom: 8px;
  }
  .up-attached-icon { font-size: 20px; }
  .up-attached-body { flex: 1; min-width: 0; }
  .up-attached-title { font-size: 14px; font-weight: var(--weight-semibold); color: var(--ink); }
  .up-attached-sub { font-size: 12px; color: var(--ink-faint); margin-top: 1px; }
  .up-attached-check {
    flex-shrink: 0; width: 24px; height: 24px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--paid); color: #fff; font-size: 13px;
  }
  /* Attached file as a clickable preview (opens inline in a new tab, like a Resource). */
  a.up-attached--link { text-decoration: none; color: inherit; transition: border-color .12s ease; }
  a.up-attached--link:hover { border-color: var(--paid); }
  .up-attached-out { color: var(--ink-faint); }

  /* Image upload — inline thumbnail preview; click opens full size in a new tab. */
  .up-preview { display: inline-block; text-decoration: none; max-width: 100%; }
  .up-preview-img {
    display: block; max-width: 100%; max-height: 240px;
    object-fit: contain;
    border: 1px solid var(--hover-edge);
    background: var(--paper-warm);
  }
  .up-preview-cap {
    display: inline-flex; align-items: center; gap: 4px; margin-top: 8px;
    font-size: 13px; color: var(--ink-soft);
    text-decoration: underline; text-underline-offset: 2px;
  }
  .up-preview:hover .up-preview-cap { color: var(--ink); }

  /* ── Answer ────────────────────────────────────────────────────── */
  .answer-label {
    display: block; margin-bottom: 8px;
    font-size: 11px; font-weight: var(--weight-semibold);
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft);
  }
  .answer-field {
    display: block; width: 100%; box-sizing: border-box;
    border: 1px solid rgba(0, 0, 0, 0.16); background: var(--paper);
    font-family: var(--sans); font-size: 15px; line-height: 1.6; color: var(--ink);
    padding: 12px 14px; resize: vertical;
  }
  .answer-field:focus { outline: none; border-color: var(--ink); }

  /* The quiet prefill line — the form arrived filled from what Gather already
     knew; the guest confirms with one tap. Never auto-completes. */
  .todo-prefill { margin: 10px 0 0; font-size: 13px; color: var(--ink-faint); font-style: italic; }

  /* A host settled this row on their behalf. Stated plainly rather than
     whispered: it explains a ✓ the guest didn't put there, so it has to be
     read, not skimmed past. (Neal, Aug 6) */
  .todo-closed-by-host {
    margin: 14px 0 0;
    padding: 10px 12px;
    background: var(--paper-sunk, var(--paper));
    border-left: 2px solid var(--ink-faint);
    border-radius: 3px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--ink-soft);
  }

  /* ── Choice / multi-choice ─────────────────────────────────────── */
  .choice-set { border: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
  .choice-option {
    display: flex; align-items: center; gap: 11px; cursor: pointer;
    border: 1px solid rgba(0, 0, 0, 0.16); background: var(--paper);
    padding: 12px 14px; font-size: 15px; color: var(--ink);
  }
  .choice-option:hover { border-color: var(--ink); }
  .choice-option input { margin: 0; flex: none; }
  .choice-option:has(input:checked) { border-color: var(--ink); background: var(--paid-soft); }

  /* ── Acknowledge done ──────────────────────────────────────────── */
  .ack-done {
    display: flex; align-items: center; gap: 10px;
    border: 1px solid var(--paid-line); background: var(--paid-soft);
    padding: 14px 16px;
    font-size: 14px; font-weight: var(--weight-semibold); color: var(--ink);
  }
  .ack-done-check {
    width: 24px; height: 24px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--paid); color: #fff; font-size: 13px;
  }

  /* Solo page: the party + note fields tucked into the travel form, set off from
     the Departure block above by clear air and a hairline. */
  .logistics-extras {
    margin-top: 28px;
    padding-top: 24px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
  }

  .logistics-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 4px;
  }
  .logistics-save {
    appearance: none;
    border: none;
    cursor: pointer;
    padding: 12px 28px;
    font-family: var(--sans);
    font-size: 13px;
    font-weight: var(--weight-bold);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    /* Token pair, not literals — a #fff here was white-on-white in dark
       (the cohort modal's Done). Ink fill, paper text, flips together. */
    background: var(--ink);
    color: var(--paper);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    border-radius: 999px; /* HEY posture (phase 6 round 3) */
    transition: transform .12s ease, box-shadow .12s ease;
  }
  .logistics-save:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 10px rgba(0,0,0,0.15);
    text-decoration: none;
    color: #fff;
  }
  .logistics-save.arrive { background: var(--arrive); }
  .logistics-save.depart { background: var(--depart); }

  /* Split row used on the todo modal: a draft "Save" alongside the
     primary "Save and mark done" — both right-aligned with a gap. */
  .logistics-actions--split { gap: 12px; }

  /* Outline variant — same shape and rhythm as .logistics-save, but
     reads as the secondary action. Used for the draft "Save" on the
     todo modal next to the filled "Save and mark done". */
  .logistics-save--outline {
    background: transparent;
    color: var(--ink);
    box-shadow: inset 0 0 0 1.5px var(--ink);
  }
  .logistics-save--outline:hover {
    background: rgba(0, 0, 0, 0.04);
    color: var(--ink);
  }


  /* ── Mobile (≤ 768px) ── */
  @media (max-width: 768px) {
    /* Whole meta row stays on one line — letterhead · | · dates · pill —
       wrapping naturally if the screen is too narrow. */
    .prep-identity-meta {
      gap: 12px;
      flex-wrap: wrap;
    }
    .prep-identity-title { font-size: 28px; line-height: 1.15; }
    .prep-attending-name { font-size: 28px; line-height: 1.15; }
    .prep-attending-lead { font-size: 14px; }
    .prep-attending-when { font-size: 17px; }
    .prep-dates { gap: 10px; font-size: 12px; }
    .prep-dates-range { font-size: 12px; letter-spacing: 0.12em; }
    .prep-dates-countdown { font-size: 10px; padding: 3px 8px; }
    /* Phone rhythm (mobile punch-list): tighter identity → hosts cadence. */
    .prep-hosts { margin-bottom: var(--space-4); }

    .prep-travel { grid-template-columns: 1fr; gap: 12px; }
    .prep-travel-summary { font-size: 18px; }

    /* Combined card — stack the two legs vertically on phones. */
    .prep-travel-legs { grid-template-columns: 1fr; gap: 16px; }

    .prep-folders-grid { grid-template-columns: 1fr 1fr; gap: 12px; }

    .prep-todos { margin-left: 0; margin-right: 0; padding: 2px 12px; }
    .prep-todo-due { font-size: 13px; }

    /* Logistics modal — title smaller, fields stack one per line. */
    .logistics-direction-title { font-size: 36px; }
    .logistics-direction-date-num { font-size: 26px; }
    .logistics-direction-head { margin-bottom: 22px; }
    .logistics-fields { grid-template-columns: 1fr; gap: 16px; }
    .logistics-upload { font-size: 13px; }

    /* Combined modal — collapse the row grid on phones: the label stacks
       above the cells, and the arrival/departure cells stack vertically.
       Each cell shows its own small caption so the user can still tell
       legs apart without the desktop column headers. */
    .logistics-combined-title { font-size: 36px; }
    .logistics-row {
      grid-template-columns: 1fr;
      gap: 8px;
    }
    .logistics-row-label { padding-top: 0; }
    .logistics-row-cells { grid-template-columns: 1fr; gap: 14px; }
    .logistics-row-cell[data-leg="arrive"]::before,
    .logistics-row-cell[data-leg="depart"]::before {
      display: block;
      font-size: 10px;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      font-weight: var(--weight-bold);
      color: var(--ink-soft);
      margin-bottom: 4px;
    }
    .logistics-row-cell[data-leg="arrive"]::before { content: "Arrival"; }
    .logistics-row-cell[data-leg="depart"]::before { content: "Departure"; }
    /* In unified mode, the leg captions are unnecessary on the Time and
       Flight rows since both cells share the same mode — let them show
       anyway; users still want to know which input is which date. */
    .logistics-mode-toggles { flex-direction: column; gap: 14px; align-items: stretch; }
    .date-range__arrow { padding-bottom: 8px; }

    /* Todo modal head — also stack-friendly. */
    .todo-head { gap: 14px; }
    .todo-title { font-size: 24px; }
    .todo-due-stamp { padding: 5px 10px; }
    .todo-due-stamp-date { font-size: 16px; }

    /* Modal action rows — stack the buttons full-width on phones so a
       label like "Save and mark done" can sit on a single line. Primary
       on top, secondary underneath. */
    .logistics-actions {
      flex-direction: column-reverse;
      align-items: stretch;
      gap: 10px;
    }
    .logistics-actions--split { gap: 10px; }
    .logistics-save { justify-content: center; width: 100%; }
  }

  /* ── Empty state (no host has published anything) ── */
  .prep-empty {
    padding: 80px var(--space-5);
    text-align: center;
  }
  .prep-empty-headline {
    font-family: var(--display);
    font-style: normal;
    font-size: 24px;
    line-height: 1.4;
    color: var(--ink-soft);
  }
  .prep-empty-sub {
    margin-top: 14px;
    font-size: 13px;
    max-width: 340px;
    margin-left: auto;
    margin-right: auto;
    line-height: 1.6;
    color: var(--ink-faint);
  }
}

@layer components {
  /* ── YOUR HOST (D3, Law 7) — face, own words, lodge local time. ── */
  .your-host { margin-top: var(--space-8); }
  .your-host-title {
    font-size: 12px; letter-spacing: .07em; text-transform: uppercase;
    color: var(--ink-soft); font-weight: var(--weight-semibold);
    border-bottom: 1px solid var(--paper-edge);
    padding-bottom: 10px; margin: 0 0 16px;
  }
  .your-host-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 16px;
  }
  .your-host-card {
    display: flex; gap: 16px; align-items: flex-start;
    background: var(--paper-warm);
    border: 1px solid var(--hover-edge);
    border-radius: var(--radius-md);
    padding: 18px 20px;
  }
  .your-host-face {
    width: 72px; height: 72px; flex: none;
    border-radius: 50%; object-fit: cover;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .your-host-face--initials {
    background: var(--paper-warm-2); color: var(--ink-soft);
    font-weight: var(--weight-semibold); font-size: 18px;
  }
  .your-host-name { font-weight: var(--weight-bold); font-size: 16px; }
  .your-host-words {
    color: var(--ink-soft); font-size: 14px; font-style: italic;
    line-height: 1.55; margin: 6px 0 8px;
  }
  .your-host-write {
    font-size: 13.5px; font-weight: var(--weight-semibold);
    color: var(--ink); text-decoration: underline; text-underline-offset: 3px;
  }
  .your-host-time { margin-top: 12px; font-size: 13px; color: var(--ink-faint); }
}

@layer components {
  /* ── THE SHUTTLE BOARD, guest side (D3). ── */
  .ride-cards { display: flex; flex-direction: column; gap: 14px; }
  .ride-card {
    border: 1px solid var(--hover-edge);
    border-radius: var(--radius-md);
    background: var(--paper-warm);
    padding: 16px 18px;
  }
  .ride-card-when { font-size: 12px; letter-spacing: .04em; color: var(--ink-faint); font-weight: var(--weight-semibold); text-transform: uppercase; }
  .ride-card-locked { color: var(--paid); margin-left: 6px; }
  .ride-card-route { font-size: 17px; font-weight: var(--weight-bold); margin-top: 4px; }
  .ride-card-vehicle { font-size: 13px; color: var(--ink-soft); margin-top: 2px; }
  .ride-card-people { display: flex; align-items: center; gap: 6px; margin-top: 12px; flex-wrap: wrap; }
  .ride-face {
    width: 30px; height: 30px; border-radius: 50%; overflow: hidden; flex: none;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--paper-warm-2); color: var(--ink-soft);
    font-size: 11px; font-weight: var(--weight-semibold);
    border: 1px solid var(--paper-edge);
  }
  .ride-face img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .ride-card-companions { font-size: 13.5px; color: var(--ink-soft); margin-left: 4px; }
  .ride-empty { color: var(--ink-soft); font-size: 15px; line-height: 1.6; }

  /* ── The car you're in, in the order it fills up ────────────────── */
  .ride-card-lede { font-size: 15px; margin: 10px 0 0; line-height: 1.5; }
  /* The thing to do before the car comes. Sits between the lede and the
     manifest and wants to be read, so it takes full ink rather than the soft
     grey the supporting lines use. */
  .ride-card-note {
    margin: 12px 0 0; padding: 10px 12px;
    border-radius: 8px;
    background: color-mix(in srgb, var(--paper-edge) 22%, transparent);
    color: var(--ink); font-size: 14.5px; line-height: 1.55;
  }

  .ride-manifest-caption {
    margin: 14px 0 0; font-size: .74rem; letter-spacing: .08em;
    text-transform: uppercase; color: var(--ink-faint);
  }
  .ride-manifest-caption + .ride-manifest { margin-top: 4px; }
  .ride-manifest { list-style: none; margin: 12px 0 0; padding: 0; }
  .ride-manifest-row {
    display: flex; align-items: center; gap: 10px;
    padding: 5px 0; font-size: 14px; color: var(--ink-soft);
  }
  /* The reader's own row is the one they scan for. Weight, not colour —
     colour is doing other work on this page. */
  .ride-manifest-row.is-you { color: var(--ink); font-weight: var(--weight-semibold); }
  .ride-manifest-at {
    min-width: 72px; font-variant-numeric: tabular-nums; white-space: nowrap;
  }
  /* One card can hold a bare time and a dated one — KPF flies the evening she
     drives, Tatsuya four days later. Widen the whole column when any row
     carries a date so the names still line up. */
  .ride-manifest--dated .ride-manifest-at { min-width: 122px; }
  .ride-manifest .ride-face { width: 24px; height: 24px; font-size: 10px; }
  .ride-card-stops,
  .ride-card-foot { font-size: 13.5px; color: var(--ink-soft); margin: 10px 0 0; }

  /* The driver's half. A rider never sees this. */
  .ride-card--driving { border-color: var(--ink); }
  .ride-keys {
    margin-top: 14px; padding-top: 12px;
    border-top: 1px solid var(--hover-edge);
  }
  .ride-keys-h {
    font-size: 12px; letter-spacing: .04em; text-transform: uppercase;
    color: var(--ink-faint); font-weight: var(--weight-semibold); margin: 0;
  }
  .ride-keys-car { font-size: 15px; font-weight: var(--weight-semibold); margin: 6px 0 0; }
  .ride-keys-where { font-size: 14px; margin: 2px 0 0; }
  .ride-keys-notes { font-size: 13.5px; color: var(--ink-soft); margin: 6px 0 0; line-height: 1.55; }

  /* ── Choosing a driver: the list that can hold a sentence ──────── */
  .drivers { list-style: none; margin: 0; padding: 0; }
  .driver-row { border-bottom: 1px solid var(--hover-edge); }
  .driver-row:last-child { border-bottom: 0; }
  .driver-pick { display: flex; gap: 10px; align-items: flex-start; padding: 9px 2px; cursor: pointer; }
  .driver-pick input { margin-top: 3px; flex: none; }
  .driver-who { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
  .driver-name { font-weight: var(--weight-semibold); }
  .driver-line { font-size: 12.5px; color: var(--ink-faint); }
  /* Their own words, which a <select> could never show. */
  .driver-said { font-size: 12.5px; color: var(--ink-soft); font-style: italic; }
  .drivers-more { margin-top: 10px; }
  .drivers-more summary { font-size: 13px; color: var(--ink-soft); cursor: pointer; }

  /* ── Travel: the people arriving who are on nobody's run ───────── */
  .own-way { margin-top: 14px; }
  .own-way-h {
    font-size: 12px; letter-spacing: .04em; text-transform: uppercase;
    color: var(--ink-faint); font-weight: var(--weight-semibold); margin: 0 0 8px;
  }
  .own-way-list { list-style: none; margin: 0; padding: 0; }
  .own-way-row {
    display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
    padding: 5px 0; font-size: 14px;
  }
  .own-way-name { font-weight: var(--weight-semibold); }
  .own-way-when { color: var(--ink-soft); }
  /* Only where it is genuinely the exception. When most of a list carries a
     mark the mark IS the background — so this stays for the few, and the
     departures side, where nearly everyone needs one, says it once instead. */
  .own-way-flag { color: var(--slipping); font-size: 13px; }
  /* Never asked is not the same as asked and still open — it wants noting,
     not marking. --slipping is the page's one "this is drifting" colour. */
  .own-way-flag--quiet { color: var(--ink-faint); }

  /* ── Travel tab: Arrival Board ─────────────────────────────────── */
  .arrival-day-label {
    font-size: 12px; letter-spacing: .06em; text-transform: uppercase;
    color: var(--ink-soft); font-weight: var(--weight-semibold);
    margin: 14px 0 6px;
  }
  .arrival-day-label:first-child { margin-top: 0; }
  .g-row-label svg { width: 15px; height: 15px; vertical-align: -2px; margin-right: 6px; opacity: .7; }
  /* A status flag, not a link — no underline (it isn't clickable; the ride
     gets assigned on the Shuttle Board / carpools below). Jul 30. */
  .arrival-needs-ride {
    color: var(--flag, #b4431f); font-weight: var(--weight-semibold);
    font-size: 14px; white-space: nowrap; text-decoration: none;
  }
  /* The quiet counterpart once a run covers the leg — the board and the
     transit plan tell the same story. */
  .arrival-on-run {
    color: var(--ink-soft); font-size: 14px; white-space: nowrap;
  }
}

@layer components {
  .your-host-prompt {
    font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
    color: var(--ink-faint); font-weight: var(--weight-semibold);
    margin-top: 6px;
  }
}

/* Where you're going — the address line under the lodge clock. */
@layer components {
  .your-host-where { margin-top: 6px; font-size: 13.5px; }
  .your-host-where a { color: var(--ink-soft); text-decoration: underline; text-underline-offset: 2px; }
  .your-host-where-notes { display: block; color: var(--ink-faint); font-size: 12.5px; margin-top: 2px; }
  .place-address { margin: 0 0 16px; }
  .place-address summary { cursor: pointer; color: var(--ink-soft); font-size: 14px; }
  .place-address-form { margin-top: 12px; max-width: 520px; }
}

/* The board composer — a quiet fold on the reading surface. */
@layer components {
  .board-compose { margin: 14px 0 4px; }
  .board-compose > summary { display: inline-flex; cursor: pointer; list-style: none; }
  .board-compose > summary::-webkit-details-marker { display: none; }
  .board-compose-form { margin-top: 14px; max-width: 480px; }
  .face-see-all { margin-top: 10px; font-size: 13.5px; }
}

@layer components {
  /* ── Messages on prep (Neal's stack rank, Jul 16): the news sits
     right under the identity band — latest message readable in place,
     the next two as rows, the rest behind the door. ── */
  .prep-messages {
    background: var(--paper);
    border: 1px solid var(--hover-edge);
    border-radius: var(--radius-md);
    padding: var(--space-5) var(--space-5) var(--space-4);
    margin: var(--space-5) 0;
  }
  .prep-messages-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: var(--space-3);
  }
  .prep-messages-all {
    font-size: 12.5px;
    font-weight: var(--weight-semibold);
    color: var(--ink-soft);
    text-decoration: none;
    white-space: nowrap;
  }
  .prep-messages-all:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
  .prep-message-lead {
    display: flex;
    flex-direction: column;
    gap: 4px;
    text-decoration: none;
    color: inherit;
    padding: 2px 0 var(--space-3);
  }
  .prep-message-lead-title {
    font-family: var(--sans);
    font-size: 15px;
    font-weight: var(--weight-bold);
    color: var(--ink);
    line-height: 1.3;
  }
  .prep-message-lead:hover .prep-message-lead-title { text-decoration: underline; text-underline-offset: 3px; }
  .prep-message-lead-meta { font-size: 12px; color: var(--ink-faint); }
  .prep-message-lead-body {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--ink-soft);
    max-width: 62ch;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .prep-message-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 0;
    border-top: 1px solid var(--hover-edge);
    text-decoration: none;
  }
  .prep-message-row .avatar { flex: none; width: 26px; height: 26px; font-size: 10px; }
  .prep-message-row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
  .prep-message-row-title {
    font-size: 13.5px;
    font-weight: var(--weight-bold);
    color: var(--ink);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .prep-message-row-line {
    font-size: 12.5px; color: var(--ink-faint);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .prep-message-row:hover .prep-message-row-title { text-decoration: underline; text-underline-offset: 3px; }
  .prep-message-row-meta { font-size: 12px; color: var(--ink-faint); white-space: nowrap; }
  .prep-messages-empty { margin: 0; font-size: 13.5px; }
  .prep-messages-empty a { color: inherit; }
}

@layer components {
  /* ── Host tools (the one-surface model, Jul 16): the quiet strip of
     doors only hosts and organizers see on the shared gathering page.
     The dashed border is the tell: guests never see this. ── */
  .host-tools {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    border: 1px dashed var(--ink-faint);
    border-radius: 8px;
    padding: 9px 14px;
    margin-bottom: var(--space-5);
  }
  .host-tools-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--cap-sm);
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-cap);
    text-transform: uppercase;
    color: var(--ink-faint);
    white-space: nowrap;
  }
  .host-tools-label svg {
    width: 13px; height: 13px;
    fill: none; stroke: currentColor;
    stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
  }
  .host-tools-links { display: inline-flex; gap: 14px; flex-wrap: wrap; }
  .host-tools-links a {
    font-size: 13.5px;
    font-weight: var(--weight-semibold);
    color: var(--ink-soft);
    text-decoration: none;
  }
  .host-tools-links a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

  /* The folder band's way back to the shared page. */
  .host-banner-crumb {
    color: inherit;
    font-size: 13.5px;
    font-weight: var(--weight-semibold);
    text-decoration: none;
    opacity: 0.85;
  }
  .host-banner-crumb:hover { opacity: 1; text-decoration: underline; text-underline-offset: 3px; }
}

@layer components {
  /* ── Your lodging (Jul 16) — where you sleep, as a card. ── */
  .prep-lodging-card {
    display: grid;
    grid-template-columns: 180px minmax(0, 1fr);
    background: var(--paper);
    border: 1px solid var(--hover-edge);
    border-radius: var(--radius-md);
    overflow: hidden;
    margin: var(--space-5) 0;
    text-decoration: none;
    color: inherit;
    transition: border-color 120ms ease;
  }
  .prep-lodging-card:hover { border-color: var(--ink-faint); text-decoration: none; }
  .prep-lodging-photo { width: 100%; height: 100%; min-height: 110px; object-fit: cover; }
  .prep-lodging-body { padding: 14px 18px; display: flex; flex-direction: column; gap: 2px; }
  .prep-lodging-name { font-family: var(--display); font-size: 19px; font-weight: var(--weight-semibold); color: var(--ink); }
  /* Only shown when a guest's room is held for less time than they are here
     — see _prep_content. Sits above the meta line and reads warmer than it:
     it is their own answer, not a fact about the cabin. */
  .prep-lodging-nights {
    display: block;
    font-size: 13px;
    color: var(--ink-soft);
  }
  .prep-lodging-meta { font-size: 13px; color: var(--ink-faint); }
  .prep-lodging-card:hover .prep-lodging-meta { color: var(--ink-soft); }
  @media (max-width: 560px) {
    .prep-lodging-card { grid-template-columns: 1fr; }
    .prep-lodging-photo { max-height: 140px; }
  }
}

@layer components {
  /* ── The section labels, Basecamp-card style (Neal, Jul 16 night):
     distinct warm color, real size, title case — the page's wayfinding. ── */
  .prep-roll-note { font-size: 12.5px; color: var(--ink-faint); margin: 6px 0 0; }
}

@layer components {
  /* Activities on the itinerary wear their own quiet tag. */
  .chk-tag--activity {
    background: color-mix(in srgb, #a85f33 14%, transparent);
    color: #a85f33;
  }
  :root[data-theme="dark"] .chk-tag--activity { color: #e2a377; }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .chk-tag--activity { color: #e2a377; }
  }
}

/* ── The section labels, Basecamp-card style (Jul 16 night) — UNLAYERED
   and double-classed on purpose: they must beat legacy per-section
   title rules (week-line-title etc.) that live outside @layer. ── */
.prep-h.prep-h {
  font-family: var(--display);
  font-size: 17px;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.01em;
  text-transform: none;
  border-bottom: 0;
  color: #a85f33;
}
:root[data-theme="dark"] .prep-h.prep-h { color: #e2a377; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .prep-h.prep-h { color: #e2a377; }
}

@layer components {
  /* ── Outside labels (Jul 16 night): every section announces itself
     ABOVE its card, one consistent grammar. ── */
  .prep-section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin: var(--space-6) 0 8px;
  }
  .prep-section-head .prep-h { margin: 0; }
  .prep-messages { margin-top: 0; }
  .chat-card-head--bare { justify-content: flex-end; }
  .chat-card-door--locked { opacity: 0.75; cursor: default; }
  .chat-card-door--locked:hover { animation: none; box-shadow: none; }
  .prep-where {
    margin: var(--space-7) 0 0;
    font-size: 13px;
    color: var(--ink-faint);
    text-align: center;
  }
  .prep-where a { color: var(--ink-soft); text-decoration: none; font-weight: var(--weight-semibold); }
  .prep-where a:hover { text-decoration: underline; text-underline-offset: 3px; }
  .prep-where-notes { display: block; margin-top: 2px; }
}

@layer components {
  /* ── The schedule's foot, BC to-do style (Jul 16 night): completions
     as a green dropdown row, the add-link quietly beneath. ── */
  .week-line-done > summary {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    list-style: none;
    font-size: 14px;
    color: var(--ink-soft);
  }
  .week-line-done > summary::-webkit-details-marker { display: none; }
  /* The strip said "6 done" and stopped there, so the one route back to an
     answered ask read as a receipt rather than a door. Faint on purpose:
     the count stays the anchor, the hint just says the row opens. (Aug 31) */
  .week-done-hint { color: var(--ink-faint); }
  .done-mark svg {
    width: 17px; height: 17px;
    fill: none;
    stroke: #3e7d4f;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    transition: transform 140ms ease;
  }
  .done-mark .done-check { transition: opacity 120ms ease; }
  .week-line-done[open] .done-mark svg { transform: rotate(0); }
  .week-line-done[open] .done-mark .done-check { opacity: 0.4; }
  .week-line .board-compose { margin-top: 10px; }
  .week-line .board-compose > summary {
    display: inline-block;
    background: none;
    border: 0;
    padding: 0 0 0 25px;
    font-size: 14px;
    font-weight: var(--weight-semibold);
    color: var(--ink-soft);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
    list-style: none;
  }
  .week-line .board-compose > summary::-webkit-details-marker { display: none; }
  .week-line .board-compose > summary:hover { color: var(--ink); }
}

@layer components {
  /* ── The pulse (Jul 17): the folder face's computed verdict, folded
     to its headline on the shared page. Hosts only. ── */
  .host-pulse {
    border: 1px dashed var(--ink-faint);
    border-radius: 8px;
    padding: 9px 14px;
    margin: 8px 0 var(--space-5);
    font-size: 13.5px;
    color: var(--ink-soft);
  }
  .host-pulse > summary {
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-weight: var(--weight-semibold);
    color: var(--ink);
  }
  .host-pulse > summary::-webkit-details-marker { display: none; }
  .host-pulse-mark { color: #a85f33; font-size: 11px; }
  .host-pulse-p { margin: 10px 0 0; line-height: 1.55; }
}

@layer components {
  /* ── Subscribe (calendar feed) — a quiet word beside a section head;
     opens a small paper popover with the two subscribe doors. Lives on
     the guest Schedule head and the folder's Basic information head. ── */
  .cal-subscribe { position: relative; }
  .cal-subscribe > summary {
    cursor: pointer;
    list-style: none;
    font-size: 13px;
    font-weight: var(--weight-semibold);
    color: var(--ink-faint);
    text-decoration: underline;
    text-underline-offset: 3px;
  }
  .cal-subscribe > summary::-webkit-details-marker { display: none; }
  .cal-subscribe > summary:hover { color: var(--ink); }
  .cal-subscribe-pop {
    position: absolute;
    right: 0;
    top: calc(100% + 6px);
    z-index: 30;
    width: 250px;
    background: var(--paper);
    border: 1px solid var(--paper-edge);
    border-radius: var(--radius-md);
    box-shadow: 0 8px 24px var(--paper-deep-shadow);
    padding: 12px 14px;
  }
  .cal-subscribe-copy {
    margin: 0 0 10px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--ink-soft);
  }
  .cal-subscribe-pop a {
    display: block;
    padding: 6px 0;
    font-size: 13.5px;
    font-weight: var(--weight-semibold);
    color: var(--ink);
    text-decoration: none;
  }
  .cal-subscribe-pop a + a { border-top: 1px dashed var(--paper-edge); }
  .cal-subscribe-pop a:hover { text-decoration: underline; text-underline-offset: 3px; }
}

@layer components {
  /* PREVIEWING A GUEST'S PAGE (Neal, Aug 11) — an organizer reading a week
     they are not on. Five of these surfaces used to bounce to /home/host; now
     they render, and this says whose page it is.

     Deliberately quiet. It is context, not a warning: nothing has gone wrong,
     and the thing below it is worth reading. */
  .guest-preview {
    margin: 0 0 18px;
    padding: 14px 16px;
    border: 1px solid var(--paper-edge);
    border-left: 3px solid var(--ink-faint);
    border-radius: var(--radius-md);
    background: var(--paper-warm);
  }
  .guest-preview-lead {
    margin: 0;
    font-size: 14.5px;
    font-weight: var(--weight-semibold);
    color: var(--ink);
  }
  .guest-preview-tag {
    display: inline-block;
    margin-right: 8px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--ink);
    color: var(--paper);
    font-size: 10.5px;
    font-weight: var(--weight-bold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    vertical-align: 1px;
  }
  .guest-preview-body {
    margin: 6px 0 0;
    font-size: 14px;
    line-height: 1.55;
    color: var(--ink-soft);
  }
  .guest-preview-go { margin: 12px 0 0; }

  /* The guest's own controls, shown but unusable. Faded enough to read as
     out of reach, legible enough that the preview is honest about what a
     guest actually sees. `inert` does the real work; this is the tell. */
  .guest-preview-inert {
    opacity: 0.55;
    filter: saturate(0.6);
    cursor: default;
  }
}

/* ── WHICH STRETCH ARE YOU THINKING ────────────────────────────────
   Only on a gathering that runs in more than one stretch, and only before
   somebody has firm dates. Saves on pick, so there is no button to press
   twice. (Chad, Aug) */
.lean { margin-top: 22px; }

/* The control names itself, permanently. It used to be titled by its own
   ANSWER — "You said October 24 – November 30" replaced the question — so
   a guest coming back could not tell what was being asked. (Neal, Aug 26) */
.lean-h {
  font-family: var(--display);
  font-size: 13px;
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-cap);
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 5px;
}
.lean-q { margin: 0 0 12px; font-size: 14px; color: var(--ink-soft); }
.lean-choices { display: flex; flex-wrap: wrap; gap: 10px; }

/* Wide enough to hold two lines: the dates, and how long the stretch runs.
   On a five-month residency one stretch is five weeks and the other is
   thirteen, and the dates alone never say that. A pill sized to one line
   of text read as a tab; sized to its content it reads as an answer. */
.lean-opt {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  padding: 10px 16px 10px 38px;
  position: relative;
  border: 1px solid var(--paper-edge);
  border-radius: 12px;
  font-size: 14px;
  color: var(--ink);
  cursor: pointer;
  background: var(--paper);
}
.lean-opt:hover { border-color: var(--ink-faint); }
.lean-opt.is-on {
  border-color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--ink);
}
/* The box sits in the padding well, vertically centred on the whole
   option rather than on its first line. */
.lean-opt input {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  margin: 0;
  width: 15px;
  height: 15px;
  accent-color: var(--ink);
  cursor: pointer;
}
.lean-opt-dates { font-weight: var(--weight-semibold); line-height: 1.3; }
.lean-opt-len { font-size: 12.5px; color: var(--ink-faint); line-height: 1.3; }
.lean-opt--unsure { justify-content: center; }

/* Quiet, and UNDER the question rather than in place of it. */
.lean-saved { margin: 10px 0 0; font-size: 12.5px; color: var(--ink-faint); }

@media (max-width: 560px) {
  /* Two stretches side by side at 390px is two half-width pills with the
     dates wrapping inside them. One each, full width. */
  .lean-choices { flex-direction: column; align-items: stretch; }
  .lean-opt { width: 100%; }
}

/* IN OR OUT for a happening, on the Timeline. In or out and nothing else —
   no capacity, no waitlist, no plus-ones. If a thing genuinely has a limit
   it should be an ask, which already carries money and a deadline. (Aug 25) */
.hap-rsvp-row { display: inline-flex; gap: 6px; margin-top: 6px; }
.hap-rsvp {
  padding: 4px 12px;
  border: 1px solid var(--paper-edge);
  border-radius: 999px;
  background: var(--paper);
  font-size: 12.5px;
  color: var(--ink-soft);
  cursor: pointer;
}
.hap-rsvp.is-on {
  border-color: var(--ink);
  color: var(--ink);
  font-weight: var(--weight-semibold);
}
.hap-rsvp-form { display: inline; }
