@layer components {
  /* ── Host folder ─────────────────────────────────────────────
     Same clipboard architecture as /stay (cork desk, landscape,
     masonite tray, paper, metal clip). The paper carries:
       1. A full-width "Host view" band at the top,
       2. Three sub-tabs,
       3. The active tab's content.
     Editor modals slide up over the clipboard exactly like the stay
     modals (set @modal in controller). */

  /* ── Hosting band ─────────────────────────────────────────────
     Full-bleed color band at the very top of the paper. It's a sibling
     of .stay-board-content (not inside it) so it isn't pushed down by
     the clip-clearance padding. Negative left/right margins break it
     out of the .stay-board horizontal padding so it reaches paper edge
     to paper edge. The clip is centered above this band. */
  .stay-board > .host-banner {
    background: var(--host-purple);
    color: var(--paper-warm);
    /* Flush header band — sits at the very top of the paper, edge to edge,
       breaking out of the board's horizontal padding to reach paper edge
       to paper edge. (Previously offset down to clear the clip.) */
    margin: 0 -80px;
    padding: 22px 80px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    box-shadow:
      inset 0 1px 0 rgba(0, 0, 0, 0.10),
      inset 0 -1px 0 rgba(0, 0, 0, 0.18);
  }
  .host-banner-text {
    font-family: var(--display);
    font-style: normal;
    font-size: 18px;
    line-height: 1.2;
    text-shadow: 0 1px 1px rgba(0, 0, 0, 0.18);
  }
  .host-banner-cta {
    flex-shrink: 0;
  }

  /* View-as toggle — persistent Host | Guest switch in the (dark) banner. The
     whole control is a link to the opposite view, so any click flips it. */
  .view-as-toggle { display: inline-flex; align-items: center; gap: 12px; flex-shrink: 0; text-decoration: none; }
  .view-as-toggle:hover,
  .view-as-toggle:focus,
  .view-as-label,
  .view-as-seg { text-decoration: none; }
  .view-as-toggle:hover .view-as-seg:not(.is-active) { color: #fff; }
  .view-as-label {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.6);
  }
  .view-as-segs {
    display: inline-flex;
    background: rgba(255, 255, 255, 0.16);
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-radius: 999px;
    padding: 3px;
  }
  .view-as-seg {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
    color: rgba(255, 255, 255, 0.85);
    text-decoration: none;
    padding: 6px 16px;
    border-radius: 999px;
    transition: background 0.12s ease, color 0.12s ease;
  }
  .view-as-seg:hover { color: #fff; text-decoration: none; }
  .view-as-seg.is-active,
  .view-as-seg.is-active:hover { background: var(--ink); color: var(--paper); }

  /* Organizer variant — same layout but a light purple wash + purple text
     so it reads as an informational note rather than a bold host badge. */
  .host-banner--organizer {
    background: var(--host-purple-soft);
    color: var(--host-purple);
    box-shadow:
      inset 0 1px 0 rgba(0, 0, 0, 0.06),
      inset 0 -1px 0 rgba(0, 0, 0, 0.10);
  }

  /* The board's content area no longer needs the full clip clearance
     when the band sits between the clip and content. The host folder
     always shows the band; the stay clipboard shows it only when the
     viewer is the host (toggled by .stay-shell--host-viewing). */
  /* The same clearance the guest's back-home link needs. The staging audit
     found "Close these dates" sitting under the Chat pill on a phone;
     anything that ends this column has the same problem. (Aug 25) */
  .host-shell .stay-board-content,
  .stay-shell--host-viewing .stay-board-content {
    padding-bottom: var(--dock-clearance);
    padding-top: 32px;
  }

  /* ── Sub-tabs — square segmented toggle, centered on desktop. Sharp corners
     (vs the rounded view-as toggle) + a filled active segment make it read as
     a control, not a label. ──────────────────────────────────────────── */
  .host-tabs-wrap {
    display: flex;
    justify-content: center;
    margin: 0 0 28px;
  }
  /* Centred is right when they all fit and wrong when they don't: a strip
     that overflows AND centres puts the first tab half off the left edge,
     so the row starts mid-word with no way to tell whether the beginning
     is missing or the end is. Once it scrolls, it starts at the start —
     the controller still brings the active tab into view, and the edge
     fades still say which way there's more. (Aug 11) */
  @media (max-width: 800px) {
    .host-tabs-wrap { justify-content: flex-start; }
  }
  .host-tabs {
    display: inline-flex;
    gap: 0;
    padding: 4px;
    background: rgba(0, 0, 0, 0.06);
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: 0;
    max-width: 100%;
    /* Six tabs outgrow a phone — they scroll instead of clipping
       (Lodgings/Fleet/Chat were unreachable at 390px). */
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .host-tabs::-webkit-scrollbar { display: none; }
  /* Edge fades say "more tabs this way" — the tab-strip controller keeps
     the classes honest on scroll/resize. */
  .host-tabs.can-scroll-right {
    -webkit-mask-image: linear-gradient(to right, black calc(100% - 32px), transparent);
    mask-image: linear-gradient(to right, black calc(100% - 32px), transparent);
  }
  .host-tabs.can-scroll-left {
    -webkit-mask-image: linear-gradient(to left, black calc(100% - 32px), transparent);
    mask-image: linear-gradient(to left, black calc(100% - 32px), transparent);
  }
  .host-tabs.can-scroll-left.can-scroll-right {
    -webkit-mask-image: linear-gradient(to right, transparent, black 32px, black calc(100% - 32px), transparent);
    mask-image: linear-gradient(to right, transparent, black 32px, black calc(100% - 32px), transparent);
  }
  .host-tab { flex: none; }
  .host-tab {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
    color: var(--ink-soft);
    text-decoration: none;
    padding: 9px 18px;
    border-radius: 0;
    white-space: nowrap;
    transition: background 0.12s ease, color 0.12s ease;
  }
  .host-tab:hover { color: var(--ink); background: var(--hover-wash); text-decoration: none; }
  .host-tab.active,
  .host-tab.active:hover { background: var(--ink); color: var(--paper); }

  /* ── Section heads ────────────────────────────────────────────
     Title on a slate rule, with a circular edit icon at the right.
     The head IS the section divider — sections themselves don't carry
     borders. */
  .host-section { padding: 0 0 28px; }
  .host-section:last-child { padding-bottom: 0; }

  /* THE HOSTS PANEL (Aug 19) — who runs this week and since when.
     Tokens throughout: this sits on the gathering page, which carries a
     backdrop photo and renders in both themes. A literal here would repeat
     the look book's mistake, where an email printed at 1.10:1 in the dark. */
  .host-roster { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
  .host-roster-row { display: flex; align-items: center; gap: 12px; }
  .host-roster-name { font-weight: var(--weight-semibold); }
  /* Semantic, not the accent: this is a warning about a real consequence
     (they are receiving nothing), so it reads as one. */
  .host-roster-bounce {
    margin-left: 8px;
    font-size: 10.5px;
    font-weight: var(--weight-semibold);
    letter-spacing: .04em;
    text-transform: uppercase;
    padding: 2px 7px;
    border-radius: 999px;
    background: var(--warn-wash, rgba(180, 83, 9, .14));
    color: var(--warn-ink, #b45309);
    white-space: nowrap;
  }
  @media (prefers-color-scheme: dark) {
    .host-roster-bounce { background: rgba(251, 191, 36, .16); color: #fbbf24; }
  }
  :root[data-theme="dark"] .host-roster-bounce { background: rgba(251, 191, 36, .16); color: #fbbf24; }
  :root[data-theme="light"] .host-roster-bounce { background: rgba(180, 83, 9, .14); color: #b45309; }
  .host-roster-since {
    margin-left: auto;
    text-align: right;
    font-size: 12.5px;
    color: var(--ink-soft);
  }
  /* A name and a long "added by" stop sharing a row before they collide —
     the roster gets read on a phone as often as a laptop. */
  @media (max-width: 540px) {
    .host-roster-row { flex-wrap: wrap; }
    .host-roster-since { margin-left: 44px; text-align: left; width: 100%; }
  }

  .host-picker-note {
    margin: 10px 0 0;
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--ink-soft);
  }

  .host-section-head {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 24px 0 18px;
  }
  .host-section:first-of-type .host-section-head { margin-top: 4px; }

  .host-section-h {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
    color: var(--slate);
    margin: 0;
    flex-shrink: 0;
  }
  .host-section-rule {
    display: block;
    flex: 1;
    height: 1px;
    background: rgba(0, 0, 0, 0.20);
  }
  .host-section-note {
    margin: -4px 0 12px;
    color: var(--ink-faint);
    font-size: 14px;
    line-height: 1.5;
  }
  .host-edit-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 28px;
    padding: 0 14px;
    border-radius: 999px;
    border: 1px solid var(--ink);
    background: var(--ink);
    color: var(--paper);
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease;
  }
  .host-edit-btn:hover {
    background: var(--ink-hover);
    border-color: var(--ink-hover);
    color: var(--paper);
    text-decoration: none;
  }
  .host-edit-btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    line-height: 1;
    margin-right: 2px;
    letter-spacing: 0;
    text-transform: none;
  }

  /* Empty-state block for a host section (Asks, Resources). Soft
     ruled-paper band with a small explanatory line and a paper-toned
     "Add the first…" affordance. Sits where the list would be. */
  .host-empty {
    background: rgba(0, 0, 0, 0.04);
    border: 1px dashed var(--hover-edge);
    border-radius: 6px;
    padding: 22px 26px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
  }
  .host-empty-body {
    margin: 0;
    font-family: var(--sans);
    font-size: 14px;
    line-height: 1.55;
    color: var(--ink-soft);
  }

  /* ── Host view: light-grey board, sharp full-width white cards
     (manage-style, confined within the folder chrome). A subtle step off the
     guest view's white paper. Scoped to .host-shell. ─────────────────── */
  /* Board is a light grey, almost white — just distinct enough from the guest
     paper. The tray stays true black (#000) behind it. Trim the board's big
     side padding so the white cards fill it nearly edge to edge. */
  .host-shell .stay-board { background: var(--desk); padding-left: 16px; padding-right: 16px; }
  .host-shell .stay-board-content { padding-left: 0; padding-right: 0; }
  /* Banner sits on the backing board (the dark tray) as a stable top strip,
     above the board — independent of the content width below, so the toggle
     never shifts. The tray stacks: banner, then board. */
  .stay-shell .stay-board-tray { display: flex; flex-direction: column; }
  .stay-shell .stay-board-tray > .host-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin: 0 0 12px;
    padding: 14px 18px;
    /* Mode-independent: the host band is a black strip in both modes. */
    background: #000;
    color: #f0f0f0;
    box-shadow: none;
  }

  /* Headers, edit/add buttons, and tabs keep their default dark-on-light
     styling — they read fine on the light-grey board. */

  /* Content cards — sharp corners, full bleed; white with a soft shadow. */
  .host-shell .host-card {
    background: var(--paper);
    border-radius: 0;
    padding: 26px 30px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10);
  }
  .host-shell .host-section { padding: 0; margin-bottom: 16px; }
  .host-shell .host-section:last-child { margin-bottom: 0; }
  .host-shell .host-section-head { margin: 0 0 12px; }
  .host-shell .host-section:first-of-type .host-section-head { margin-top: 0; }
  /* Welcome letter renders flat inside its card (no nested frame). */
  .host-shell .host-welcome-letter { background: transparent; border: none; box-shadow: none; padding: 0; }
  /* Visibility toggle now lives inside the Basic information card — set it off
     from the identity above with a hairline. */
  .host-card-visibility { margin: 20px 0 0; padding-top: 18px; border-top: 1px solid var(--paper-edge); }

  /* Lists fill their card flush — no framed box inside the card. */
  .host-shell .host-todos,
  .host-shell .host-files {
    background: transparent;
    border: none;
    box-shadow: none;
    border-radius: 0;
    padding: 0;
    margin: 0;
  }
  /* Empty sections: the whole card goes a deeper grey (no inner dashed box) so
     it stays distinct from the light board. */
  .host-shell .host-card:has(.host-empty) {
    background: var(--paper-warm-2);
    box-shadow: none;
  }
  .host-shell .host-empty {
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 0;
  }

  /* Data tabs (Tasks / Invites / Lodgings): white card panels on the light board. */
  .host-shell .tasks-table-wrap,
  .host-shell .manage-table-wrap,
  .host-shell .lodging-timeline {
    background: var(--paper);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10);
  }
  .host-shell .manage-requests {
    background: var(--paper);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.10);
    padding: 6px 20px;
  }
  .host-shell .invite-result { background: var(--paper); border-color: var(--paper-edge); border-radius: 0; }
  /* The lodging timeline's label column was flush to the card edge — inset it. */
  .host-shell .lodging-timeline { padding-left: 22px; }

  /* Identity block — kill the prep-identity bottom margin so the
     description doesn't have a giant gap below it. The blurb fills
     the parent width and sits flush with the section's bottom. */
  .host-section .prep-identity { margin-bottom: 0; }
  .host-identity-blurb {
    margin: 0;
    color: var(--ink);
    font-size: 14px;
    line-height: 1.6;
  }

  /* ── Welcome letter — calm rich-text preview on warm paper. ──── */
  .host-welcome-letter {
    background-color: var(--paper-warm, #f6f1e6);
    background-image: var(--paper-texture);
    background-repeat: repeat;
    background-size: 480px auto;
    padding: 28px 32px 22px;
    border-radius: 4px;
    border: 1px solid var(--paper-edge);
    box-shadow: var(--shadow-paper);
    font-family: var(--sans);
    font-size: 15px;
    line-height: 1.75;
    color: var(--ink);
  }
  /* Trix stores blocks as <div>, not <p>. Apply paragraph spacing to
     both so the preview and the in-modal editor render with the same
     breathing room. */
  .host-welcome-letter p,
  .host-welcome-letter > div { margin: 0 0 22px; }
  .host-welcome-letter p:last-child,
  .host-welcome-letter > div:last-child { margin-bottom: 0; }
  .host-welcome-letter strong { font-weight: var(--weight-semibold); }
  .host-welcome-letter em { font-style: normal; }
  .host-welcome-letter ul, .host-welcome-letter ol { margin: 0 0 22px 1.2em; }
  .host-welcome-fixed {
    color: var(--ink);
    font-style: normal;
  }
  .host-welcome-fixed em { color: var(--ink-faint); font-style: normal; }

  /* Welcome-letter editor: flat layout — no outer card. Divider above,
     plain salutation + signature, the Trix editor itself carries the
     only border (set on trix-editor.host-trix at the bottom of file). */
  .host-welcome-divider {
    border: none;
    border-top: 1px solid var(--paper-edge);
    margin: 18px 0 22px;
  }
  .host-welcome-modal {
    background: transparent;
    border: none;
    padding: 0;
  }
  .host-welcome-modal .host-welcome-fixed {
    margin: 0 0 12px;
    font-family: var(--sans);
    font-size: 15px;
    line-height: 1.7;
    color: var(--ink);
  }
  .host-welcome-modal .host-welcome-fixed:last-child {
    margin: 18px 0 0;
  }

  /* "To <email>" line in the composer header — shows the recipient clearly. */
  .nudge-to-line { font-size: 13px; color: var(--ink-faint); margin-top: 8px; }
  .nudge-to-line strong { color: var(--ink); font-weight: var(--weight-semibold); }

  /* Nudge CTA field — styled as the actual ink-stamp button (inverted: ink
     fill, paper text, centered) so editing the label previews the real
     button the recipient sees. */
  .nudge-cta-input {
    /* The whole black block is sized to the character budget (~24 chars +
       padding) so it reads as a limited-width text field, not a full-width
       button. Full width on mobile (below). */
    width: min(100%, calc(24ch + 56px));
    border: none;
    color: var(--paper);
    font-family: var(--sans);
    font-size: 14px;
    font-weight: var(--weight-semibold);
    letter-spacing: 0.02em;
    text-align: left;
    padding: 14px 28px 18px;
    border-radius: var(--radius-xs);
    box-sizing: border-box;
    /* White underline sits INSIDE the block — inset from every edge — so it's
       clearly visible. Drawn as a background line because Safari/WebKit won't
       render text-decoration on <input> text. */
    background-color: var(--ink);
    background-image: linear-gradient(#fff, #fff);
    background-repeat: no-repeat;
    background-size: calc(100% - 56px) 2px;
    background-position: 28px calc(100% - 12px);
  }
  @media (max-width: 768px) {
    .nudge-cta-input { width: 100%; }
  }
  .nudge-cta-input:focus { outline: 2px solid var(--ink); outline-offset: 2px; }
  .nudge-cta-input::selection { background: rgba(255, 255, 255, 0.30); }

  /* ── Trix editor — see the un-layered overrides at the bottom of
     this file. Trix's CDN CSS is unlayered, so any rule placed inside
     @layer components loses to it regardless of specificity. */

  /* ── Todos band — keep the prep ruled-paper aesthetic. ──────── */
  .host-todos {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
  }
  .host-todo .prep-todo-row { cursor: pointer; }

  /* ── Fleet — drivers / riders / unanswered lists ─────────────── */
  .fleet-list { list-style: none; margin: 0; padding: 0; }
  .fleet-row { padding: 8px 4px; }
  .fleet-row + .fleet-row { border-top: 1px solid rgba(0, 0, 0, 0.07); }

  /* ── Per-ask visibility — title links to edit, toggle hides it ── */
  .host-todo {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
  }
  /* A pay ask guests can't complete — full-width line under the row. */
  .host-todo-warning {
    flex: 1 1 100%;
    margin: 0 0 4px 28px;
    font-size: 12.5px;
    color: var(--pip-flag-fg);
  }
  .host-todo-warning a { color: inherit; text-decoration: underline; }
  .host-todo-edit {
    flex: 1;
    min-width: 0;
  }
  .host-todo-toggle {
    flex-shrink: 0;
    margin: 0;
    padding-right: 2px;
  }
  .host-todo-flag {
    flex-shrink: 0;
    font-family: var(--display);
    font-size: 11px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-faint);
    border: 1px solid var(--hover-edge);
    border-radius: 999px;
    padding: 1px 7px;
  }
  .host-todo--hidden .prep-todo-title,
  .host-todo--hidden .prep-todo-due { color: var(--ink-faint); }
  /* Past its due date with guests still open — same ochre as everywhere. */
  .prep-todo-due--slipping { color: var(--slipping); font-weight: var(--weight-semibold); }
  .host-todo--hidden .prep-todo-check { opacity: 0.45; }
  /* Quiet door to the responses rail — reads as an aside, not a button. */
  .host-todo-responses {
    flex-shrink: 0;
    font-size: 12.5px;
    color: var(--ink-faint);
    text-decoration: underline;
    text-underline-offset: 2px;
  }
  .host-todo-responses:hover { color: var(--ink); }

  /* ── The responses rail — one ask, every confirmed guest ─────── */
  .ask-responses-title { margin: 2px 0 2px; }
  .ask-responses-count { font-size: 13px; margin: 0 0 12px; }
  .ask-responses-list { list-style: none; margin: 0; padding: 0; }
  .ask-responses-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 2px;
  }
  .ask-responses-row + .ask-responses-row { border-top: 1px solid var(--hover-edge); }
  .ask-responses-name { flex-shrink: 0; font-weight: var(--weight-semibold); }
  .ask-responses-state { min-width: 0; text-align: right; overflow-wrap: anywhere; }
  .ask-responses-state a { color: inherit; }
  .ask-responses-notyet { color: var(--ink-faint); font-style: italic; }
  .ask-responses-check { color: var(--ink); }
  /* Where an answer came from, when it wasn't typed here. (Aug 5) */
  .ask-responses-source {
    display: block;
    font-size: 11.5px;
    color: var(--ink-faint);
    font-style: italic;
    margin-top: 1px;
  }
  .ask-responses-thumb img {
    max-width: 96px;
    max-height: 96px;
    border-radius: var(--radius-sm);
    display: block;
    margin-left: auto;
  }

  /* ── Visibility settings — inline toggle list ───────────────── */
  .host-toggle-list {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .host-toggle-row {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 10px 0;
  }
  .host-toggle-row + .host-toggle-row {
    border-top: 1px solid rgba(0, 0, 0, 0.06);
  }

  /* Pair the ON/OFF pill with the switch on the right of a setup row. */
  .g-row-control {
    display: inline-flex;
    align-items: center;
    gap: 10px;
  }
  .toggle-state {
    font-family: var(--display);
    font-size: 11px;
    font-weight: var(--weight-bold);
    letter-spacing: 0.06em;
    line-height: 1;
    padding: 3px 7px;
    border-radius: 999px;
    color: var(--ink-faint);
    border: 1px solid var(--hover-edge);
    background: transparent;
  }
  .toggle-state--on {
    color: var(--paper);
    background: var(--ink);
    border-color: var(--ink);
  }
  .g-row-control .host-toggle { margin-top: 0; }

  .host-toggle {
    position: relative;
    display: inline-block;
    flex-shrink: 0;
    margin-top: 2px;
    cursor: pointer;
  }
  .host-toggle input {
    position: absolute;
    opacity: 0;
    inset: 0;
    width: 100%;
    height: 100%;
    cursor: pointer;
    margin: 0;
  }
  .host-toggle-track {
    display: block;
    width: 36px;
    height: 20px;
    background: rgba(0, 0, 0, 0.18);
    border-radius: 999px;
    transition: background 0.15s ease;
    position: relative;
  }
  .host-toggle-track::after {
    content: '';
    position: absolute;
    top: 2px;
    left: 2px;
    width: 16px;
    height: 16px;
    background: var(--paper);
    border-radius: 50%;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
    transition: transform 0.18s ease;
  }
  .host-toggle input:checked + .host-toggle-track {
    background: var(--ink);
  }
  .host-toggle input:checked + .host-toggle-track::after {
    transform: translateX(16px);
  }
  .host-toggle input:focus-visible + .host-toggle-track {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
  }

  .host-toggle-body { flex: 1; min-width: 0; }
  .host-toggle-title {
    font-size: 14px;
    color: var(--ink);
    font-weight: var(--weight-semibold);
    line-height: 1.3;
  }
  .host-toggle-help {
    font-size: 12.5px;
    color: var(--ink-soft);
    line-height: 1.5;
    margin-top: 2px;
  }

  /* ── Task editor — clean, solid surface (matches the guest task card).
     No ruled paper, no pink margin; just a white sheet filling the card. */
  .ask-modal-paper {
    background: var(--paper);
    margin: -64px -60px;
    padding: 44px 56px;
    min-height: 360px;
  }
  .ask-modal-h {
    font-size: 24px;
    margin: 8px 0 0;
    line-height: 1.15;
  }
  .ask-modal-help {
    color: var(--ink-soft);
    font-size: 13px;
    margin-top: 6px;
    line-height: 1.5;
  }
  .ask-modal-todo {
    margin: 22px 0 6px;
  }
  .ask-modal-todo .prep-todo-row {
    align-items: center;
    gap: 12px;
    padding: 6px 0;
  }
  .ask-modal-title {
    flex: 1;
    border: none;
    background: transparent;
    font-family: inherit;
    font-size: 15px;
    color: var(--ink);
    padding: 4px 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.16);
  }
  .ask-modal-title:focus { outline: none; border-bottom-color: var(--ink); }
  .ask-modal-title::placeholder { color: var(--ink-faint); font-style: normal; }
  .ask-modal-due {
    flex: 0 0 140px;
    border: none;
    background: transparent;
    font-family: var(--display);
    font-style: normal;
    font-size: 14px;
    color: var(--ink);
    padding: 4px 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.16);
  }
  .ask-modal-due:focus { outline: none; border-bottom-color: var(--ink); }
  .ask-modal-field { margin-top: 22px; padding-left: 30px; }
  .ask-modal-label {
    display: block;
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-faint);
    font-weight: var(--weight-bold);
    margin-bottom: 8px;
  }
  .ask-modal-textarea {
    width: 100%;
    box-sizing: border-box;
    border: 1px solid rgba(0, 0, 0, 0.16);
    background: var(--paper);
    font-family: inherit;
    font-size: 14px;
    line-height: 1.6;
    color: var(--ink);
    resize: vertical;
    min-height: 96px;
    padding: 12px 14px;
  }
  .ask-modal-textarea:focus { outline: none; border-color: var(--ink); }
  .ask-modal-actions {
    margin-top: 28px;
    padding-top: 18px;
    border-top: 1px solid rgba(0, 0, 0, 0.10);
  }

  /* ── Kind (type) picker — segmented control ─────────────────── */
  .ask-modal-kind-row { padding-left: 30px; }

  /* Type picker — a responsive grid of labeled cards (Jul 30). Replaces the
     single non-wrapping tab row that overflowed the 420px rail. auto-fit means
     it lays out as many columns as fit: 2 in the rail, more if it ever gets
     wider, 1 on a phone. Each card names the type and says what it does. */
  .ask-kind-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 8px;
    max-width: 100%;
  }
  .ask-kind-card {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
    border: 1px solid var(--hover-edge);
    border-radius: var(--radius-xs, 6px);
    cursor: pointer;
    user-select: none;
    transition: border-color 0.12s, background 0.12s;
  }
  .ask-kind-card input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    pointer-events: none;
  }
  .ask-kind-card-name {
    font-family: var(--sans);
    font-size: 12.5px;
    font-weight: var(--weight-bold);
    letter-spacing: 0.03em;
    color: var(--ink);
    line-height: 1.2;
  }
  .ask-kind-card-help {
    font-size: 11.5px;
    color: var(--ink-soft);
    line-height: 1.25;
  }
  .ask-kind-card:hover { border-color: var(--ink-faint); background: var(--hover-wash); }
  .ask-kind-card:has(input:checked) {
    border-color: var(--ink);
    background: var(--ink);
  }
  .ask-kind-card:has(input:checked) .ask-kind-card-name { color: var(--paper); }
  .ask-kind-card:has(input:checked) .ask-kind-card-help { color: color-mix(in srgb, var(--paper) 78%, transparent); }
  .ask-kind-card:has(input:focus-visible) { outline: 2px solid var(--ink); outline-offset: 2px; }
  /* Amount sub-field — indented under the picker */
  .ask-amount-row {
    margin-top: 16px;
  }
  .ask-amount-input-wrap {
    display: flex;
    align-items: baseline;
    gap: 4px;
    border-bottom: 1px dashed var(--hover-edge);
    width: 120px;
    padding-bottom: 4px;
  }
  .ask-amount-symbol {
    font-size: 15px;
    color: var(--ink-faint);
  }
  .ask-modal-amount {
    border: none;
    background: transparent;
    font-family: inherit;
    font-size: 15px;
    color: var(--ink);
    width: 100%;
    padding: 0;
    -moz-appearance: textfield;
  }
  .ask-modal-amount::-webkit-inner-spin-button,
  .ask-modal-amount::-webkit-outer-spin-button { -webkit-appearance: none; }
  .ask-modal-amount:focus { outline: none; }
  .ask-amount-hint { margin-top: 8px; }

  /* ── Modal-internal action row ──────────────────────────────── */
  .host-modal-actions {
    margin-top: 28px;
    padding-top: 18px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
  }

  /* ── People / Logistics tab intros ──────────────────────────── */
  .host-section-title {
    font-family: var(--display);
    font-style: normal;
    font-weight: var(--weight-semibold);
    font-size: 28px;
    line-height: 1.15;
    color: var(--ink);
    margin: 4px 0 6px;
  }
  /* NEEDS A PLAN (Manasa, Sep 1). Warm clay, the same register the app uses
     for the things that went wrong — never a saturated alarm. It sits above
     the rollup and has to read as "look here first" without shouting, because
     most weeks it is absent entirely and a host should notice the week it
     is not. */
  .unmet {
    margin: 0 0 22px;
    padding: 14px 16px 12px;
    /* --pink is #FF00C7, a brand accent rather than the "warm clay" the alert
       styles describe. As a full box it shouted; g-alert gets away with it
       because it only ever wears it on one 3px edge. Same restraint here —
       this band is present most weeks, and a thing that shouts every week
       stops being read. */
    border: 1px solid var(--paper-edge);
    border-left: 3px solid var(--pink);
    border-radius: var(--radius-md);
    background: var(--paper);
  }
  .unmet-h {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 10px;
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-weight: var(--weight-semibold);
    color: var(--ink-soft);
  }
  .unmet-mark { color: var(--pink); font-size: 13px; }
  .unmet-list { list-style: none; margin: 0; padding: 0; }
  .unmet-row {
    display: grid;
    gap: 1px 12px;
    padding: 8px 0;
    border-top: 1px solid var(--paper-edge);
  }
  .unmet-row:first-child { border-top: 0; padding-top: 0; }
  .unmet-name {
    font-weight: var(--weight-semibold);
    font-size: 15px;
    color: var(--ink);
    text-decoration: none;
  }
  .unmet-name:hover { text-decoration: underline; text-underline-offset: 2px; }
  .unmet-when { font-size: 13.5px; color: var(--ink-soft); }
  .unmet-why  { font-size: 13px; color: var(--ink-faint); }
  @media (min-width: 640px) {
    .unmet-row { grid-template-columns: minmax(140px, 1fr) minmax(200px, 1.2fr) 1.4fr; align-items: baseline; }
  }

  .host-section-rollup {
    font-size: 13px;
    color: var(--ink-soft);
    margin: 0 0 24px;
  }

  /* Invites header: title on the left, the open/invite-only status on the right. */
  .invites-headerline {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
  }

  /* Open ⇄ invite-only status — a segmented pill. The active side is a filled
     label; the inactive side is a button_to that switches the status. */
  .status-toggle {
    display: inline-flex;
    align-items: stretch;
    padding: 3px;
    background: rgba(0, 0, 0, 0.05);
    border-radius: 999px;
  }
  /* Open ⇄ invite-only is now an on/off switch (.host-toggle) + a label. */
  .status-toggle-form {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin: 0;
  }
  .status-toggle-label {
    font-family: var(--sans);
    font-size: 13px;
    color: var(--ink-soft);
  }
  /* Invite-mode box — the open/invite-only switch + explanation + (when open)
     the share link, in one .invite-result panel. */
  .invite-mode { margin-top: 16px; }
  .invite-mode-form {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    margin: 0;
  }
  .invite-mode-body { flex: 1; min-width: 0; }
  .invite-mode-title {
    font-family: var(--sans);
    font-size: 15px;
    font-weight: var(--weight-semibold);
    color: var(--ink);
  }
  .invite-mode-help {
    font-size: 13px;
    color: var(--ink-soft);
    line-height: 1.5;
    margin-top: 3px;
  }
  .invite-mode-link {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid rgba(0, 0, 0, 0.1);
  }

  /* Roster header — title left, the confirmed/declined count top-right. */
  .roster-headerline {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    margin-top: 28px;
    margin-bottom: 10px;
  }
  .roster-headerline .roster-count { margin: 0; }
  .status-toggle-seg {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
    padding: 7px 16px;
    border-radius: 999px;
    line-height: 1;
    display: inline-flex;
    align-items: center;
  }
  .status-toggle-seg--active {
    background: var(--ink);
    color: var(--paper);
  }
  .status-toggle-seg--btn {
    background: transparent;
    border: none;
    color: var(--ink-soft);
    cursor: pointer;
    transition: color 0.12s ease, background 0.12s ease;
  }
  .status-toggle-seg--btn:hover {
    color: var(--ink);
    background: rgba(0, 0, 0, 0.05);
  }

  /* Coming-soon placeholder for unfinished folder tabs (e.g. Fleet). */
  .host-coming-soon {
    margin: 24px 0 0;
    padding: 32px 24px;
    background: rgba(0, 0, 0, 0.03);
    border: 1px dashed var(--hover-edge);
    border-radius: var(--radius-sm, 6px);
    text-align: center;
    font-size: 14px;
    color: var(--ink-soft);
    font-style: normal;
  }

  /* ── Person detail modal ────────────────────────────────────── */
  .person-modal-head {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 28px;
  }
  .person-modal-avatar {
    flex-shrink: 0;
  }
  .person-modal-id { flex: 1; min-width: 0; }
  .person-modal-name {
    font-family: var(--display);
    font-style: normal;
    font-weight: var(--weight-semibold);
    font-size: 26px;
    line-height: 1.15;
    margin: 0;
    color: var(--ink);
  }
  .person-modal-meta {
    font-size: 13px;
    color: var(--ink-soft);
    margin-top: 4px;
  }

  .person-modal-section {
    padding: 22px 0;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
  }
  .person-modal-section:first-of-type { border-top: none; padding-top: 0; }

  .person-modal-h {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
    color: var(--slate);
    margin: 0 0 12px;
  }
  .person-modal-h-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
  }
  .person-modal-h-row .person-modal-h { margin-bottom: 0; }

  .person-modal-dl {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 8px 16px;
    margin: 0;
  }
  .person-modal-dl > div {
    display: contents;
  }
  .person-modal-dl dt {
    font-size: 12px;
    color: var(--ink-faint);
    letter-spacing: 0.04em;
  }
  .person-modal-dl dd {
    margin: 0;
    font-size: 14px;
    color: var(--ink);
  }
  .person-modal-note { font-size: 14px; color: var(--ink-soft); }
  .person-modal-email {
    color: var(--ink);
    text-decoration: none;
    border-bottom: 1px solid var(--hover-edge);
    padding-bottom: 1px;
  }
  .person-modal-email:hover { border-bottom-color: var(--ink); color: var(--ink); }

  .person-modal-travel {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
  }
  .person-modal-travel-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 12px 14px;
    background: rgba(0, 0, 0, 0.035);
    border-radius: 4px;
    font-size: 13px;
    color: var(--ink);
  }
  .person-modal-travel-tag { align-self: flex-start; }

  .person-modal-lodging {
    margin: 0;
    font-family: var(--display);
    font-size: 18px;
    color: var(--ink);
  }
  .person-modal-lodging em { color: var(--ink-faint); font-style: normal; }

  .person-modal-asks {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .person-modal-ask {
    display: grid;
    grid-template-columns: 22px 1fr auto;
    align-items: center;
    gap: 10px;
    padding: 10px 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
    font-size: 14px;
  }
  .person-modal-ask:last-child { border-bottom: none; }
  .person-modal-ask-check {
    width: 18px;
    height: 18px;
    border-radius: 3px;
    border: 1.5px solid var(--ink-soft);
    background: var(--paper-warm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    color: var(--ink);
  }
  .person-modal-ask.done .person-modal-ask-check {
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
  }
  .person-modal-ask-title { color: var(--ink); }
  .person-modal-ask.done .person-modal-ask-title {
    text-decoration: line-through;
    color: var(--ink-soft);
  }
  .person-modal-ask-state {
    font-size: 12px;
    color: var(--ink-soft);
    text-align: right;
  }

  /* PINNED. This nav has existed since June and nobody has seen it: it sat
     at the foot of a card that scrolls, so on anyone with a full profile it
     was below the fold, and Brenda spent two months closing the rail and
     going back to the list. Same trade the ✕ at the top of this same card
     already made. (Brenda, Aug 20) */
  .person-modal-nav {
    position: sticky;
    bottom: 0;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 16px;
    align-items: center;
    margin-top: 28px;
    padding: 14px 0 12px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
    background: var(--paper);
    /* The card has its own bottom padding; bleed over it so nothing shows
       through underneath the bar as the card scrolls. */
    box-shadow: 0 12px 0 var(--paper);
  }
  .person-modal-nav-end {
    font-size: 12px;
    color: var(--ink-faint);
  }
  .person-modal-nav-link {
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-decoration: none;
    color: var(--ink);
    padding: 8px 0;
  }
  .person-modal-nav-link--right {
    align-items: flex-end;
    text-align: right;
  }
  .person-modal-nav-link:hover { text-decoration: none; color: var(--ink); }
  .person-modal-nav-link:hover .person-modal-nav-name { text-decoration: underline; }
  .person-modal-nav-dir {
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-faint);
    font-weight: var(--weight-bold);
  }
  .person-modal-nav-name {
    font-family: var(--display);
    font-style: normal;
    font-size: 15px;
    color: var(--ink);
  }

  /* "Add people" block at the bottom of the People tab — the trigger
     button plus the (initially hidden) invite-people panel. */
  .people-add-new {
    margin-top: 28px;
    padding-top: 20px;
    border-top: 1px dashed var(--hover-edge);
  }

  /* Last cell of a People-tab row: "Copy" link + "Uninvite" red text link. */
  .people-link-cell {
    display: inline-flex;
    align-items: center;
    gap: 16px;
    justify-content: flex-end;
  }

  /* ── Readiness tab ──────────────────────────────────────────── */
  .tasks-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 18px;
    margin-bottom: 18px;
  }
  .tasks-head .host-section-rollup { margin-bottom: 0; }

  /* The readiness matrix is wider than the paper it sits on — at 1440px
     it showed 2 of 6 asks with 357px hidden and no scrollbar (the
     overlay kind only appears while scrolling), so a host read the
     gathering as having two asks. Same problem on the roster. Keep the
     scrollbar on screen, and say which way there's more. (Aug 5) */
  .tasks-table-wrap,
  .manage-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: var(--hover-edge) transparent;
  }
  .tasks-table-wrap::-webkit-scrollbar,
  .manage-table-wrap::-webkit-scrollbar { height: 8px; -webkit-appearance: none; }
  .tasks-table-wrap::-webkit-scrollbar-thumb,
  .manage-table-wrap::-webkit-scrollbar-thumb {
    background: var(--hover-edge);
    border-radius: 999px;
  }
  .tasks-table th,
  .tasks-table td { vertical-align: middle; }
  .tasks-table td.task-cell {
    padding-top: 14px;
    padding-bottom: 14px;
  }

  /* Person column stays pinned while the to-do columns scroll — same
     position:sticky pattern as the lodgings timeline's name column. It needs
     an opaque background to paint over whatever scrolls beneath it. */
  /* Whole row is clickable (row-link controller) — pointer cursor across it. */
  .tasks-table tbody tr { cursor: pointer; }
  .tasks-table .tasks-sticky-col {
    position: sticky;
    left: 0;
    z-index: 5;
    background: var(--paper);
    border-right: 1px solid var(--paper-edge);
    width: 252px;
  }
  /* The pinned column must match the row's hover/ready tint AND stay opaque,
     or the scrolled to-do cells show through it. Layer the translucent tint
     over a solid paper backing so the result is an opaque grey. */
  .tasks-table tr:hover td.tasks-sticky-col {
    background: linear-gradient(rgba(0, 0, 0, 0.02), rgba(0, 0, 0, 0.02)), var(--paper);
  }
  .tasks-table tr.tasks-row--ready td.tasks-sticky-col {
    background: linear-gradient(rgba(0, 0, 0, 0.02), rgba(0, 0, 0, 0.02)), var(--paper);
  }
  .tasks-person-link {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
  }
  .tasks-person-body { flex: 1; min-width: 0; }
  .tasks-person-attrs {
    font-size: 12px;
    color: var(--ink-soft);
    margin-top: 3px;
  }
  /* "Nudged 2d ago" pill above the end-column button — a visible reminder so
     the host doesn't re-poke blindly. */
  /* Plain caption stacked under the Nudge button — no label/pill background. */
  .tasks-nudged-note {
    display: block;
    font-size: 11px;
    color: var(--ink-soft);
    margin-top: 6px;
    white-space: nowrap;
  }

  /* Far-right Nudge shortcut — compact outlined pill, only on not-ready rows. */
  .tasks-nudge-th { width: 1%; }
  .tasks-nudge-cell { text-align: center; white-space: nowrap; padding: 0 12px; }
  .tasks-nudge-link {
    display: inline-block;
    padding: 5px 13px;
    border: 1px solid var(--ink);
    border-radius: var(--radius-xs);
    font-family: var(--sans);
    font-size: 12px;
    font-weight: var(--weight-semibold);
    letter-spacing: 0.02em;
    color: var(--ink);
    text-decoration: none;
    transition: background 0.15s ease, color 0.15s ease;
  }
  .tasks-nudge-link:hover { background: var(--ink); color: var(--paper); text-decoration: none; }
  /* Already nudged today — same pill shape, greyed and inert. */
  .tasks-nudge-link--off,
  .tasks-nudge-link--off:hover {
    border-color: var(--paper-edge);
    color: var(--ink-faint);
    background: transparent;
    cursor: default;
  }

  /* Nudge column stays pinned to the right edge on desktop so it never scrolls
     out of reach once several to-do columns are present. Mirrors the sticky
     person column on the left — same opaque-paper backing, layered with the
     row hover/ready tints so scrolled cells don't bleed through. Mobile keeps
     the plain horizontal scroll (no pinning). */
  @media (min-width: 769px) {
    .tasks-table .tasks-nudge-th,
    .tasks-table .tasks-nudge-cell {
      position: sticky;
      right: 0;
      z-index: 5;
      background: var(--paper);
      border-left: 1px solid var(--paper-edge);
    }
    .tasks-table tr:hover td.tasks-nudge-cell {
      background: linear-gradient(rgba(0, 0, 0, 0.02), rgba(0, 0, 0, 0.02)), var(--paper);
    }
    .tasks-table tr.tasks-row--ready td.tasks-nudge-cell {
      background: linear-gradient(rgba(0, 0, 0, 0.02), rgba(0, 0, 0, 0.02)), var(--paper);
    }
  }

  /* Right side of the task modal footer — stacks the "nudged 2d ago" note on
     its own line above the action buttons (Nudge / Close) instead of inline. */
  .task-modal-actions-right {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
  }
  /* "Nudged 2d ago" — small pill above the modal's Nudge button. */
  .task-nudged-note {
    font-size: 12px;
    font-weight: var(--weight-semibold);
    color: var(--ink-soft);
    background: var(--paper-warm-2);
    padding: 3px 10px;
    border-radius: 999px;
    white-space: nowrap;
  }
  /* Explicit affordance that the row opens a detail modal. */
  .tasks-person-chevron {
    flex-shrink: 0;
    color: var(--ink-faint);
    font-size: 20px;
    line-height: 1;
    transition: transform .12s ease, color .12s ease;
  }
  .tasks-person-link:hover .tasks-person-chevron {
    color: var(--ink);
    transform: translateX(2px);
  }
  .tasks-row--ready .manage-row-name { color: var(--ink-soft); }

  /* Status columns are narrow and centred — each holds a single check. */
  .tasks-check-th { text-align: center; }
  .task-cell--check { text-align: center; width: 92px; }

  /* To-do's form a shaded column group, set apart from Profile/Travel by a
     faint wash and a divider on the leading edge. Headers are small and
     sentence-case (the prompts are sentences); full text shows on hover. */
  .tasks-todos-grouphead {
    text-align: center;
    background: rgba(0, 0, 0, 0.05);
    border-left: 1px solid var(--paper-edge);
  }
  /* To-do headers are sentence text, not labels — set them in the display
     face, regular case (the th.tasks-todo-col specificity beats the base
     manage-table th uppercase rule). Full prompt shows on hover. */
  .tasks-table th.tasks-todo-col {
    min-width: 88px;
    max-width: 124px;
    font-family: var(--display);
    font-style: normal;
    font-size: 11px;
    font-weight: var(--weight-normal);
    letter-spacing: 0;
    text-transform: none;
    line-height: 1.3;
    white-space: normal;
    vertical-align: top;
    color: var(--ink-soft);
  }
  .tasks-table th.tasks-todo-col,
  .tasks-table td.tasks-todo-cell { background: rgba(0, 0, 0, 0.03); }
  .tasks-table th.tasks-todo-col:first-of-type,
  .tasks-table td.tasks-todo-cell:first-of-type {
    border-left: 1px solid var(--paper-edge);
  }

  /* Completion mark — a soft circle (gentler than a square) that fills with
     a ✓ when done, echoing the participant checklist's checkbox. */
  .task-check {
    display: inline-block;
    width: 18px;
    height: 18px;
    border: 1.5px solid var(--ink-faint);
    border-radius: 50%;
    background: var(--paper);
    line-height: 16px;
    text-align: center;
    font-size: 11px;
    color: var(--ink);
    vertical-align: middle;
  }
  .task-check--on {
    border-color: var(--ink);
    background: var(--ink);
    color: var(--paper);
  }
  .task-check--on::before { content: "✓"; }
  /* Not needed — a host said this one doesn't apply. A dashed ring with a
     dash inside, deliberately unlike the filled ✓ a guest earns: the row
     is resolved, but nobody did it. (Neal, Aug 5) */
  .task-check--na {
    border-style: dashed;
    border-color: var(--ink-faint);
    color: var(--ink-faint);
    background: transparent;
  }
  .task-check--na::before { content: "–"; }
  /* Open past its due date — the ochre ring says "this one's slipping". */
  .task-check--slipping {
    border-color: var(--slipping);
    border-width: 2px;
  }

  /* Travel — journey strip: each end is that leg's mode glyph (plane/car) with
     an arrow between and the leg's date beneath. Laid out as a 3-column grid so
     each date sits under its glyph. Empty legs show a hollow dot + muted dash. */
  .task-travel-cell { width: 152px; text-align: center; }
  /* Fixed column tracks so the strip is the same width — and the dots line up
     across rows — in every state (complete, partial, empty). */
  .travel-strip {
    display: inline-grid;
    grid-template-columns: 50px 20px 50px;
    justify-items: center;
    align-items: center;
    gap: 3px 0;
  }
  .travel-glyph {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 18px;
    color: var(--ink-soft);
  }
  .travel-mode-icon { width: 18px; height: 18px; display: block; }
  .travel-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    border: 1.5px solid var(--ink-faint);
    background: var(--paper);
  }
  .travel-arrow { color: var(--ink-faint); font-size: 13px; line-height: 1; }
  .travel-date {
    font-size: 11px;
    color: var(--ink-soft);
    white-space: nowrap;
  }
  .travel-date.is-muted { color: var(--ink-faint); }

  /* ── Task-status modal ──────────────────────────────────────── */
  .task-modal-head {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 16px;
    margin-bottom: 4px;
  }
  .task-modal-name {
    font-family: var(--display);
    font-style: normal;
    font-weight: var(--weight-semibold);
    font-size: 26px;
    line-height: 1.15;
    margin: 0;
    color: var(--ink);
  }
  .task-modal-attrs {
    font-size: 13px;
    color: var(--ink-soft);
    margin-top: 4px;
  }
  .task-modal-meta {
    font-size: 12px;
    color: var(--ink-faint);
    margin-top: 2px;
  }

  /* Basics (Profile + Travel) read as a labelled summary, deliberately unlike
     the checkbox to-do list below so they don't look like more to-do's. */
  .task-basics {
    padding: 14px 0 4px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
    margin-top: 8px;
  }
  .task-basic {
    display: grid;
    grid-template-columns: 92px 1fr;
    gap: 14px;
    padding: 9px 2px;
    font-size: 14px;
    line-height: 1.5;
  }
  .task-basic + .task-basic { border-top: 1px solid rgba(0, 0, 0, 0.05); }
  .task-basic-label {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
    color: var(--ink-faint);
    padding-top: 3px;
  }
  .task-basic-body { color: var(--ink-soft); }
  .task-basic-leg { display: flex; gap: 10px; align-items: flex-start; }
  .task-basic-leg + .task-basic-leg { margin-top: 8px; }
  /* Full per-leg travel detail in the readiness modal. */
  .task-leg { flex: 1; min-width: 0; }
  .task-leg-line { color: var(--ink); }
  .task-leg-sub { font-size: 13px; color: var(--ink-soft); margin-top: 2px; }
  .task-leg-flight {
    font-size: 13px;
    color: var(--ink-soft);
    margin-top: 2px;
    white-space: pre-line; /* keep the itinerary's own line breaks */
  }
  .task-basic-leg-label {
    min-width: 78px;
    color: var(--ink-faint);
  }

  .task-modal-group {
    padding: 16px 0;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
  }
  .task-modal-h {
    font-family: var(--sans);
    font-size: 11px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    font-weight: var(--weight-bold);
    color: var(--slate);
    margin: 0 0 12px;
  }
  /* Warm orange-red (the lodging-full --warning hue), softer than the rust. */
  .task-modal-h--needed { color: var(--ink); }

  /* Only short, discrete markers ("not set", a due date) are labels — a chip
     with a soft background. Anything sentence-length (a needs list, a note) is
     plain text in the same orange-red, never a chip: chips on full sentences
     read as too much, especially when a profile is still empty. */
  .task-tag {
    display: inline-block;
    padding: 2px 9px;
    border-radius: var(--radius-md);
    font-size: 12px;
    line-height: 1.45;
    font-weight: var(--weight-semibold);
  }
  /* Missing / unanswered items read as light-red tags. */
  .task-tag--alert { background: rgba(204, 68, 68, 0.10); color: var(--required); }
  .task-alert { color: var(--required); }
  /* A due date is a gentle reminder, not a problem — amber, not the alert red. */
  .task-tag--due { background: rgba(160, 109, 36, 0.10); color: var(--due); }
  /* Wrappers that lay out a row of alert tags (profile gaps, travel gaps). */
  .task-tags, .task-leg-tags { display: flex; flex-wrap: wrap; gap: 6px; }
  .task-leg-tags { margin-top: 4px; }
  .task-leg-tags:empty { display: none; }

  /* Modal to-do's are the participant checklist, shown host-side: a checkbox,
     the item, and (when done) the submitted note on its own line beneath. */
  .task-checklist {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .task-checklist-item {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 12px;
    padding: 8px 2px;
    font-size: 14px;
    line-height: 1.45;
  }
  .task-checklist-item .task-check {
    flex-shrink: 0;
    position: relative;
    top: 3px;
  }
  .task-checklist-label {
    color: var(--ink);
    font-weight: var(--weight-medium);
  }
  .task-checklist-item.is-done .task-checklist-label {
    color: var(--ink-faint);
    text-decoration: line-through;
  }
  /* Not needed reads as retired, not as achieved — dimmed, but no strike:
     nobody did this one, and the row shouldn't imply they did. */
  .task-checklist-item.is-not-needed .task-checklist-label {
    color: var(--ink-faint);
  }
  /* Who closed the row, which of the two they meant, and their note. The
     note is host-only — it never renders on the guest's own pages. */
  .task-checklist-closed {
    flex-basis: 100%;
    margin: 3px 0 0 30px;
    color: var(--ink-faint);
    font-size: 12.5px;
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
  }
  .task-checklist-closed em { font-style: italic; }
  .task-checklist-reopen { font-size: 12.5px; padding: 0; }
  /* The ⋯ only earns its place on a row that can still be closed, and it
     sits at the end of the line rather than in the flow of the label. */
  .task-checklist-more { margin-left: auto; }
  /* The submitted answer — prominent (it's the content the host wants to read),
     not the muted aside it used to be. */
  .task-checklist-note {
    flex-basis: 100%;
    margin: 5px 0 0 30px;
    color: var(--ink);
    font-size: 15px;
    font-weight: var(--weight-medium);
    line-height: 1.5;
  }
  /* Setting the nights a stay covers, from the person rail. Sits under the
     read-only travel lines because it answers a different question: not "how
     are they getting here" but "which nights is this cabin theirs". */
  .person-modal-dates { margin-top: 14px; }
  .person-modal-dates-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 4px;
  }
  .person-modal-dates-row .input { flex: 1 1 130px; min-width: 130px; }
  .person-modal-dates-to { color: var(--ink-faint); font-size: 13px; }

  /* The thread on one row. Lines up under the label with the note and the
     closure line, because it's the same kind of thing: something said
     about this row rather than the row itself. (Neal, Aug 6) */
  .task-checklist-thread {
    flex-basis: 100%;
    margin: 6px 0 0 30px;
  }
  /* Quiet at rest. Most rows will never be discussed, and 7 asks × 19
     guests of shouting "Comment" would bury the checklist it sits in. A
     row with words in it says how many, in the normal label size. Not
     hidden-until-hover: there is no hover on a phone. */
  .task-checklist-thread > summary {
    font-size: 12.5px;
    color: var(--ink-faint);
    cursor: pointer;
  }
  .task-checklist-thread[open] > summary { color: var(--ink-soft); }
  .task-checklist-thread .ann-comments { margin-top: 6px; }
  /* "Paid $X" on a completed payment task. */
  .task-checklist-paid { color: var(--paid); font-weight: var(--weight-semibold); }
  .task-checklist-due { margin-left: auto; }
  /* Small type chip (Pay / Upload / Question / Confirm) so the host can scan
     what each task is at a glance. */
  .task-type-tag {
    font-family: var(--sans);
    font-size: 10px;
    font-weight: var(--weight-semibold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-soft);
    background: rgba(0, 0, 0, 0.05);
    padding: 2px 7px;
    border-radius: 999px;
  }
  /* A question that isn't being asked any more, on the row of someone who
     answered it while it was. Outlined rather than filled: it names a state
     of the ask, not a kind of work. (Neal, Aug 6) */
  .task-type-tag--retired {
    background: none;
    border: 1px solid var(--paper-edge);
    color: var(--ink-faint);
  }
  /* The row itself sits back — it's history, not something anyone owes. */
  .task-checklist-item.is-retired .task-checklist-label { color: var(--ink-soft); }
  /* Link to a guest's uploaded file (opens inline in a new tab). */
  .task-checklist-file {
    font-size: 13px;
    color: var(--ink-soft);
    text-decoration: underline;
    text-underline-offset: 2px;
  }
  .task-checklist-file:hover { color: var(--ink); }
  /* Thumbnail preview of an image upload (host review). Own line under the
     task; click opens full size in a new tab. */
  .task-checklist-thumb { flex-basis: 100%; margin: 6px 0 0 30px; }
  .task-checklist-thumb img {
    display: block; max-width: 140px; max-height: 140px; object-fit: cover;
    border: 1px solid var(--hover-edge);
  }
  /* Smaller thumb in the full person modal's checklist. */
  .person-modal-thumb img {
    display: block; max-width: 96px; max-height: 96px; object-fit: cover;
    border: 1px solid var(--hover-edge);
  }
  .task-modal-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-top: 18px;
    margin-top: 8px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
  }

  .host-foot {
    margin-top: 36px;
    padding-top: 20px;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
    display: flex;
    justify-content: flex-end;
    gap: 12px;
  }
  .host-foot-note {
    font-size: 12px;
    color: var(--ink-soft);
    margin: 8px 0 0;
  }

  /* ── Logistics (placeholder; deferred for now) ───────────────── */
  .host-logistics-section { margin-bottom: 36px; }
  .host-logistics-section:last-child { margin-bottom: 0; }
  .host-lodgings, .host-runs, .host-await-list { list-style: none; margin: 0; padding: 0; }
  .host-lodging-row {
    display: grid;
    grid-template-columns: 110px 60px 1fr auto;
    align-items: center;
    gap: 14px;
    padding: 12px 4px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    font-size: 14px;
  }
  .host-lodging-row:last-child { border-bottom: none; }
  .host-lodging-name { font-family: var(--display); font-weight: var(--weight-semibold); }
  .host-lodging-cap { font-size: 12px; color: var(--ink-soft); }
  .host-lodging-cap--full { color: var(--warning, #b54b1f); font-weight: var(--weight-semibold); }
  .host-lodging-occ { font-size: 13px; }
  .host-lodging-conflict { font-size: 12px; margin-top: 2px; font-style: normal; }
  .host-await { margin-top: 0; margin-bottom: 28px; padding: 16px 18px; background: rgba(0,0,0,0.035); border-radius: 6px; }
  .host-await-eyebrow {
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ink-faint);
    font-weight: var(--weight-bold);
    margin-bottom: 12px;
  }
  .host-await-table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .host-await-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
  }
  .host-await-table tr { border-bottom: 1px solid rgba(0,0,0,0.06); }
  .host-await-table tr:last-child { border-bottom: none; }
  .host-await-table td {
    padding: 10px 12px 10px 0;
    vertical-align: middle;
  }
  .host-await-avatar { width: 32px; padding-right: 12px; }
  .host-await-name { font-weight: var(--weight-semibold); white-space: nowrap; }
  .host-await-meta { font-size: 12px; color: var(--ink-soft); }
  .host-await-assign { width: 1%; white-space: nowrap; padding-right: 0; }
  .host-await-assign .lodging-assign-form {
    display: inline-flex;
    align-items: center;
    gap: 8px;
  }
  .host-await-assign .lodging-assign-select { min-width: 200px; }
  .host-run-row {
    display: grid;
    grid-template-columns: 130px 1fr auto;
    align-items: flex-start;
    gap: 16px;
    padding: 14px 4px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  }
  .host-run-row:last-child { border-bottom: none; }
  .host-run-when { font-family: var(--display); font-style: normal; font-size: 14px; }
  .host-run-route { font-size: 14px; }
  .host-run-meta { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
  .host-run-riders { font-size: 13px; color: var(--ink-soft); margin-top: 4px; }

  .folder-fold-hosts {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
    padding: 6px 0;
  }

  /* ── Mobile ──────────────────────────────────────────────────── */
  @media (max-width: 768px) {
    /* Specificity matches the desktop `.stay-board > .host-banner` rule
       so the mobile margin/padding actually win on small viewports —
       otherwise the band keeps the desktop -80px breakout and shoots
       past the paper edges. Flush header at the paper top. */
    .stay-board > .host-banner {
      flex-direction: column;
      align-items: flex-start;
      gap: 10px;
      margin: 0 -14px 20px;
      padding: 16px 14px;
    }
    .host-banner-text { font-size: 16px; }
    /* Drop the container pill on mobile so wrapping doesn't stretch a blob —
       each tab is its own chip (manage-style). The active one fills. */
    .host-tabs-wrap { margin-bottom: 22px; justify-content: flex-start; }
    /* Segmented bar scrolls left-to-right on phones instead of wrapping. */
    .host-tabs {
      flex-wrap: nowrap;
      overflow-x: auto;
      max-width: 100%;
      -webkit-overflow-scrolling: touch;
    }
    .host-tab { font-size: 10px; letter-spacing: 0.1em; padding: 9px 14px; }

    /* Banner wraps on mobile — title on top, the Host|Guest switch below. */
    .stay-shell .stay-board-tray > .host-banner {
      flex-direction: column;
      align-items: flex-start;
      gap: 12px;
    }
    .tasks-head {
      flex-direction: column;
      gap: 12px;
    }
    .task-checklist-item { flex-wrap: wrap; }
    .task-checklist-note { flex-basis: 100%; margin-left: 30px; }
    .host-lodging-row { grid-template-columns: 1fr auto; gap: 4px 12px; }
    .host-lodging-name { grid-column: 1; }
    .host-lodging-cap { grid-column: 2; text-align: right; }
    .host-lodging-occ { grid-column: 1 / -1; }
    .host-lodging-row > a { grid-column: 1 / -1; justify-self: end; }
    .host-run-row { grid-template-columns: 1fr auto; }
    .host-run-when { grid-column: 1 / -1; }

    /* Modal action rows — stack the buttons full-width so labels stay on
       a single line on phone widths. Primary lands on top, secondary
       underneath, matching the todo modal's pattern. */
    .host-modal-actions,
    .ask-modal-actions {
      flex-direction: column-reverse;
      align-items: stretch;
      gap: 10px;
    }
    .host-modal-actions > .btn,
    .host-modal-actions > .btn-paper,
    .host-modal-actions > .btn-paper--danger,
    .host-modal-actions > .logistics-save,
    .host-modal-actions > .logistics-save--outline,
    .ask-modal-actions > .btn,
    .ask-modal-actions > .btn-paper,
    .ask-modal-actions > .logistics-save,
    .ask-modal-actions > .logistics-save--outline {
      width: 100%;
      justify-content: center;
    }
  }
}

/* ── Trix overrides — UNLAYERED ─────────────────────────────────
   Trix's CDN stylesheet is unlayered, which wins over any rules
   inside @layer components regardless of specificity. These overrides
   sit outside the layer so they actually apply. */

/* Welcome letter preview: Trix stores blocks as <div> and its CDN
   `.trix-content * { margin: 0 }` rule (unlayered) zeroes their
   margins. Re-add paragraph spacing here, also unlayered, so it
   actually wins. */
.host-welcome-letter > p,
.host-welcome-letter > div { margin: 0 0 22px; }
.host-welcome-letter > p:last-child,
.host-welcome-letter > div:last-child { margin-bottom: 0; }
.host-welcome-letter ul,
.host-welcome-letter ol { margin: 0 0 22px 1.2em; padding-left: 0; }

/* Minimal toolbar — bare icons, no boxes, no dividers, no border.
   Reads as a quiet row of glyphs above the writing surface. */
trix-toolbar {
  background: transparent;
  margin: 0;
  padding: 0 0 8px;
  border: none;
}
trix-toolbar .trix-button-row {
  background: transparent;
  border: none;
  display: inline-flex;
  flex-wrap: nowrap;
  gap: 0;
  align-items: center;
}
trix-toolbar .trix-button-group {
  background: transparent;
  border: none;
  border-radius: 0;
  overflow: visible;
  margin: 0;
  padding: 0;
  display: inline-flex;
  align-items: center;
}
trix-toolbar .trix-button-group + .trix-button-group {
  margin-left: 10px;
}
trix-toolbar .trix-button,
trix-toolbar .trix-button-group .trix-button,
trix-toolbar .trix-button-group .trix-button + .trix-button {
  background: transparent;
  border: none;
  color: var(--ink-soft);
  height: 26px;
  width: 26px;
  padding: 0;
  margin: 0;
  border-radius: 3px;
  transition: background 0.12s ease, color 0.12s ease;
}
trix-toolbar .trix-button:disabled { opacity: 0.35; cursor: not-allowed; }
trix-toolbar .trix-button:hover:not(:disabled) {
  background: rgba(0, 0, 0, 0.05);
  color: var(--ink);
}
trix-toolbar .trix-button.trix-active {
  background: rgba(0, 0, 0, 0.10);
  color: var(--ink);
}
/* Hide groups we don't need in the welcome letter context. */
trix-toolbar .trix-button-group--file-tools,
trix-toolbar .trix-button-group--history-tools,
trix-toolbar .trix-button-group-spacer,
trix-toolbar .trix-button--icon-heading-1,
trix-toolbar .trix-button--icon-code,
trix-toolbar .trix-button--icon-decrease-nesting-level,
trix-toolbar .trix-button--icon-increase-nesting-level {
  display: none !important;
}

trix-editor.host-trix {
  min-height: 240px;
  background: var(--paper-warm, #f6f1e6);
  padding: 22px 26px;
  border: 1px solid var(--paper-edge);
  border-radius: 4px;
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.75;
  color: var(--ink);
}
trix-editor.host-trix:focus {
  outline: none;
  border-color: var(--ink);
}
/* Trix renders block content as <div>; give them air. */
trix-editor.host-trix > div + div { margin-top: 14px; }
trix-editor.host-trix h1 {
  font-family: var(--display);
  font-style: normal;
  font-size: 22px;
  margin: 14px 0;
  color: var(--ink);
}
trix-editor.host-trix blockquote {
  border-left: 2px solid var(--ink-faint);
  padding-left: 14px;
  margin: 0 0 14px;
  color: var(--ink-soft);
  font-style: normal;
}
trix-editor.host-trix ul,
trix-editor.host-trix ol { margin: 0 0 14px 1.4em; }
trix-editor.host-trix a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

@layer components {
  /* Hero-photo field in the basics editor. */
  .basics-hero-row { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
  .basics-hero-thumb { width: 88px; height: 56px; object-fit: cover; border-radius: var(--radius-sm); }
  .basics-hero-remove { font-size: 13px; color: var(--ink-soft); display: inline-flex; gap: 6px; align-items: center; }
  .basics-hero-input { font-size: 13px; color: var(--ink-soft); }
  /* Native file/datetime widgets dressed to match the rail. (Audit P1-19) */
  .basics-hero-input::file-selector-button,
  .folder-rail input[type="file"]::file-selector-button {
    font-family: var(--sans);
    font-size: 13px;
    font-weight: var(--weight-semibold);
    color: var(--ink);
    background: var(--paper);
    border: 1px solid var(--ink);
    border-radius: var(--radius-sm);
    padding: 6px 12px;
    margin-right: 10px;
    cursor: pointer;
  }
  .basics-hero-input::file-selector-button:hover,
  .folder-rail input[type="file"]::file-selector-button:hover { background: var(--hover-wash); }
  .folder-rail input[type="datetime-local"].nom-input,
  .folder-rail input[type="date"].nom-input {
    font-family: var(--sans);
    min-height: 38px;
  }
  .nom-hint { margin-top: 6px; font-size: 12px; color: var(--ink-faint); }
}

@layer components {
  /* The setup rows (D3, Law 3) — row grammar inside a host card. */
  .setup-rows { padding-top: 4px; padding-bottom: 4px; }
  .setup-rows .g-row { padding-left: 0; padding-right: 0; align-items: center; }
  .g-row-control { flex-shrink: 0; }
}

@layer components {
  .setup-matrix { margin-top: 10px; padding-top: 12px; border-top: 1px solid var(--paper-edge); }

  /* ── CLOSING A STRETCH OF DATES (Neal, Aug 25) ──────────────────────
     This form had no styles at all. It rendered as the last child of a
     .g-rows column, which meant the row above it kept its hairline and
     the form sat flush underneath — "a little sandwich with the line
     just above it". Three stacked date fields and a button with no
     margin under them.

     It is a composer, not a row: its own heading, its own space, and the
     three fields on one line where there is room for them. ───────── */
  /* No border of its own: the row above already ends in a hairline, and
     drawing a second one 22px below it put two lines across the card —
     the same sandwich, just further apart. The space IS the separation. */
  .blackout-form { padding-top: 26px; }
  .blackout-form-h {
    font-family: var(--display);
    font-size: 16px;
    font-weight: var(--weight-bold);
    color: var(--ink);
    margin: 0;
  }
  .blackout-form-note {
    font-size: 14px;
    line-height: 1.5;
    color: var(--ink-faint);
    margin: 2px 0 0;
  }
  .blackout-fields {
    display: flex;
    flex-wrap: wrap;
    gap: 14px 18px;
    margin-top: 16px;
  }
  /* The two dates want only as much room as a date needs; the reason
     takes whatever is left, and drops to its own full line first. */
  .blackout-field { flex: 0 1 150px; min-width: 140px; }
  .blackout-field--wide { flex: 1 1 240px; }
  .blackout-field .nom-input { width: 100%; }
  .blackout-submit { margin-top: 18px; }

  @media (max-width: 560px) {
    /* At phone width three fields on a line is two fields and a stub.
       One each, full width, which is also how every other form in the
       host shell behaves down here. */
    .blackout-field,
    .blackout-field--wide { flex: 1 1 100%; }
    .blackout-fields { gap: 14px; }
    .blackout-submit { width: 100%; }
  }
}

/* ── Happenings — the days taking shape. Day-grouped rows shared by
   the host tab and the guest prep board. ── */
@layer components {
  .prep-happenings { margin: 26px 0; }
  .hap-day { margin-top: 20px; }
  .hap-day:first-of-type { margin-top: 8px; }
  .hap-day-h {
    font-size: var(--cap-md);
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-cap);
    text-transform: uppercase;
    color: var(--ink-faint);
    margin-bottom: 6px;
  }
  .hap-rows { list-style: none; margin: 0; padding: 0; }
  .hap-row {
    display: flex;
    align-items: baseline;
    gap: 14px;
    padding: 10px 2px;
  }
  .hap-row + .hap-row { border-top: 1px solid var(--paper-edge); }
  .hap-when {
    flex: none;
    width: 76px;
    font-size: 12.5px;
    font-weight: var(--weight-semibold);
    color: var(--ink-soft);
    white-space: nowrap;
  }
  .hap-body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
  .hap-title { font-weight: var(--weight-semibold); color: var(--ink); font-size: 15px; }
  .hap-meta { color: var(--ink-faint); font-size: 13px; }
  .hap-empty { max-width: 480px; line-height: 1.5; }
  @media (max-width: 640px) {
    .hap-when { width: 64px; }
  }
}

/* ── Announcements — the board on the lodge wall. Rows borrow
   Basecamp's anatomy: face, bold title, quiet byline + em-dash
   excerpt as one paragraph, a comment badge riding right. ── */
@layer components {
  .ann-rows { list-style: none; margin: 4px 0 0; padding: 0; }
  .ann-row + .ann-row { border-top: 1px solid var(--paper-edge); }
  .ann-row-link {
    display: flex;
    align-items: flex-start;
    gap: 14px;
    padding: 18px 2px;
    text-decoration: none;
    color: inherit;
  }
  .ann-row-link:hover .ann-row-title { text-decoration: underline; }
  .ann-face { flex: none; }
  /* The board's faces run a touch larger than the 32px avatar-sm —
     Basecamp's row weight without a new avatar size class. */
  .ann-row-link .avatar-sm.ann-face { width: 40px; height: 40px; font-size: 13px; }
  .ann-row-body { min-width: 0; flex: 1; }
  .ann-row-title {
    font-family: var(--display);
    font-weight: var(--weight-bold);
    color: var(--ink);
    font-size: 18px;
    line-height: 1.25;
    letter-spacing: -0.005em;
  }
  .ann-row-line {
    margin: 4px 0 0;
    font-size: 14px;
    color: var(--ink-soft);
    line-height: 1.5;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .ann-byline { color: var(--ink-faint); }
  .ann-count {
    flex: none;
    align-self: center;
    min-width: 26px;
    height: 26px;
    padding: 0 7px;
    border-radius: 999px;
    border: 1px solid var(--ink-faint);
    color: var(--ink-soft);
    font-size: 12.5px;
    font-weight: var(--weight-semibold);
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* The full read — centered head, hairline, comfortable measure. */
  .ann-sheet { padding: 34px clamp(18px, 5vw, 56px) 30px; }
  .ann-back-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
  /* ── The message as a document (Basecamp's posture, Jul 16):
     left-aligned title, one quiet byline, generous body, a labeled
     Comments boundary, and a composer that waits its turn. ── */
  .ann-full { max-width: 680px; margin: 0 auto; }
  .ann-full-head { text-align: left; }
  .ann-full-title {
    font-family: var(--display);
    font-size: clamp(26px, 4vw, 34px);
    font-weight: var(--weight-bold);
    color: var(--ink);
    line-height: 1.15;
    letter-spacing: -0.005em;
    margin: 6px 0 10px;
  }
  .ann-full-byline {
    display: flex; align-items: center; gap: 9px;
    color: var(--ink-faint); font-size: 14px;
  }
  .ann-full-byline strong { color: var(--ink-soft); font-weight: var(--weight-semibold); }
  .ann-head-actions { margin-left: auto; }
  .ann-edit-link {
    font-size: 13px; font-weight: var(--weight-semibold);
    color: var(--ink-soft); text-decoration: none;
  }
  .ann-edit-link:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
  .ann-full-body { margin: 22px 0 0; font-size: 16.5px; line-height: 1.7; max-width: 65ch; }

  .ann-comments { margin: 34px 0 0; }
  .ann-comments-head {
    border-top: 1px solid var(--paper-edge);
    padding-top: 14px;
    margin-bottom: 4px;
  }
  .ann-comments-label {
    font-size: var(--cap-sm);
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-cap);
    text-transform: uppercase;
    color: var(--ink-faint);
  }
  .ann-comment { display: flex; gap: 12px; padding: 16px 0; }
  .ann-comment + .ann-comment { border-top: 1px solid var(--paper-edge); }

  /* ── THE ⋯ ON A COMMENT (Chad, Aug 25) ────────────────────────────
     Each comment now rides in its own turbo-frame so the editor can
     stand where the words were. Custom elements default to inline, and
     the frames broke the hairline the adjacent-sibling rule above drew
     between comments — both restated here. ─────────────────────── */
  turbo-frame.ann-comment-frame { display: block; }
  turbo-frame.ann-comment-frame + turbo-frame.ann-comment-frame .ann-comment {
    border-top: 1px solid var(--paper-edge);
  }

  /* The ⋯ itself reuses chat's menu wholesale — same button, same
     popup, same Stimulus. Only its place in the line is different: a
     comment's byline is baseline-aligned, chat's is not. */
  .ann-comment-actions { align-self: center; }
  .ann-comment-actions .chat-msg-menu-item { white-space: nowrap; }

  /* An open editor is not a composer waiting its turn — Save is the
     whole point of being here, so it does not hide until focus.

     And it must be FULL WIDTH. .ann-comment-form is a column flex with
     align-items: flex-start, which is right for a composer (the Save
     button should not stretch) and catastrophic for a field: staging
     rendered the editor one character wide, every letter on its own
     line. The row stretches; only the button row stays put. (Aug 25) */
  .ann-comment-form--edit { align-items: stretch; }
  .ann-comment-form--edit .ann-comment-field,
  .ann-comment-form--edit lexxy-editor { width: 100%; }
  .ann-comment-form--edit .ann-comment-submit { display: inline-flex; margin-left: 0; }
  .ann-comment-edit-actions { display: flex; gap: 12px; align-items: center; margin-top: 10px; }
  .ann-comment--editing .ann-comment-form { margin-top: 0; width: 100%; }
  .ann-comment-body { min-width: 0; flex: 1; }
  .ann-comment-meta { font-size: 14px; display: flex; gap: 8px; align-items: baseline; }
  .ann-comment-meta .ann-byline { font-size: 12px; }
  .ann-comment-words { font-size: 15px; line-height: 1.6; margin-top: 3px; }

  /* ── The in-place edit (Jul 16 night): the edit state mirrors the
     reading state — the field IS the title, the editor IS the body. ── */
  .ann-edit-actions { display: flex; justify-content: flex-start; gap: 10px; margin: 14px 0 4px; }
  .ann-title-input {
    width: 100%;
    font-family: var(--display);
    font-size: clamp(26px, 4vw, 34px);
    font-weight: var(--weight-bold);
    color: var(--ink);
    line-height: 1.15;
    background: transparent;
    border: 0;
    border-bottom: 2px solid var(--hover-edge);
    padding: 2px 0 6px;
    margin: 6px 0 10px;
    resize: none;
    overflow: hidden;
    field-sizing: content;
    min-height: 1.3em;
  }
  .ann-title-input:focus { outline: none; border-bottom-color: var(--ink-faint); }
  .ann-edit-body { margin-top: 18px; }
  .ann-full-title--editable { display: block; text-decoration: none; color: inherit; }
  a.ann-full-title { font-size: clamp(26px, 4vw, 34px); font-weight: var(--weight-bold); line-height: 1.15; margin: 6px 0 10px; color: var(--ink); }
  .ann-full-title--editable:hover { text-decoration: underline; text-underline-offset: 4px; text-decoration-color: var(--hover-edge); }
  .board-locked-note { font-size: 13.5px; }

  /* The composer: one avatar-and-line row until it's focused — then
     the toolbar and button step forward (Basecamp's move). */
  .ann-comment-form { margin-top: 16px; display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
  .ann-comment-compose { display: flex; gap: 12px; width: 100%; align-items: flex-start; }
  .ann-comment-compose > .avatar { flex: none; margin-top: 2px; }
  .ann-comment-field { flex: 1; min-width: 0; }
  .ann-comment-form lexxy-editor { width: 100%; }
  .ann-comment-submit { display: none; margin-left: 42px; }
  .ann-comment-form:focus-within .ann-comment-submit,
  .ann-comment-form:has(lexxy-editor:not(.lexxy-editor--empty)) .ann-comment-submit { display: inline-flex; }
  .ann-notify-note {
    margin: 14px 0 0;
    font-size: 12.5px;
    color: var(--ink-faint);
    line-height: 1.5;
  }

  /* The prep door — one quiet line to the board. */
  .ann-door {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-top: 12px;
    padding: 12px 16px;
    background: var(--paper);
    border: 1px solid var(--paper-edge);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: inherit;
  }
  .ann-door:hover { border-color: var(--ink-faint); text-decoration: none; }
  .ann-door-label {
    flex: none;
    font-size: var(--cap-sm);
    font-weight: var(--weight-bold);
    letter-spacing: var(--tracking-cap);
    text-transform: uppercase;
    color: var(--ink-faint);
  }
  .ann-door-latest {
    min-width: 0; flex: 1;
    font-size: 14px; font-weight: var(--weight-semibold); color: var(--ink);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .ann-door-count { flex: none; color: var(--ink-faint); font-size: 13px; }
}

/* The send moment on the People tab. The button is a gate now (Neal, Aug 3):
   pressing it opens a panel that names every recipient and what each gets,
   and only then offers the real send. Plain <details>, no JS. */
@layer components {
  .people-send-all { margin: 14px 0 4px; }
  .send-all-toggle { cursor: pointer; list-style: none; display: inline-block; }
  .send-all-toggle::-webkit-details-marker { display: none; }
  .send-all-toggle::marker { content: ""; }
  .send-all-panel {
    margin-top: 10px;
    padding: 14px 16px;
    max-width: 560px;
    border: 1px solid rgba(0, 0, 0, 0.10);
    border-radius: 8px;
  }
  .send-all-what {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--ink-soft);
    margin: 0 0 10px;
  }
  .send-all-names {
    margin: 0 0 14px;
    padding-left: 18px;
    font-size: 14px;
    color: var(--ink);
    columns: 2 160px;
    column-gap: 24px;
  }
  .send-all-names li { margin: 2px 0; break-inside: avoid; }
  .people-send-invite { display: inline; }
  .people-send-invite .btn-text { white-space: nowrap; }
  /* The invitation didn't arrive. Pink rather than a red alarm — this is a
     thing to fix, not a thing that has gone catastrophically wrong, and the
     button beside it is already the fix. */
  .people-invite-failed,
  .people-send-invite .people-invite-failed { color: var(--pink); font-weight: var(--weight-semibold); }
  .people-invite-failed:hover { color: var(--pink); text-decoration: underline; }
}

@layer components {
  /* The message bar's right end: Edit while reading, Never mind + Save
     while editing (BC's top-right placement, Jul 16). */
  .ann-bar-actions { display: inline-flex; align-items: center; gap: 14px; }
  .ann-bar-save { padding: 6px 18px; }
}

@layer components {
  /* ── Suggested carpools (Jul 17): the noticing, on the fleet tab. ── */
  .ride-suggestions { margin: 6px 0 22px; }
  .ride-suggestion {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    padding: 10px 14px;
    border: 1px dashed color-mix(in srgb, #a85f33 45%, transparent);
    border-radius: 8px;
    margin-top: 8px;
    font-size: 13.5px;
    color: var(--ink-soft);
  }
  .ride-suggestion strong { color: var(--ink); }
  .ride-suggestion-act {
    white-space: nowrap;
    font-weight: var(--weight-semibold);
    color: var(--ink-soft);
    text-decoration: none;
  }
  .ride-suggestion-act:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
}

@layer components {
  /* ── The matrix in a pocket — person cards at phone width, the table at
     desktop. Same VM rows, said in words. (Audit Hero D) ─────────────── */
  .tasks-cards { display: none; }
  @media (max-width: 640px) {
    .tasks-table-wrap { display: none; }
    .tasks-cards { display: grid; gap: 10px; }
  }
  .tasks-card {
    background: var(--paper);
    border: 1px solid var(--paper-edge);
    padding: 12px 14px;
  }
  .tasks-card--ready { opacity: 0.75; }
  .tasks-card-person {
    display: flex; align-items: center; gap: 10px;
    color: inherit; text-decoration: none;
  }
  .tasks-card-name { font-weight: var(--weight-bold); color: var(--ink); flex: 1; min-width: 0; }
  .tasks-card-count { font-size: 12px; color: var(--ink-faint); white-space: nowrap; }
  .tasks-card-missing {
    margin: 8px 0 0; font-size: 13px; line-height: 1.5; color: var(--ink-soft);
  }
  .tasks-card-missing--ready { color: var(--ink-faint); font-style: italic; }
  .tasks-card-slip { color: var(--slipping); font-weight: var(--weight-semibold); }
  .tasks-card-actions { margin-top: 8px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
}

@layer components {
  /* ── Lodgings in a pocket — the assignment queue at phone width; the
     timeline stays the desktop tool. ──────────────────────────────── */
  .lodgings-queue { display: none; }
  @media (max-width: 640px) {
    .host-shell .lodging-timeline { display: none; }
    .lodgings-queue { display: block; margin-top: 14px; }
  }
  .lodgings-queue-h {
    font-size: var(--cap-lg);
    letter-spacing: var(--tracking-cap-tight);
    text-transform: uppercase;
    font-weight: var(--weight-semibold);
    color: var(--ink-faint);
    margin: 0 0 10px;
  }
  .lodgings-queue-row {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    background: var(--paper);
    border: 1px solid var(--paper-edge);
    padding: 10px 12px;
    margin-bottom: 8px;
  }
  .lodgings-queue-id { flex: 1; min-width: 0; display: flex; flex-direction: column; }
  .lodgings-queue-name { font-weight: var(--weight-bold); color: var(--ink); }
  .lodgings-queue-dates { font-size: 12px; color: var(--ink-faint); }
  .lodgings-queue-pick { flex: 1 1 100%; min-height: 40px; }
  .lodgings-queue-go { flex: 1 1 100%; text-align: center; }
  .lodgings-queue-done { color: var(--ink-faint); font-style: italic; }
  .lodgings-queue-placed { margin-top: 12px; font-size: 13px; color: var(--ink-soft); }
  .lodgings-queue-placed ul { margin: 8px 0 0; padding-left: 18px; }
}

@layer components {
  /* Row overflow — the quiet home for a row's destructive action. */
  .row-more { position: relative; display: inline-block; }
  .row-more-trigger {
    cursor: pointer; list-style: none;
    letter-spacing: 0.1em; font-weight: var(--weight-bold);
    padding: 2px 8px;
  }
  .row-more-trigger::-webkit-details-marker { display: none; }
  .row-more[open] .row-more-trigger { color: var(--ink); }
  .row-more-menu {
    position: absolute; right: 0; top: calc(100% + 4px); z-index: 20;
    background: var(--paper);
    border: 1px solid var(--paper-edge);
    box-shadow: var(--shadow-card);
    padding: 8px 12px;
    white-space: nowrap;
  }
  /* A menu entry that has to explain itself — the two ways to close a row
     read as sentences, so this one wraps where the uninvite item doesn't.
     (Neal, Aug 5) */
  .row-more-item {
    display: block;
    padding: 7px 4px;
    color: var(--ink);
    font-size: 14px;
    white-space: normal;
    /* A max-width with no MIN-width let shrink-to-fit resolve against a
       33px trigger: the menu rendered 92px wide and broke "Mark it not
       needed" across seven lines. A menu that explains itself needs room
       to. (Aug 5) */
    min-width: 232px;
    max-width: 260px;
    text-decoration: none;
  }
  .row-more-item + .row-more-item { border-top: 1px solid var(--hover-edge); }
  .row-more-item:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }
  .row-more-item small {
    display: block;
    color: var(--ink-faint);
    font-size: 12px;
    line-height: 1.4;
    margin-top: 1px;
  }
}

@layer components {
  /* ── THE TRANSIT PLAN — the fleet tab's lead overview. Coverage reads in
     three registers: aboard is settled (soft ink), needs-a-ride borrows the
     slipping ochre, and an unanswered pickup fades back — a question, not
     an alarm. ── */
  .transit-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 28px; }
  @media (max-width: 640px) { .transit-cols { grid-template-columns: 1fr; } }
  .transit-col-h {
    font-size: 13px; letter-spacing: .04em; text-transform: uppercase;
    color: var(--ink); font-weight: var(--weight-semibold);
    margin: 0 0 10px; padding-bottom: 6px;
    border-bottom: 1px solid var(--paper-edge);
  }
  .transit-row { padding: 4px 0; }
  .transit-row-main { font-size: 14px; color: var(--ink-soft); }
  .transit-row-main b { color: var(--ink); font-weight: var(--weight-semibold); }
  .transit-cover { font-size: 13px; margin-top: 1px; }
  .transit-cover--aboard { color: var(--ink-soft); }
  .transit-cover--needs  { color: var(--slipping); font-weight: var(--weight-semibold); }
  .transit-cover--quiet  { color: var(--ink-faint); }
}


@layer components {
  /* ── THE HOST BOARD GOES EDGE TO EDGE ON A PHONE ──────────────────
     The backdrop behind the folder is the gathering's own photo, and it
     is deliberately the one piece of chrome a host can change (Aug 5).
     So it stays — my first read called it decorative noise and that was
     wrong; deleting it would delete a feature.

     What actually reads as unfinished is the 16px of it showing down each
     side of the board. At desk width that margin is a frame. At 390px it
     is two slivers of night sky beside a workbench, and it costs 32px of
     the narrowest screen the app has — which the roster, the responses
     table and the report all need more than the photo does.

     Full bleed below 600px. The backdrop still frames the board above and
     below, where it reads as intent. (Aug 11) */
  @media (max-width: 600px) {
    .host-shell .stay-board { padding-left: 0; padding-right: 0; }
  }
}

@layer components {
  /* ── THE SHUTTLE BOARD, DRAWN (Neal, Aug 11) ──────────────────────
     "Who rides with who, in what car... plain dead simple, elegant, and
     beautiful." A run is a vehicle with seats, so it is drawn as one:
     taken seats carry a face and a first name, free seats are outlines
     you can count at a glance. Same grammar the lodgings page uses for
     beds — people placed into containers with capacity. */
  .runs { display: flex; flex-direction: column; gap: 14px; }

  .run {
    background: var(--paper);
    border: 1px solid var(--paper-edge);
    border-radius: var(--radius, 14px);
    padding: 16px 18px 14px;
    box-shadow: var(--shadow-paper);
  }
  .run--locked { border-color: var(--ink-faint); }

  .run-head { margin-bottom: 12px; }
  .run-route {
    display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
    margin: 0; font-family: var(--display);
    font-size: 17px; font-weight: var(--weight-bold); color: var(--ink);
  }
  .run-arrow { color: var(--ink-faint); font-weight: 400; }
  .run-when {
    margin: 4px 0 0; color: var(--ink-faint); font-size: 13.5px;
    display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline;
  }
  .run-vehicle::before, .run-locked::before { content: "· "; }
  .run-locked { color: var(--ink-soft); font-weight: var(--weight-semibold); }

  /* An instruction the riders have been given. Marked with a rule down its
     left rather than a colour, because on a board of eight cards it should
     read as "this one has a note" and not as "this one is a problem". The
     edge is a paper-edge mix so it survives the dark ground; rgba black is
     invisible there. */
  .run-note {
    margin: 0 0 14px; padding: 2px 0 2px 12px;
    border-left: 2px solid color-mix(in srgb, var(--paper-edge) 70%, transparent);
    color: var(--ink-soft); font-size: 13.5px; line-height: 1.5;
  }

  /* The seats. A row that wraps — a fifteen-seat van should look like a lot
     of seats, because it is. */
  .slots {
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-wrap: wrap; gap: 14px 12px;
  }
  .slot {
    display: flex; flex-direction: column; align-items: center;
    gap: 4px; width: 56px; text-align: center;
  }
  .slot-face {
    width: 42px; height: 42px; border-radius: 999px;
    display: flex; align-items: center; justify-content: center;
    background: var(--hover-wash); color: var(--ink-soft);
    font-size: 13px; font-weight: var(--weight-bold);
    overflow: hidden; flex: none;
  }
  .slot-face img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .slot-name {
    font-size: 12px; color: var(--ink-soft); line-height: 1.2;
    max-width: 56px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .slot-role { font-size: 10.5px; letter-spacing: .04em; text-transform: uppercase; color: var(--ink-faint); }

  /* The driver reads first and reads differently — "who is driving" is a
     different question from "who is going". */
  .slot--lead .slot-face { box-shadow: 0 0 0 2px var(--ink); }

  /* A free seat is an outline. Countable without reading a number. */
  .slot--free .slot-face {
    background: transparent;
    border: 1.5px dashed var(--paper-edge);
  }
  .slot--free .slot-name { color: var(--ink-faint); opacity: .75; }

  .run-foot {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; margin-top: 14px; padding-top: 10px;
    border-top: 1px solid var(--hover-edge);
  }
  .run-count { font-size: 13px; color: var(--ink-soft); font-weight: var(--weight-semibold); }
  .run-change {
    font-size: 13px; font-weight: var(--weight-semibold); color: var(--ink);
    text-decoration: underline; text-underline-offset: 3px;
  }

  /* Nobody at the kerb is the good state, so this only exists when it isn't. */
  .run-waiting {
    margin-bottom: 16px; padding: 14px 16px;
    border: 1px dashed var(--warn, #d99a26); border-radius: var(--radius, 14px);
  }
  .run-waiting-h {
    margin: 0 0 10px; font-size: 13px; font-weight: var(--weight-bold);
    color: var(--ink);
  }
  .run-waiting-list {
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-wrap: wrap; gap: 14px 18px;
  }
  .run-waiting-person { display: flex; align-items: center; gap: 8px; }
  .run-waiting-name { font-size: 14px; font-weight: var(--weight-semibold); color: var(--ink); }
  .run-waiting-when { font-size: 12.5px; color: var(--ink-faint); }

  @media (max-width: 600px) {
    .run { padding: 14px 14px 12px; }
    .slots { gap: 12px 10px; }
    .slot { width: 52px; }
    .slot-face { width: 38px; height: 38px; }
  }
}

@layer components {
  /* ── ASKS GET THEIR OWN LINE ON A PHONE (Neal, Aug 11) ─────────────
     "Everything feels a little sandwiched... right now the information
     just barely fits in each space on the phone."

     The row is one flex line: checkbox, title, due date, Responses, the
     visibility toggle. At desk width that reads across in one glance. At
     390px the title is the only thing that can give, so it does — "Provide
     one memorable photo" broke into three lines of two words while "was due
     Jul 12" and a toggle sat beside it holding their full width.

     Two lines instead: the ask, then what is true about it. The title gets
     the whole measure, and the due date, the responses link and the toggle
     share the line beneath — which is also the line a thumb wants them on. */
  @media (max-width: 600px) {
    .host-shell .host-todo {
      flex-wrap: wrap;
      row-gap: 10px;
      padding-top: 14px;
      padding-bottom: 14px;
    }
    .host-shell .host-todo-edit { flex: 1 0 100%; }
    .host-shell .host-todo .prep-todo-row { flex-wrap: wrap; row-gap: 6px; }
    .host-shell .host-todo .prep-todo-title { flex: 1 1 auto; min-width: 0; }
    /* The due date drops under the title rather than shouldering it. */
    .host-shell .host-todo .prep-todo-due { flex: 1 0 100%; margin-left: 32px; }
    .host-shell .host-todo-responses { margin-left: 32px; }
    .host-shell .host-todo-toggle { margin-left: auto; }
  }

  /* ── ROOM BETWEEN THE SECTIONS ─────────────────────────────────────
     Basic information, Welcome letter, What guests need to do — three
     cards with 16px between them and 12px under each header, which reads
     as one continuous wall of text on a phone. A section is a change of
     subject and should look like one. (Aug 11) */
  @media (max-width: 600px) {
    .host-shell .host-section { margin-bottom: 28px; }
    .host-shell .host-section-head { margin: 0 0 16px; }
    .host-shell .host-card { padding-top: 16px; padding-bottom: 16px; }

    /* A section head is a title, a rule, and sometimes a long rollup —
       "10 arriving Sun · 0 covered · 12 need rides · 11 need rides home".
       On one flex line at 390px the rollup wraps to three lines BESIDE the
       title and the two collide. Stack them: the title, then the rule, then
       the count on its own line where it has room to be read. (Aug 11) */
    .host-shell .host-section-head { flex-wrap: wrap; row-gap: 6px; }
    .host-shell .host-section-head .host-section-rollup { flex: 1 0 100%; }
    .host-shell .host-section-rule { display: none; }
  }
}

@layer components {
  /* ── A PLACE IS A CONTAINER WITH SLOTS ─────────────────────────────
     Cabins here, vehicles on the travel board. Same idea, same component
     (.slots above), so a host learns it once and reads both. (Aug 11) */
  .places {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 12px;
    margin-top: 14px;
  }
  .place {
    background: var(--paper);
    border: 1px solid var(--paper-edge);
    border-radius: var(--radius, 14px);
    padding: 14px 16px 12px;
  }
  .place--full { border-color: var(--hover-edge); }
  .place-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 10px; margin-bottom: 10px;
  }
  .place-name {
    margin: 0; font-family: var(--display);
    font-size: 15px; font-weight: var(--weight-bold); color: var(--ink);
  }
  .place-count { margin: 0; font-size: 12.5px; color: var(--ink-faint); white-space: nowrap; }
  .place-empty { margin: 0; font-size: 13px; color: var(--ink-faint); font-style: italic; }

  /* A bed another booking holds is neither free nor a guest, and says so. */
  .slot--held .slot-face {
    background: transparent;
    border: 1.5px solid var(--hover-edge);
    color: var(--ink-faint);
  }
  .slot--held .slot-name { color: var(--ink-faint); }

  @media (max-width: 600px) {
    .places { grid-template-columns: 1fr; }
  }
}

@layer components {
  /* The waiting list is people, not slots — a face and a name and when they
     land, in a row. It borrowed .slot-face for the circle and nothing else,
     so give the row its own shape rather than leaving it to inherit one.
     (Aug 11 — and it shipped for ten minutes with a class that no longer
     existed, which rendered every photo at its natural size. A rename has to
     follow the markup into every file that used the old name.) */
  .run-waiting-person .slot-face { width: 34px; height: 34px; flex: none; }
  .run-waiting-person { min-width: 0; }
  .run-waiting-name { white-space: nowrap; }
}

@layer components {
  /* ── BOTH ENDS OF THE MATRIX STAY PUT ──────────────────────────────
     The responses table is a matrix: one column per published ask, and
     Corkins has nineteen. It is legitimately wider than any screen — the
     sweep measures 181px off the right edge at 1440px, which is not a
     phone problem, it is arithmetic.
     Person is already pinned left so a host never loses track of whose
     row they are reading. The action at the far right is the other thing
     they came for, and it was the first casualty of the scroll. Pin it
     too: the asks scroll between two fixed anchors, which is what a wide
     matrix wants. (Aug 11) */
  .tasks-table .tasks-nudge-cell,
  .tasks-table th:last-child {
    position: sticky;
    right: 0;
    z-index: 4;
    background: var(--paper);
    border-left: 1px solid var(--paper-edge);
  }
  /* Same opacity contract the left-hand pin already keeps, or the ask
     columns show through it on hover. */
  .tasks-table tr:hover td.tasks-nudge-cell {
    background: linear-gradient(rgba(0, 0, 0, 0.02), rgba(0, 0, 0, 0.02)), var(--paper);
  }

  /* Below the table's breakpoint the rows are cards and there is nothing
     to pin — sticky there would park the action mid-card. */
  @media (max-width: 900px) {
    .tasks-table .tasks-nudge-cell,
    .tasks-table th:last-child { position: static; border-left: 0; }
  }
}

  /* What somebody actually wrote about driving, under their name on the
     Travel tab. Only rendered when their words say more than the option
     they picked. (Aug 25) */
  .fleet-said {
    margin-top: 3px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--ink-soft);
    font-style: italic;
  }

  /* Headcount and what those people eat, under a happening on the host's
     board. Absent until somebody has answered — a bare "0 in" reads as
     nobody wants to come rather than nobody has been asked. (Aug 25) */
  .hap-count {
    display: block;
    margin-top: 3px;
    font-size: 13px;
    color: var(--ink-soft);
  }
