/* ============================================
   SESSION BOARD STYLES
   One-time appointments with guest access
   ============================================ */

/* ---- Session Badge ---- */

.session-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  border-radius: 10px;
  background: var(--primary-100, #dbeafe);
  color: var(--primary-700, #1d4ed8);
  white-space: nowrap;
}

.dark .session-badge {
  background: var(--primary-900, #1e3a5f);
  color: var(--primary-300, #93c5fd);
}

.session-badge i {
  font-size: 9px;
}

/* ---- Status Badges ---- */

.session-status-active {
  background: var(--success-100, #dcfce7);
  color: var(--success-700, #15803d);
}

.session-status-locked {
  background: var(--warning-100, #fef3c7);
  color: var(--warning-700, #a16207);
}

.session-status-archived {
  background: var(--surface-200, #e5e7eb);
  color: var(--text-tertiary, #9ca3af);
}

.session-status-cancelled {
  background: var(--danger-100, #fee2e2);
  color: var(--danger-700, #b91c1c);
}

.session-tbd-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  font-size: 11px;
  font-weight: 500;
  border-radius: 8px;
  background: var(--warning-100, #fef3c7);
  color: var(--warning-700, #a16207);
}

/* ---- Temporary Group Modal ---- */

/* Sizing lives here (not inline) so it can respond to viewport width:
   roomy 600px on desktop, full-bleed 95vw on small screens. */
.temp-group-modal .modal-content {
  max-width: 600px;
}

@media (max-width: 640px) {
  .temp-group-modal .modal-content {
    max-width: 95vw;
  }
}

/* "What's the time?" posture pills: 2x2 grid at full width so the four
   postures read as one decision with four equal shapes. Collapses to a
   single column on narrow viewports. */
#temp-group-posture-options {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  width: 100%;
}

#temp-group-posture-options .option-pill {
  width: 100%;
  /* Centered like every other pill row in the app (was flex-start/left, the
     lone outlier the user flagged). Labels are short enough to center cleanly. */
  justify-content: center;
  text-align: center;
}

@media (max-width: 480px) {
  #temp-group-posture-options {
    grid-template-columns: 1fr;
  }
}

/* ── Custom expiry picker (2026-07-04) ─────────────────────────────────────
   Revealed under the expiry chips only when "Custom" is chosen. */
.temp-expiry-custom {
  margin-top: 10px;
  padding: 12px;
  border: 1px solid var(--border-color, #e5e7eb);
  border-radius: 10px;
  background: var(--surface-2, #f8fafc);
}
.temp-expiry-custom[hidden] { display: none; }
.temp-expiry-custom-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}
.temp-expiry-custom-row:last-of-type { margin-bottom: 0; }
.temp-expiry-mode {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-color, #374151);
  min-width: 44px;
}
.temp-expiry-amount {
  width: 72px;
  padding: 6px 8px;
  border: 1px solid var(--border-color, #e5e7eb);
  border-radius: 8px;
  font-size: 0.9rem;
}
.temp-expiry-unit,
.temp-expiry-datetime {
  padding: 6px 8px;
  border: 1px solid var(--border-color, #e5e7eb);
  border-radius: 8px;
  font-size: 0.9rem;
  background: var(--white, #fff);
}
.temp-expiry-datetime { flex: 1; min-width: 160px; }
.temp-expiry-cap-hint {
  margin: 6px 0 0;
  font-size: 0.75rem;
  color: var(--text-muted, #9ca3af);
}
.temp-expiry-explain {
  margin: 8px 0 0;
  font-size: 0.78rem;
  color: var(--text-muted, #6b7280);
  display: flex;
  align-items: center;
  gap: 6px;
}
.temp-expiry-explain i { color: var(--accent-color, #14b8a6); }

body.dark-mode .temp-expiry-custom {
  background: rgba(255, 255, 255, 0.03);
  border-color: rgba(255, 255, 255, 0.12);
}

/* Warning when the host opts a shareable temp group into full event titles. */
.temp-open-titles-warning {
  margin: 8px 0 0;
  font-size: 0.78rem;
  color: #b45309;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.temp-open-titles-warning[hidden] { display: none; }
.temp-open-titles-warning i { color: #f59e0b; margin-top: 1px; }
body.dark-mode .temp-open-titles-warning { color: #fbbf24; }

/* ── "WHAT GUESTS CAN SEE" visibility pills (2026-06-26, user screenshot) ──────
   These three pills (Show availability / Show names only / Host only) used the
   base .create-board-options layout = three flex:1 pills crammed into ONE row.
   The FIRST pill also carries a .recommended-pill "Recommended" badge, so its
   content is the widest of the three — on a phone a third of the row can't hold
   "Show availability" + the badge, so the label clipped to "… now / ability", the
   fully-rounded pill collapsed into an oblong blob, and the badge spilled over
   the neighbouring pill (user: "these buttons need fixing"). Match the sibling
   posture/expiry groups: lay them out as a GRID of equal full-width shapes that
   collapses to a single column on a phone, so every label + the badge get a full
   row and never clip. */
#temp-participant-visibility {
  display: grid;
  /* minmax(0, …), NOT a bare 1fr (2026-08-24, owner: "alignment is odd").
     A bare `1fr` is `minmax(auto, 1fr)`, so a track can never shrink below its
     widest unbreakable content — the "Recommended" pill made card 1 render
     190px against its siblings' 169px and the three columns stopped lining
     up. minmax(0, 1fr) lets the tracks be genuinely equal and pushes the
     wrapping into the card, where it belongs. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  width: 100%;
  /* Equal heights already came free from grid; state it so a future card with
     a shorter body can't reintroduce a ragged bottom edge. */
  align-items: stretch;
}
#temp-participant-visibility .option-pill {
  width: 100%;
  /* Let a long label + the Recommended badge wrap to two lines inside the pill
     instead of clipping; the pill grows to fit rather than crushing its text. */
  flex-wrap: wrap;
  white-space: normal;
  text-align: center;
  /* A capsule that may wrap to two lines reads better with a softer radius than
     the full 9999px pill (which turns a 2-line box into an oval). */
  border-radius: var(--radius-lg, 12px);
}
@media (max-width: 640px) {
  /* Stack to a single full-width column on a phone so each option — especially
     the Recommended one — gets its own clean row. */
  #temp-participant-visibility {
    grid-template-columns: 1fr;
  }
}

/* ── MEETING-LENGTH duration chips (2026-07-12, user: "Custom button is
   misaligned on mobile") ──────────────────────────────────────────────────
   Same bug the visibility pills above already had: the base
   .create-board-options layout is six flex:1 pills crammed into ONE wrapping
   row. At phone width each pill is ~61px, too narrow for "Custom" (icon +
   word) and "Not set" (icon + two words), so the label overflows/wraps and the
   fully-rounded 9999px radius turns the clipped pill into a blob — the "Custom"
   chip visibly spilled its text past its right edge. Match the sibling
   visibility/expiry groups: lay the chips out as an even GRID of full-width
   shapes with a softer radius, collapsing to fewer columns on a phone so every
   label gets a full cell and never clips. */
#temp-group-duration-chips {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  width: 100%;
}
#temp-group-duration-chips .option-pill {
  width: 100%;
  /* Kill the flex:1-in-a-wrapping-row behaviour the base rule sets; inside a
     grid the cell already sizes the pill, and flex-basis:0 would fight it. */
  flex: none;
  min-width: 0;
  /* Centre the label and let a long one wrap to two lines inside the cell
     rather than clipping — the grid row grows to fit. */
  justify-content: center;
  text-align: center;
  white-space: normal;
  /* A cell that may hold two lines reads better with a soft radius than the
     full 9999px capsule (which ovals a 2-line box). Matches the visibility
     pills' radius. */
  border-radius: var(--radius-lg, 12px);
}
@media (max-width: 640px) {
  /* Two per row on a phone so "Not set" / "Custom" keep a full-width cell. */
  #temp-group-duration-chips {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* ── Option cards (2026-08-22 temp-group redesign) ───────────────────────────
   The create step used to present its choices as bare one-or-two-word pills
   ("Anyone / Request / Invite", "I've set it / Set, but flexible") whose meaning
   lived in a single shared hint line that only described the SELECTED option —
   so most choices were unexplained at any moment (user: "the options seem
   confusing perhaps make them cards with explanations like proposal").

   These mirror the add-choice modal's .add-choice-option shape (icon tile +
   title + description + optional feature list), which is the app's established
   pattern for "pick one of N, here's what each does". */
.temp-option-cards {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* CENTRED (2026-08-30, owner: "the titles are fine but the text should be
   centered"). The icon moves from a left gutter to sit ABOVE the copy, so the
   title, description and feature list all share the card's centre axis — text
   centred beside a left-hand icon reads as misaligned rather than centred. */
.temp-option-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 14px;
  background: var(--bg-secondary, #f8fafc);
  border: 2px solid transparent;
  border-radius: var(--radius-md, 10px);
  cursor: pointer;
  text-align: center;
  width: 100%;
  transition: background-color .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.temp-option-card:hover {
  background: var(--bg-hover, #f1f5f9);
  border-color: var(--border-color, #e2e8f0);
}
.temp-option-card:focus-visible {
  outline: 2px solid var(--primary-500, #14b8a6);
  outline-offset: 2px;
}
/* Selected state must be legible without relying on colour alone — the border
   plus the tinted icon tile carry it together. */
.temp-option-card.selected {
  border-color: var(--primary-500, #14b8a6);
  background: var(--primary-50, #f0fdfa);
}
body.dark-mode .temp-option-card {
  background: var(--slate-800, #1e293b);
}
body.dark-mode .temp-option-card:hover {
  background: var(--slate-700, #334155);
}
body.dark-mode .temp-option-card.selected {
  background: rgba(20, 184, 166, .12);
  border-color: var(--primary-500, #14b8a6);
}

/* ── Member picker chips (2026-08-24) ──────────────────────────────────
   "Start with people from this board" on the create step. Same selection
   language as .temp-option-card (teal border + tint, aria-pressed), sized
   as chips because a full explanation card per person would be noise. */
.temp-member-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.temp-member-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px 6px 6px;
  min-height: 36px; /* WCAG 2.5.8 with margin to spare */
  background: var(--bg-secondary, #f8fafc);
  border: 2px solid transparent;
  border-radius: 999px;
  cursor: pointer;
  transition: background-color .2s ease, border-color .2s ease;
}
.temp-member-chip:hover {
  background: var(--bg-hover, #f1f5f9);
  border-color: var(--border-color, #e2e8f0);
}
.temp-member-chip:focus-visible {
  outline: 2px solid var(--primary-500, #14b8a6);
  outline-offset: 2px;
}
.temp-member-chip.selected {
  border-color: var(--primary-500, #14b8a6);
  background: var(--primary-50, #f0fdfa);
}
.temp-member-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  /* Fallback only — the per-person gradient comes from the [data-color]
     rules below, keyed by memberAvatarColorIndex(). Was a flat --primary-500
     for EVERYONE, so three teammates rendered as three identical teal discs
     (2026-08-24, owner: "why no coloured attendees like the rest of the
     app"). */
  background: var(--primary-500, #14b8a6);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
}
/* Per-person avatar palette. Mirrors the Review Center's member-chip
   gradients (review-dashboard.js `_chipColors`) so one person is one colour
   across surfaces. Lives in CSS rather than JS because the palette ratchet
   (canonical-shading-guards.test.js) forbids new JS files carrying literal
   palette hexes — a palette duplicated into JS is a palette that drifts. */
.temp-member-avatar[data-color="0"] { background: linear-gradient(135deg, #14b8a6, #0d9488); }
.temp-member-avatar[data-color="1"] { background: linear-gradient(135deg, #6366f1, #4f46e5); }
.temp-member-avatar[data-color="2"] { background: linear-gradient(135deg, #f59e0b, #d97706); }
.temp-member-avatar[data-color="3"] { background: linear-gradient(135deg, #ec4899, #db2777); }
.temp-member-avatar[data-color="4"] { background: linear-gradient(135deg, #8b5cf6, #7c3aed); }
.temp-member-avatar[data-color="5"] { background: linear-gradient(135deg, #10b981, #059669); }
.temp-member-avatar[data-color="6"] { background: linear-gradient(135deg, #f97316, #ea580c); }
.temp-member-avatar[data-color="7"] { background: linear-gradient(135deg, #3b82f6, #2563eb); }
.temp-member-avatar[data-color="8"] { background: linear-gradient(135deg, #ef4444, #dc2626); }
.temp-member-avatar[data-color="9"] { background: linear-gradient(135deg, #84cc16, #65a30d); }
.temp-member-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary, #0f172a);
}
.temp-member-tz {
  font-size: 11px;
  color: var(--text-secondary, #64748b);
}
/* The check is the not-colour-alone half of the selected state.
   ⚠️ SCOPED TO THE CHIP (2026-08-24, caught by looking at the render, not the
   rule): a bare `.temp-member-check { display: none }` is a single-class
   selector, and Font Awesome's `.fa-solid { display: var(--fa-display,
   inline-block) }` has the SAME specificity and loads later — so the glyph
   showed on every chip, selected or not, and the check stopped meaning
   anything. Scoping to `.temp-member-chip .temp-member-check` wins on
   specificity without reaching for !important. */
.temp-member-chip .temp-member-check {
  display: none;
  font-size: 11px;
  color: var(--primary-600, #0d9488);
}
.temp-member-chip.selected .temp-member-check { display: inline-block; }
body.dark-mode .temp-member-chip {
  background: var(--slate-800, #1e293b);
}
body.dark-mode .temp-member-chip:hover {
  background: var(--slate-700, #334155);
}
body.dark-mode .temp-member-chip.selected {
  background: rgba(20, 184, 166, .12);
  border-color: var(--primary-500, #14b8a6);
}
body.dark-mode .temp-member-name { color: var(--slate-100, #f1f5f9); }
body.dark-mode .temp-member-tz { color: var(--slate-400, #94a3b8); }

/* Locked state (below Team): one honest sentence + the upgrade CTA. */
.temp-members-locked {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px 12px;
  background: var(--bg-secondary, #f8fafc);
  border: 1px dashed var(--border-color, #cbd5e1);
  border-radius: var(--radius-md, 10px);
  cursor: pointer;
  text-align: left;
  font-size: 13px;
  color: var(--text-secondary, #475569);
}
.temp-members-locked:focus-visible {
  outline: 2px solid var(--primary-500, #14b8a6);
  outline-offset: 2px;
}
.temp-members-upgrade-cta {
  margin-left: auto;
  flex-shrink: 0;
  font-weight: 600;
  color: var(--primary-600, #0d9488);
  white-space: nowrap;
}
body.dark-mode .temp-members-locked {
  background: var(--slate-800, #1e293b);
  border-color: var(--slate-600, #475569);
  color: var(--slate-300, #cbd5e1);
}
body.dark-mode .temp-members-upgrade-cta { color: var(--primary-400, #2dd4bf); }

.temp-option-card .option-icon {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md, 10px);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 17px;
  background: var(--bg-tertiary, #e2e8f0);
  color: var(--text-secondary, #64748b);
  transition: background-color .2s ease, color .2s ease;
}
.temp-option-card.selected .option-icon {
  background: linear-gradient(135deg, #14b8a6, #0d9488);
  color: #fff;
}
body.dark-mode .temp-option-card .option-icon {
  background: var(--slate-700, #334155);
  color: var(--slate-300, #cbd5e1);
}

.temp-option-card .option-content {
  flex: 1;
  min-width: 0;
  /* Full width now that the card is a COLUMN (2026-08-30): as a column flex
     child `flex:1` sizes the HEIGHT, so without this the block shrinks to its
     content and the centred text centres inside a narrower box than the card. */
  width: 100%;
  /* Column so the feature list can be pushed to the bottom: the three
     descriptions are legitimately 6/5/6 lines of copy, so without this the
     tick-lists float at three different heights even once the titles align
     (2026-08-24). margin-top:auto on the list does the work. */
  display: flex;
  flex-direction: column;
  height: 100%;
}
.temp-option-card .option-content .option-features {
  margin-top: auto;
  padding-top: 8px;
}
/* ALIGN THE THREE CARDS' BODY TEXT (2026-08-24, owner: "text alignment still
   seems off").
   In a three-up 169px column "Show availability" and "Show names only" wrap to
   two lines while "Host only" fits on one, so each card's description began at
   a different height — measured 441 / 419 / 402px, a 39px stagger across a row
   the eye reads as a table.
   Two parts:
     a) reserve two lines for every title, so a one-line title sits in a
        two-line box instead of pulling its card up;
     b) take the "Recommended" pill OUT of the title's flow — as a flex child
        it wrapped onto a THIRD line and pushed card 1 down 25px on its own
        (title height 64px vs the siblings' 39px). It now floats at the card's
        top-right, where it labels the card without occupying a text line. */
.temp-option-card .option-title {
  display: flex;
  align-items: flex-start;
  align-content: flex-start;
  /* Centred on the card axis (2026-08-30). The title is a flex row, so
     text-align on the card cannot move it — justify-content does. */
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  min-height: calc(2 * 1.3em);
  color: var(--text-primary, #1e293b);
  margin-bottom: 3px;
  /* Room for the absolutely-positioned pill so a long title never runs under it. */
  padding-right: 4px;
}
/* The pill sits on its own row ABOVE the title rather than inside the title's
   text flow. Absolute positioning collided with the label ("RECOMMENDED"
   printed over "Show availability"); a reserved row above keeps the three
   titles on one baseline AND keeps the badge legible. Non-recommended cards
   get the same reserved row so all three still align.
   2026-08-30: that reserved row moved from .option-content to the CARD. Once
   the icon centred at the top of the card, an 18px pad on the content block
   sat BELOW the icon and the centred pill printed over it; padding the card
   pushes the icon clear (measured 5px of daylight) while keeping the reserve
   uniform across all three cards. */
.temp-option-card { padding-top: 32px; }
.temp-option-card { position: relative; }
/* Re-anchored 2026-08-30: `left: 62px` was measured from the icon's old LEFT
   gutter. With the icon centred above the copy that offset is meaningless, so
   the pill centres on the card instead — still its own reserved row above the
   title, so the three titles keep one baseline. */
.temp-option-card .option-title .recommended-pill {
  position: absolute;
  top: 10px;
  /* Centred against the BORDER box, not the padding box: a percentage `left`
     resolves against the padding box, so with the card's 2px border `left:50%`
     lands 2px shy of the true visual centre. Insetting both edges and using
     margin:auto centres against the full box instead. */
  left: 0;
  right: 0;
  margin-inline: auto;
  width: fit-content;
}
/* Below the three-up breakpoint each card is full width, titles no longer
   wrap, and a reserved second line would just be a gap. */
@media (max-width: 640px) {
  .temp-option-card .option-title { min-height: 0; }
}
.temp-option-card .option-desc {
  display: block;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-secondary, #64748b);
}
/* ONE FEATURE PER LINE (2026-08-24). This was a wrapping flex ROW, which in a
   three-up 176px column let two items share a line and a three-word item wrap
   across three — the icons then floated mid-block and nothing lined up
   vertically. In a narrow card the list is a list: one item per row, icons in
   a fixed gutter so the text edges align down the card. */
.temp-option-card .option-features {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  /* Centred 2026-08-30: each row shrinks to its content and the stack centres,
     so the list sits on the card's axis instead of hugging the left edge. */
  align-items: center;
  gap: 5px;
}
/* Inline-flex, not grid: the old fixed 12px gutter was there to align labels
   down a LEFT edge. Centred, that gutter just shifts each label right of the
   axis by half the icon width, so the text reads off-centre even though the
   row's box measures centred. Letting icon+label flow as one inline group
   centres what the eye actually tracks — the text (2026-08-30). */
.temp-option-card .option-features li {
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  gap: 6px;
  /* A long label wraps within the card rather than overflowing it. */
  max-width: 100%;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-tertiary, #94a3b8);
}
/* Colour carries MEANING, not decoration (2026-08-24, owner: "everything is
   teal?"). Every feature icon used to be forced teal, so "Titles stay hidden"
   and "No calendar data shared" — privacy RESTRICTIONS — read as affirmative
   ticks identical to "Best for finding a time together". Teal is reserved for
   the check (a capability you gain); the restriction/limit glyphs take the
   muted body tone so the row reads as neutral fact, not benefit. */
.temp-option-card .option-features i {
  font-size: 10px;
  color: var(--text-tertiary, #94a3b8);
  /* The row is baseline-aligned inline-flex now, which already seats the glyph
     on the label's first line; `justify-self`/`margin-top` were grid-era
     corrections and no longer apply (2026-08-30). */
  flex-shrink: 0;
}
.temp-option-card .option-features i.fa-check {
  color: var(--primary-500, #14b8a6);
}
/* The "Recommended" chip sits inline with the title. */
.temp-option-card .recommended-pill {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--primary-100, #ccfbf1);
  color: var(--primary-700, #0f766e);
}
body.dark-mode .temp-option-card .recommended-pill {
  background: rgba(20, 184, 166, .2);
  color: var(--primary-300, #5eead4);
}

/* ── Two-pane create (2026-08-30) ───────────────────────────────────────────
   Pane 1 = the group (title, visibility, join, expiry, notes) and mirrors the
   permanent create modal. Pane 2 = when, on the group's own timeline.

   ⚠️ BOTH PANES STAY IN THE DOM -- never re-render them, because
   openTimeEditor() moves #temp-group-time-disclosure by node identity and
   every timeline listener is bound once from initCreateListeners.

   ⚠️ BUT pane 2 IS display:none when mountTimelinePicker() runs (it mounts
   synchronously from show(), before any navigation). TimeRangePicker.mount and
   SessionGuestCellGrid.render therefore measure a zero-size box. That is why
   goToPane(2) repaints the roster and re-syncs the duration on arrival --
   that repaint is load-bearing, not a nicety. If you ever make pane 2 active
   at mount, keep the repaint anyway; it is cheap and it is the only thing
   standing between a hidden mount and a zero-width drag bar. */
#temp-group-create-step {
  display: flex;
  flex-direction: column;
}
.temp-pane { display: none; }
.temp-pane.is-active { display: block; }
/* Pane 1's settings block sits AFTER the time panel in source order (moving
   320 lines of template literal would risk far more than it buys, and
   openTimeEditor depends on the time panel's node identity). Order pulls it
   back above so the host reads title -> what guests see -> who can join ->
   expiry -> notes, exactly as in the permanent modal. */
.temp-pane-details { order: -1; }
/* ⚠️ The rail must outrank the panes it labels. Default order is 0, so an
   order:-1 pane would render ABOVE it and the modal would open on a settings
   card with no "1 The group / 2 When" in sight. */
#temp-step-rail { order: -2; }

/* The step rail. Two dots, so pane 2 is never a surprise. */
.temp-step-rail {
  display: flex;
  gap: 18px;
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  font-size: 12.5px;
  color: var(--text-tertiary, #94a3b8);
}
.temp-step-dot { display: flex; align-items: center; gap: 7px; }
.temp-step-dot span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--surface-200, #e2e8f0);
  color: var(--text-secondary, #475569);
  font-size: 11px;
  font-weight: 700;
}
.temp-step-dot.is-current { color: var(--text-primary, #0f172a); font-weight: 600; }
.temp-step-dot.is-current span {
  background: var(--primary-500, #14b8a6);
  color: #fff;
}
body.dark-mode .temp-step-dot span {
  background: var(--slate-700, #334155);
  color: var(--slate-300, #cbd5e1);
}
body.dark-mode .temp-step-dot.is-current { color: var(--slate-100, #f1f5f9); }

/* Why Create is not available yet. Informational, not an error: the host has
   not done anything wrong, they simply have not answered the question yet. */
.temp-when-gate {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 10px;
}
.temp-when-gate[hidden] { display: none; }

/* ── "Set a time" panel — now lives on the SHARE step ────────────────────────
   Previously a collapsed <details> on the create step, which asked the host to
   decide a time before the group existed. It is hidden markup on the create
   step and is MOVED into #temp-group-time-mount after creation. */
.temp-time-panel {
  border: 1px solid var(--border-color, #e2e8f0);
  border-radius: 10px;
  padding: 12px 14px;
  margin-top: 12px;
}
body.dark-mode .temp-time-panel {
  border-color: var(--slate-700, #334155);
}
.temp-time-panel-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary, #1e293b);
  margin-bottom: 10px;
}
/* ⚠️ `display:flex` beats the `hidden` ATTRIBUTE — hidden is only a UA
   display:none rule, which any author display wins. Without this the head
   stayed visible on the create step and printed a second "When could this
   happen?" plus a raw ISO stamp above the timeline's own label. */
.temp-time-panel-head[hidden] {
  display: none;
}
.temp-time-panel-head > i {
  color: var(--primary-500, #14b8a6);
}
.temp-time-summary-value {
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--primary-600, #0d9488);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 45%;
}
body.dark-mode .temp-time-summary-value {
  color: var(--primary-400, #2dd4bf);
}

/* ⭐ 2026-08-31 — the share step's "what happens next" handoff. The time
   editor left this modal for the board, so this row explains the drag-bar
   step and offers one honest button (close onto the already-active board).
   Same visual weight as the old time-slot row it replaces. */
.temp-group-next-steps {
  margin: 16px 0 4px;
  border-top: 1px solid var(--border-color, #e2e8f0);
  padding-top: 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
body.dark-mode .temp-group-next-steps {
  border-top-color: var(--slate-700, #334155);
}
.temp-group-next-steps .btn { flex-shrink: 0; }

/* The share-step row that owns the current time state + its trigger. */
.temp-group-time-slot {
  margin: 16px 0 4px;
  border-top: 1px solid var(--border-color, #e2e8f0);
  padding-top: 14px;
}
body.dark-mode .temp-group-time-slot {
  border-top-color: var(--slate-700, #334155);
}
.temp-group-time-state {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.temp-group-time-copy {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  color: var(--text-secondary, #64748b);
  min-width: 0;
}
.temp-group-time-copy > i {
  color: var(--primary-500, #14b8a6);
  flex-shrink: 0;
}
.temp-group-time-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.temp-group-modal .form-group textarea {
  width: 100%;
  padding: 10px 14px;
  border-radius: 0.5rem;
  border: 1.5px solid #e2e8f0;
  font-size: 14px;
  resize: vertical;
  font-family: inherit;
  box-sizing: border-box;
  transition: border-color 0.15s ease;
}

.temp-group-modal .form-group textarea:focus {
  outline: none;
  border-color: var(--primary-500, #14b8a6);
  box-shadow: var(--focus-ring-shadow);
}

/* Expiry options: 2x2 grid for 4 items */
.expiry-options {
  display: grid !important;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.expiry-options .option-pill {
  /* Inherit the base 0.8125rem so expiry chips match the duration/posture
     pills (was 12px — visibly smaller). Keep tight horizontal padding so the
     longer labels still fit the 2-col grid. */
  padding: 8px 6px;
}

/* TBD pill override.
   The only element carrying .tbd-pill today is the LEGACY #temp-group-tbd-toggle,
   which the posture radio ("How is the time decided?") replaced and which ships
   hidden (inline `display:none` + aria-hidden). A blanket `display:inline-flex
   !important` here used to DEFEAT that inline hide (inline styles lose to
   !important), re-surfacing the stray "Time to be determined" button directly
   under the Date & time inputs — clicking it disabled both fields while the
   posture still read "I've set it", so setting a time silently stopped working
   (user: "set a time doesn't allow setting of time"). Scope the layout override
   to the button's VISIBLE state (:not([style*="display: none"])) so a hidden
   toggle stays hidden, and drop the display `!important` so an inline hide wins. */
.tbd-pill:not([aria-hidden="true"]) {
  display: inline-flex;
  width: auto !important;
  flex: none !important;
}

/* ---- Preview-as-guest button + preview-mode banner ---- */
.temp-group-preview-row {
  text-align: center;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border-subtle, #f1f5f9);
}

.temp-group-preview-btn {
  background: none;
  border: none;
  color: var(--text-secondary, #475569);
  font-size: 12px;
  cursor: pointer;
  padding: 4px 8px;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.temp-group-preview-btn:hover {
  color: var(--primary-600, #0d9488);
}

.preview-mode-strip {
  background: #fef3c7;
  border-bottom: 1px solid #fde68a;
  color: #78350f;
  font-size: 12px;
  font-weight: 600;
  padding: 8px 16px;
  text-align: center;
  position: sticky;
  top: 0;
  z-index: 10;
}

/* ---- "Recommended" mini-tag on the visibility picker ----
   Matches the shared .recommended-badge (board-modals.css) so the
   "Recommended" marker looks identical across the event/board/temp modals. */
.recommended-pill {
  display: inline-flex;
  align-items: center;
  margin-left: 6px;
  padding: 1px 6px;
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  border-radius: 4px;
  background: rgba(20, 184, 166, 0.12);
  color: #0d9488;
  vertical-align: middle;
}

body.dark-mode .recommended-pill {
  background: rgba(45, 212, 191, 0.15);
  color: #2dd4bf;
}

/* ---- Form-field helpers (extracted from inline styles) ---- */

.temp-group-modal .form-hint-secondary {
  margin-top: 4px;
  /* One step quieter than .form-hint (12px secondary): same size, muted colour,
     so the "use Propose to vote" aside reads as supplementary, not a second hint
     at a different scale. */
  font-size: 12px;
  color: var(--text-muted, #9ca3af);
}

/* Global so both creation modals (create-board + temp-group) share the same
   "(optional)" label affordance. */
.form-label-optional {
  font-weight: 400;
  color: var(--text-muted, #6b7280);
}

.temp-group-modal .datetime-row {
  display: flex;
  gap: 10px;
  align-items: center;
}

.temp-group-modal .datetime-row > input {
  flex: 1;
}

.temp-group-modal .checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}

.temp-group-modal .checkbox-row input[type="checkbox"] {
  margin: 0;
}

.temp-group-modal .range-editor {
  display: none;
  margin-top: 8px;
  padding: 10px 12px;
  background: var(--surface-2, #f1f5f9);
  border-radius: 8px;
}

.temp-group-modal .range-editor-label {
  font-size: 12px;
  color: var(--text-muted, #6b7280);
  margin-bottom: 6px;
}

.temp-group-modal .range-editor-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.temp-group-modal .range-editor-row .num-input {
  width: 70px;
  padding: 4px 8px;
  font-size: 13px;
}

.temp-group-modal .range-editor-row .sep {
  font-size: 12px;
  color: var(--text-muted, #6b7280);
}

.temp-group-modal .range-editor-footnote {
  font-size: 11px;
  color: var(--text-muted, #9ca3af);
  margin-top: 8px;
  line-height: 1.4;
}

.temp-group-modal .range-editor-footnote .fa-solid {
  margin-right: 4px;
}

.temp-group-modal .day-chips-empty {
  font-size: 11px;
  color: var(--text-muted, #9ca3af);
}

.temp-group-modal .day-chips-mount {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.temp-group-modal .day-chips-heading {
  font-size: 12px;
  color: var(--text-muted, #6b7280);
  margin-top: 10px;
  margin-bottom: 6px;
}

.temp-group-modal .day-chips-heading .muted {
  color: var(--text-muted, #9ca3af);
}

/* ---- Share-step elements (extracted from inline styles) ---- */

/* Q4 share-step redesign (2026-08-19). The step used to be a 48px FontAwesome
   tick over three equally-weighted blocks, with no brand present anywhere. It
   read like a generic widget at the exact moment the host shows the product to
   people who have never seen it. Now: the product's own clock-ring mark leads,
   the link is the primary action, and QR/code are demoted to an "or" tier. */

.temp-group-share-header {
  text-align: center;
  margin-bottom: 22px;
}

/* Brand mark + status dot. The mark is the product; the dot is the state.
   Overlapping them keeps one focal point instead of the old lone tick. */
.temp-group-brand-badge {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 16px;
  background: var(--primary-50, #f0fdfa);
  border: 1px solid var(--primary-100, #ccfbf1);
  margin-bottom: 12px;
}

.temp-group-brand-badge .fr-brand-mark {
  display: block;
}

.temp-group-status-dot {
  position: absolute;
  right: -6px;
  bottom: -6px;
  font-size: 18px;
  line-height: 1;
  border-radius: 50%;
  background: var(--bg-primary, #ffffff);
}

.temp-group-share-header.is-live .temp-group-status-dot {
  color: var(--primary-600, #0d9488);
}

.temp-group-share-header.is-warning .temp-group-status-dot {
  color: var(--status-tentative, #f59e0b);
}

.temp-group-share-header.is-warning .temp-group-brand-badge {
  background: var(--warning-100, #fef3c7);
  border-color: var(--status-tentative, #f59e0b);
}

.temp-group-share-header h3 {
  margin: 0 0 4px;
  font-size: 19px;
  font-weight: 650;
  letter-spacing: -0.01em;
  color: var(--text-color, #111827);
}

.temp-group-share-header p {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-muted, #6b7280);
}

/* Names the group being shared, so a host juggling several knows which one. */
.temp-group-share-subject {
  margin-top: 8px !important;
  display: inline-block;
  max-width: 100%;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--hover-bg, #f3f4f6);
  color: var(--text-color, #374151) !important;
  font-size: 13px !important;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.temp-group-field-label {
  margin: 0 0 6px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted, #6b7280);
}

.temp-group-share-row .copy-btn {
  flex-shrink: 0;
  padding: 9px 16px;
  font-size: 13px;
  font-weight: 600;
  /* 44px tap floor: this is the single most-tapped control in the flow and it
     sat at ~30px on phones, which is where the host actually shares from. */
  min-height: 40px;
}

.temp-group-qr-mount .fa-spinner {
  font-size: 18px;
  color: var(--text-muted, #9ca3af);
}

.temp-group-share-actions {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin-top: 10px;
}

.temp-group-share-actions .option-pill {
  flex: 1;
  min-height: 40px;
  font-size: 13px;
}

/* ---- Secondary tier: QR + code sit BELOW an "or" rule, not beside the link ---- */

.temp-group-share-alt {
  margin-top: 18px;
}

.temp-group-alt-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
  color: var(--text-muted, #9ca3af);
  font-size: 12px;
}

.temp-group-alt-divider::before,
.temp-group-alt-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border-color, #e5e7eb);
}

.temp-group-alt-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.temp-group-alt-caption {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted, #9ca3af);
}

/* ---- Temporary Group Share Step ---- */

.temp-group-share-row {
  display: flex;
  align-items: center;
  gap: 8px;
  /* Tighter left padding + flush button: the copy affordance now reads as part
     of the field rather than a pill floating in a grey box. */
  padding: 6px 6px 6px 14px;
  background: var(--bg-primary, #ffffff);
  border-radius: 12px;
  border: 1px solid var(--border-color, #e5e7eb);
  box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
  margin-bottom: 0;
}

.temp-group-share-row:focus-within {
  border-color: var(--primary-500, #14b8a6);
  box-shadow: 0 0 0 3px rgba(var(--primary-rgb, 20, 184, 166), 0.15);
}

.temp-group-share-url {
  flex: 1;
  min-width: 0;
  text-align: left;
  font-family: monospace;
  font-size: 13px;
  color: var(--text-color, #374151);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.temp-group-qr-block {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 28px;
  margin-bottom: 16px;
  flex-wrap: wrap;
}

.temp-group-qr-mount {
  /* box-sizing so the 4px padding + 1px border don't shrink the content box
     below the 140px QR image (which was clipping the QR — "cut off"). Size the
     box to fit a 140px image plus its padding/border, and let the image scale
     to the content box on any viewport. */
  box-sizing: border-box;
  /* 150 -> 124: the QR is a secondary handoff now, so it no longer competes
     with the link for the eye. Still well above the ~100px scan floor at this
     module density, and the image scales to the content box. */
  width: 124px;
  height: 124px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Always white regardless of theme: a dark-tinted quiet zone breaks scanning. */
  background: #ffffff;
  border: 1px solid var(--border-color, #e5e7eb);
  border-radius: 12px;
  padding: 6px;
  flex-shrink: 0;
  overflow: hidden;
}

.temp-group-qr-mount img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: 100%;
  object-fit: contain;
}

.temp-group-code {
  text-align: center;
}

/* The code is read aloud and typed by hand, so it gets a monospace face (even
   digit/letter widths) and a card that looks selectable, rather than floating
   teal text that read as a heading. */
.temp-group-code {
  box-sizing: border-box;
  min-width: 124px;
  min-height: 124px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 10px 14px;
  border: 1px dashed var(--border-color, #d1d5db);
  border-radius: 12px;
  background: var(--hover-bg, #f9fafb);
}

.temp-group-code-value {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: 2px;
  line-height: 1.3;
  /* Wraps instead of overflowing the card on narrow phones. */
  overflow-wrap: anywhere;
  color: var(--primary-700, #0f766e);
  user-select: all;
}

.temp-group-code-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted, #9ca3af);
  margin-top: 6px;
}

/* ---- Guest View ---- */

.session-guest-view {
  min-height: 100vh;
  background: var(--bg-primary, #ffffff);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.session-guest-view .guest-container {
  width: 100%;
  max-width: 640px;
  padding: 24px 16px;
  margin: 0 auto;
}

.session-guest-view .guest-header {
  text-align: center;
  padding: 32px 0 24px;
}

/* The guest-page wordmark is styled ONCE, in the branding block further down
   (search: "BRANDING ON THE GUEST PAGE"). This rule used to set 14px muted
   grey here and was then overridden there by an identical-specificity rule —
   two sources for one thing, which is how the branding ended up looking like
   a caption in the first place. Only the margin lives here now. */
.session-guest-view .guest-header .app-logo {
  margin-bottom: 16px;
}

.session-guest-view .guest-header h1 {
  font-size: 24px;
  font-weight: 700;
  color: var(--text-primary, #111827);
  margin: 0 0 8px;
}

.session-guest-view .guest-header .session-meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  color: var(--text-secondary, #6b7280);
  font-size: 14px;
}

.session-guest-view .guest-header .session-meta i {
  font-size: 12px;
}

/* Event details card */
.session-event-card {
  background: var(--surface-50, #f9fafb);
  border-radius: 12px;
  padding: 20px;
  margin-bottom: 24px;
  border: 1px solid var(--border-color, #e5e7eb);
}

.session-event-card .event-title {
  font-size: 18px;
  font-weight: 600;
  color: var(--text-primary, #111827);
  margin: 0 0 12px;
}

.session-event-card .event-detail-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  font-size: 14px;
  color: var(--text-secondary, #6b7280);
}

.session-event-card .event-detail-row i {
  width: 20px;
  text-align: center;
  color: var(--primary-500, #3b82f6);
}

.session-event-card .event-description {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border-color, #e5e7eb);
  font-size: 14px;
  color: var(--text-secondary, #6b7280);
  line-height: 1.5;
}

/* ---- Timezone Strip ---- */

.session-timezone-strip {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 20px 0;
}

.session-tz-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-radius: 10px;
  border: 1px solid var(--border-color, #e5e7eb);
  background: white;
  transition: all 0.15s ease;
}

.dark .session-tz-card {
  background: var(--surface-100, #1f2937);
}

.session-tz-card.tz-business {
  border-left: 3px solid var(--success-500, #22c55e);
}

.session-tz-card.tz-early-late {
  border-left: 3px solid var(--warning-500, #eab308);
}

.session-tz-card.tz-sleep {
  border-left: 3px solid var(--danger-500, #ef4444);
}

.session-tz-card .tz-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 600;
  color: white;
  background: var(--primary-500, #3b82f6);
  flex-shrink: 0;
}

.session-tz-card .tz-info {
  flex: 1;
  min-width: 0;
}

.session-tz-card .tz-name {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-primary, #111827);
}

.session-tz-card .tz-city {
  font-size: 12px;
  color: var(--text-tertiary, #9ca3af);
}

.session-tz-card .tz-time {
  text-align: right;
  flex-shrink: 0;
}

.session-tz-card .tz-time .time-value {
  font-size: 18px;
  font-weight: 600;
  color: var(--text-primary, #111827);
}

.session-tz-card .tz-time .time-label {
  font-size: 11px;
  color: var(--text-tertiary, #9ca3af);
}

/* ---- RSVP Buttons ---- */

.session-rsvp-buttons {
  display: flex;
  gap: 12px;
  margin: 24px 0;
}

.session-rsvp-buttons .rsvp-btn {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 20px;
  border-radius: 10px;
  border: 2px solid transparent;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
}

.session-rsvp-buttons .rsvp-btn.accept {
  background: var(--success-500, #22c55e);
  color: white;
}

.session-rsvp-buttons .rsvp-btn.accept:hover {
  background: var(--success-600, #16a34a);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(34, 197, 94, 0.3);
}

.session-rsvp-buttons .rsvp-btn.decline {
  background: var(--surface-50, #f9fafb);
  color: var(--text-secondary, #6b7280);
  border-color: var(--border-color, #e5e7eb);
}

.session-rsvp-buttons .rsvp-btn.decline:hover {
  background: var(--danger-50, #fef2f2);
  border-color: var(--danger-300, #fca5a5);
  color: var(--danger-700, #b91c1c);
}

.session-rsvp-buttons .rsvp-btn.selected {
  pointer-events: none;
}

.session-rsvp-buttons .rsvp-btn.accept.selected {
  background: var(--success-100, #dcfce7);
  color: var(--success-700, #15803d);
  border-color: var(--success-500, #22c55e);
}

.session-rsvp-buttons .rsvp-btn.decline.selected {
  background: var(--danger-100, #fee2e2);
  color: var(--danger-700, #b91c1c);
  border-color: var(--danger-500, #ef4444);
}

/* ---- Guest Join Form ---- */

.session-join-form {
  background: var(--surface-50, #f9fafb);
  border-radius: 12px;
  padding: 24px;
  border: 1px solid var(--border-color, #e5e7eb);
}

.session-join-form h3 {
  font-size: 16px;
  font-weight: 600;
  margin: 0 0 16px;
  color: var(--text-primary, #111827);
}

.session-join-form .form-group {
  margin-bottom: 16px;
}

.session-join-form label {
  display: block;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary, #6b7280);
  margin-bottom: 6px;
}

.session-join-form input,
.session-join-form select {
  width: 100%;
  padding: 10px 14px;
  border-radius: 8px;
  border: 1px solid var(--border-color, #e5e7eb);
  font-size: 14px;
  background: white;
  transition: border-color 0.15s ease;
  box-sizing: border-box;
}

.session-join-form input:focus,
.session-join-form select:focus {
  outline: none;
  border-color: var(--primary-500, #3b82f6);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}

/* CityPicker contract (2026-08-25): the dropdown stays hidden until
   CityPicker adds .active — no inline display styles. */
.session-join-form .city-results {
  display: none;
}

.session-join-form .city-results.active {
  display: block;
}

/* CityPicker renders name/offset as SPANS; stack them like the old two-line
   rows rather than letting them run inline. */
.session-join-form .city-result-item .city-name,
.session-join-form .city-result-item .city-tz {
  display: block;
}

.session-join-form .city-results {
  max-height: 200px;
  overflow-y: auto;
  border: 1px solid var(--border-color, #e5e7eb);
  border-radius: 8px;
  background: white;
  margin-top: 4px;
}

.session-join-form .city-result-item {
  padding: 10px 14px;
  cursor: pointer;
  font-size: 13px;
  transition: background 0.1s ease;
}

.session-join-form .city-result-item:hover,
.session-join-form .city-result-item.active {
  background: var(--primary-50, #eff6ff);
}

.session-join-form .city-result-item .city-name {
  font-weight: 500;
  color: var(--text-primary, #111827);
}

.session-join-form .city-result-item .city-tz {
  font-size: 12px;
  color: var(--text-tertiary, #9ca3af);
}

.session-join-form .join-btn {
  width: 100%;
  padding: 12px;
  border-radius: 10px;
  border: none;
  background: var(--primary-500, #3b82f6);
  color: white;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s ease;
}

.session-join-form .join-btn:hover {
  background: var(--primary-600, #2563eb);
}

.session-join-form .join-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Inline join-form error (sessions-client-7): transient failures render
   here, above the submit button, so the form and everything the guest
   typed stays mounted and the Join button is the retry. */
.guest-join-error {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0 0 12px;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--danger-50, #fef2f2);
  border: 1px solid var(--danger-200, #fecaca);
  color: var(--danger-700, #b91c1c);
  font-size: 13px;
  line-height: 1.45;
}

.guest-join-error i {
  flex-shrink: 0;
  margin-top: 2px;
}

body.dark-mode .guest-join-error {
  background: rgba(239, 68, 68, 0.12);
  border-color: rgba(239, 68, 68, 0.35);
  color: var(--danger-300, #fca5a5);
}

/* Retry button on the full-page transient-error state (sessions-client-5).
   The .join-btn rules above are scoped under .session-join-form, so the
   standalone retry button restates the same treatment. */
#guest-error-retry-btn {
  padding: 12px 24px;
  border-radius: 10px;
  border: none;
  background: var(--primary-500, #3b82f6);
  color: white;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.15s ease;
}

#guest-error-retry-btn:hover {
  background: var(--primary-600, #2563eb);
}

/* ---- Participant List ---- */

.session-participant-list {
  margin: 20px 0;
}

.session-participant-list h3 {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-secondary, #6b7280);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin: 0 0 12px;
}

.session-participant-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border-subtle, #f3f4f6);
}

.session-participant-item:last-child {
  border-bottom: none;
}

.session-participant-item .participant-name {
  flex: 1;
  font-size: 14px;
  color: var(--text-primary, #111827);
}

.session-participant-item .participant-city {
  font-size: 12px;
  color: var(--text-tertiary, #9ca3af);
}

.session-rsvp-indicator {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 500;
}

.session-rsvp-indicator.rsvp-accepted {
  background: var(--success-100, #dcfce7);
  color: var(--success-700, #15803d);
}

.session-rsvp-indicator.rsvp-declined {
  background: var(--danger-100, #fee2e2);
  color: var(--danger-700, #b91c1c);
}

.session-rsvp-indicator.rsvp-pending {
  background: var(--surface-200, #e5e7eb);
  color: var(--text-tertiary, #9ca3af);
}

.session-rsvp-indicator.rsvp-proposed {
  background: var(--primary-100, #dbeafe);
  color: var(--primary-700, #1d4ed8);
}

/* ---- Host Panel ---- */

.session-host-panel {
  padding: 20px;
  /* ⚠️ 2026-08-31 — CONTAIN THE PANEL. It had no width constraint at all, so a
     single non-shrinking child (the sync-failed banner) stretched it to 772px
     inside a 412px phone, dragging its left edge to x=-283 and pushing the
     board down the page. A defensive max-width means the next unconstrained
     child clips instead of relocating the whole panel. */
  max-width: 100%;
  box-sizing: border-box;
  overflow-x: hidden;
}
/* ⚠️ 2026-08-31 — THE DOCK MUST NOT INHERIT THE BOARD'S SCROLL WIDTH.
   #timezone-list is DESIGNED to grow past the viewport and scroll (style.css:
   "desktop-width: #timezone-list + its wrapper grow to max-content and
   overflow"). It is a flex sibling of this dock inside .app, so it stretches
   .app to its own width — measured 772px inside a 412px phone — and the dock,
   having no width of its own, came along: left edge at x=-283, a third of the
   host panel off-screen, with the board pushed below it.

   Pin the dock to the VIEWPORT rather than to its stretched parent. `sticky`
   keeps it in the normal flow while `left: 0` anchors it to the scroll origin,
   so scrolling the timeline sideways no longer drags the panel with it. */
#session-host-panel-dock {
  position: sticky;
  left: 0;
  width: 100vw;
  max-width: 100vw;
  box-sizing: border-box;
  overflow-x: hidden;
}

/* Why the proposals list is empty, when it is empty for a REASON (a 403 from
   opening another account's board) rather than because nobody has proposed.
   Quiet by design: this is an explanation, not an error the host can act on. */
.session-proposals-note {
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-secondary, #6b7280);
  background: var(--surface-50, #f9fafb);
  border-radius: 8px;
}

.session-host-panel .rsvp-summary-bar {
  display: flex;
  gap: 16px;
  padding: 16px;
  background: var(--surface-50, #f9fafb);
  border-radius: 10px;
  margin-bottom: 20px;
  justify-content: center;
}

.session-host-panel .rsvp-summary-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
}

.session-host-panel .rsvp-count {
  font-weight: 700;
  font-size: 18px;
}

.session-host-panel .rsvp-label {
  font-size: 12px;
  color: var(--text-tertiary, #9ca3af);
}

.session-host-panel .host-actions {
  display: flex;
  gap: 8px;
  margin-top: 20px;
}

.session-host-panel .host-actions .btn {
  flex: 1;
}

/* ⭐ 2026-08-30 — THE THREE-WAY "HOW DO YOU WANT TO SETTLE THE TIME?" CHOOSER.
   Reuses .temp-option-cards / .temp-option-card wholesale (the same component
   "What guests can see" and "Who can join" already use) so this reads as the
   third question of the same form, not a new pattern. Only the spacing below
   is local. */
.temp-when-choice { margin-bottom: 14px; }
.temp-when-choice > label {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 8px;
}
/* These three are short one-liners, so they sit in a row on anything wider
   than a phone instead of stacking like the longer privacy cards. */
@media (min-width: 560px) {
  #temp-when-choice { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
}

/* What the GUEST will be asked, shown before the host commits. A static
   illustration, deliberately not interactive: it is a preview, and a strip
   that looks draggable but is not would be its own small lie. */
.temp-ask-preview {
  border: 1px solid var(--border-color, #e2e8f0);
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 14px;
  background: var(--surface-50, #f8fafc);
}
.temp-ask-preview[hidden] { display: none; }
.temp-ask-preview-head {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-secondary, #475569);
  margin-bottom: 10px;
}
.temp-ask-preview-q {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary, #0f172a);
  margin: 0 0 8px;
}
.temp-ask-preview-strip {
  display: grid;
  grid-template-columns: repeat(24, 1fr);
  gap: 1px;
  height: 20px;
  margin-bottom: 8px;
}
.temp-ask-cell {
  background: var(--surface-200, #e2e8f0);
  border-radius: 1px;
}
/* Green, matching the guest grid's available-mode polarity — a painted cell
   means "I CAN make this" and must not wear the busy red. */
.temp-ask-cell.is-on { background: var(--status-available, #22c55e); }
body.dark-mode .temp-ask-preview {
  background: var(--slate-800, #1e293b);
  border-color: var(--slate-700, #334155);
}
body.dark-mode .temp-ask-cell { background: var(--slate-700, #334155); }
body.dark-mode .temp-ask-cell.is-on { background: var(--status-available, #22c55e); }

/* The meeting-link hint. Empty until the field is used, so it costs no space
   on an untouched form. Warn state is amber, not red: an unusable link is a
   correction to make, not an error already committed. */
#temp-group-join-url-hint { margin: 6px 0 0; }
#temp-group-join-url-hint:empty { display: none; }
#temp-group-join-url-hint.is-warn { color: var(--warning-700, #b45309); }
body.dark-mode #temp-group-join-url-hint.is-warn { color: var(--warning-300, #fcd34d); }

/* ⭐ 2026-08-31 — [hidden] MUST ACTUALLY HIDE THE FOOTER BUTTONS.
   The two-pane footer toggles Next / Back / Create with the `hidden`
   ATTRIBUTE, but `hidden` only carries the UA default `display: none`, and
   `.btn { display: inline-flex }` (style.css) beats it on specificity. Seen in
   a real browser: pane 2 rendered "Next: pick a time" AND "Create & Share"
   side by side. Every jsdom guard passed — jsdom has no cascade.
   Scoped to this modal's footer so no other .btn[hidden] behaviour changes. */
#temp-group-modal .modal-footer .btn[hidden] { display: none !important; }

/* ⭐ 2026-08-30 — THE DECISION IS CONTENT; THE LINK TOOLS ARE CHROME.
   Finalize is the one thing a host comes back to do, so it sits in the open
   and only when it is actually available. Share / Deactivate / Extend go
   behind a closed disclosure -- they were displacing the timeline, which is
   the thing the panel is about. */
.session-host-panel .host-actions--decide {
  margin-top: 12px;
  /* ⚠️ 2026-08-31 — CONSTRAIN THE BUTTON TO THE PANEL.
     This had no width rule, so "Finalize Time" sized itself against the
     stretched .app (the board's scroll width) rather than the panel and ran
     off the right edge on a phone, while the rows above it fitted. A block
     inside a container that is wider than the viewport needs to be told what
     to measure against. */
  max-width: 100%;
  box-sizing: border-box;
}
/* Same for the shared actions row: .btn children are flex:1, so without a
   bound the row grows to whatever its parent allows. */
.session-host-panel .host-actions {
  max-width: 100%;
  box-sizing: border-box;
  flex-wrap: wrap;
}
.session-host-panel .host-actions .btn { min-width: 0; }
.session-host-panel .host-decide-note {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  font-weight: 600;
  color: var(--success-700, #15803d);
  margin: 0 0 8px;
}
.session-host-panel .host-decide-pending {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  font-size: 12px;
  color: var(--text-tertiary, #9ca3af);
  margin: 12px 0 0;
}
.session-host-panel .host-link-tools {
  margin-top: 12px;
  border-top: 1px solid var(--border-primary, #e5e7eb);
  padding-top: 10px;
}
.session-host-panel .host-link-tools > summary {
  display: flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary, #475569);
  list-style: none;
  padding: 4px 0;
}
.session-host-panel .host-link-tools > summary::-webkit-details-marker { display: none; }
.session-host-panel .host-link-tools > summary::after {
  content: '\f078'; /* chevron-down */
  font-family: 'Font Awesome 6 Free';
  font-weight: 900;
  font-size: 10px;
  margin-left: auto;
  opacity: 0.6;
  transition: transform 0.15s ease;
}
.session-host-panel .host-link-tools[open] > summary::after { transform: rotate(180deg); }
.session-host-panel .host-link-tools-body { padding-top: 4px; }
/* The expiry row lives in here now, so its own top border would double the
   disclosure's. */
.session-host-panel .host-link-tools-body .session-expiry-row {
  border-top: none;
  margin-top: 0;
}
body.dark-mode .session-host-panel .host-link-tools {
  border-top-color: var(--slate-700, #334155);
}

/* ⭐ 2026-08-30 — A DISABLED BUTTON MUST LOOK DISABLED.
   "Finalize Time" carries `disabled` while a group is still time-TBD, and an
   explanatory line sits underneath. But the only :disabled treatment for a
   primary button is scoped to .modal-footer, and these buttons live in
   .host-actions -- so the dead control rendered at FULL strength, gradient and
   glow intact. The host taps a confident primary button, nothing happens, and
   the explanation is below the two buttons under it (user: "finalize time
   doesn't respond"). Same dead-affordance class as the docked hints.
   Applies to any disabled button in this row, not just Finalize. */
.session-host-panel .host-actions .btn:disabled,
.session-host-panel .host-actions .btn[disabled] {
  opacity: 0.45;
  filter: grayscale(0.55);
  box-shadow: none;
  cursor: not-allowed;
  pointer-events: auto; /* keep the title tooltip reachable on hover */
}

/* ---- Expiry row (2026-08-29) ----
   The host's view of the deadline the guest page has always shown, plus the
   extend controls. Sits between the privacy block and the host actions: it is
   status first, action second, so it reads as information the host can act on
   rather than another button row. */

.session-host-panel .session-expiry-row {
  padding: 10px 0;
  border-top: 1px solid var(--border-primary, #e5e7eb);
  margin-top: 12px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 12px;
}

.session-host-panel .session-expiry-line {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--text-secondary, #6b7280);
  min-width: 0;
}

.session-host-panel .session-expiry-line > i {
  opacity: 0.8;
}

.session-host-panel .session-expiry-label {
  font-weight: 600;
}

/* Within 3 days, today, tomorrow, or already lapsed. Amber rather than red:
   an expiring link is a deadline, not an error. */
.session-host-panel .session-expiry-label.is-urgent {
  color: var(--amber-600, #d97706);
}

.session-host-panel .session-expiry-exact {
  color: var(--text-tertiary, #9ca3af);
  font-size: 12px;
  white-space: nowrap;
}

.session-host-panel .session-expiry-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.session-host-panel .session-expiry-extend-label {
  font-size: 12px;
  color: var(--text-tertiary, #9ca3af);
  white-space: nowrap;
}

.session-host-panel .session-expiry-extend-btns {
  display: flex;
  gap: 6px;
}

/* These sit inside .session-host-panel, whose .host-actions .btn rule sets
   flex:1. Scoped tight so the extend buttons stay content-width chips and do
   not stretch like the primary action row. */
.session-host-panel .session-extend-btn {
  flex: 0 0 auto;
  padding: 4px 10px;
  font-size: 12px;
  white-space: nowrap;
}

.session-host-panel .session-expiry-capped {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  font-size: 12px;
  color: var(--text-tertiary, #9ca3af);
}

/* Narrow docks: let the label and the buttons stack rather than squeeze. */
@media (max-width: 480px) {
  .session-host-panel .session-expiry-row {
    flex-direction: column;
    align-items: flex-start;
  }
}

body.dark-mode .session-host-panel .session-expiry-label.is-urgent {
  color: var(--amber-400, #fbbf24);
}

/* ---- Locked Banner ---- */

.session-locked-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  background: var(--warning-50, #fffbeb);
  border: 1px solid var(--warning-200, #fde68a);
  border-radius: 10px;
  margin-bottom: 16px;
  font-size: 14px;
  color: var(--warning-700, #a16207);
}

.session-locked-banner i {
  font-size: 16px;
}

/* ---- Guest Footer ---- */

.guest-footer {
  margin-top: 28px;
  padding: 18px 16px 0;
  border-top: 1px solid var(--border-subtle, #f1f5f9);
  text-align: center;
}

.guest-try-own-team {
  background: white;
  color: var(--primary-600, #0d9488);
  border: 1.5px solid var(--primary-300, #5eead4);
  border-radius: 10px;
  padding: 10px 18px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.guest-try-own-team:hover {
  background: var(--primary-50, #f0fdfa);
  border-color: var(--primary-500, #14b8a6);
}

.guest-footer-tag {
  margin-top: 14px;
  font-size: 12px;
  color: var(--text-tertiary, #9ca3af);
}

/* ---- Guest Trust Strip ---- */

.guest-trust-strip {
  margin-top: 16px;
  padding: 14px 16px;
  background: var(--surface-50, #f9fafb);
  border: 1px solid var(--border-color, #e5e7eb);
  border-radius: 10px;
  text-align: left;
}

.guest-trust-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-secondary, #4b5563);
  margin-bottom: 6px;
}

.guest-trust-row:last-of-type {
  margin-bottom: 0;
}

.guest-trust-row i {
  color: var(--primary-500, #14b8a6);
  font-size: 12px;
  margin-top: 2px;
  flex-shrink: 0;
}

.guest-trust-links {
  margin-top: 10px;
  font-size: 11px;
  color: var(--text-tertiary, #9ca3af);
  display: flex;
  align-items: center;
  gap: 8px;
}

.guest-trust-links a {
  color: var(--text-secondary, #6b7280);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.guest-trust-links a:hover {
  color: var(--primary-600, #0f766e);
}

/* ---- Claim Success Banner ---- */

.session-claim-banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  background: var(--success-50, #f0fdf4);
  border: 1px solid var(--success-200, #bbf7d0);
  border-radius: 10px;
  margin-bottom: 16px;
}

.session-claim-banner-icon {
  color: var(--success-500, #22c55e);
  font-size: 20px;
  flex-shrink: 0;
  margin-top: 2px;
}

.session-claim-banner-body {
  flex: 1;
  min-width: 0;
}

.session-claim-banner-body strong {
  display: block;
  color: var(--success-700, #166534);
  font-size: 14px;
}

.session-claim-banner-body p {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--text-secondary, #64748b);
  line-height: 1.5;
}

.session-claim-banner-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}

.session-claim-banner-cta {
  background: var(--success-500, #22c55e);
  color: white;
  font-size: 12px;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 8px;
  text-decoration: none;
  white-space: nowrap;
}

.session-claim-banner-cta:hover {
  background: var(--success-600, #16a34a);
}

.session-claim-banner-dismiss {
  /* Solid chip + darker glyph so the X stays visible on the light-green banner
     (2026-06-17 X-visibility pass; was background:none + slate-400 ≈2.7:1). */
  background: var(--slate-100, #f1f5f9);
  border: 1px solid var(--slate-200, #e2e8f0);
  cursor: pointer;
  color: var(--slate-600, #475569);
  padding: 4px 6px;
  font-size: 14px;
  border-radius: 6px;
}

.session-claim-banner-dismiss:hover {
  background: var(--slate-200, #e2e8f0);
  border-color: var(--slate-300, #cbd5e1);
  color: var(--slate-700, #334155);
}

body.dark-mode .session-claim-banner-dismiss {
  background: var(--slate-700, #334155);
  border-color: var(--slate-600, #475569);
  color: var(--slate-200, #e2e8f0);
}

/* ---- Archived Banner ---- */

.session-archived-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  background: var(--surface-100, #f3f4f6);
  border: 1px solid var(--border-color, #e5e7eb);
  border-radius: 10px;
  margin-bottom: 16px;
  font-size: 14px;
  color: var(--text-tertiary, #9ca3af);
}

/* ---- Convert Guests Prompt ---- */

.session-convert-prompt {
  background: var(--primary-50, #eff6ff);
  border: 1px solid var(--primary-200, #bfdbfe);
  border-radius: 12px;
  padding: 20px;
  margin: 20px 0;
}

.session-convert-prompt h3 {
  font-size: 15px;
  font-weight: 600;
  color: var(--primary-700, #1d4ed8);
  margin: 0 0 8px;
}

.session-convert-prompt p {
  font-size: 13px;
  color: var(--primary-600, #2563eb);
  margin: 0 0 16px;
}

.session-convert-prompt .guest-checkbox-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;
}

.session-convert-prompt .guest-checkbox-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
}

.session-convert-prompt .convert-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

.session-convert-prompt .convert-actions select {
  flex: 1;
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid var(--primary-200, #bfdbfe);
  font-size: 13px;
}

/* ---- Board Switcher Session Chip ---- */

.board-chip.session-chip {
  border-left: 3px solid var(--primary-500, #3b82f6);
}

.board-chip.session-chip.archived {
  opacity: 0.6;
  border-left-color: var(--text-tertiary, #9ca3af);
}

/* Board type toggle now uses .option-pill classes from board-modals.css */

/* ---- Responsive ---- */

@media (max-width: 640px) {
  .session-guest-view .guest-header .session-meta {
    flex-wrap: wrap;
    gap: 8px 12px;
  }

  /* Share-step layout reflows on tablet+phone so QR + code stack cleanly.
     Q4 redesign: keep them SIDE BY SIDE down to 480px. They are 124px each and
     both fit, and stacking pushed "Preview as a guest" below the fold on the
     phone this flow is mostly used from. */
  .temp-group-qr-block {
    gap: 16px;
  }

  .temp-group-share-actions .option-pill {
    font-size: 12px;
    padding-left: 6px;
    padding-right: 6px;
  }

  /* Tap-target floor for the small dismiss button and similar icon buttons */
  .session-claim-banner-dismiss {
    min-width: 44px;
    min-height: 44px;
  }
}

@media (max-width: 480px) {
  .session-guest-view .guest-container {
    padding: 16px 12px;
  }

  .session-guest-view .guest-header h1 {
    font-size: 20px;
  }

  .session-rsvp-buttons {
    flex-direction: column;
  }

  .session-share-step .share-buttons {
    flex-wrap: wrap;
  }

  .session-host-panel .rsvp-summary-bar {
    flex-wrap: wrap;
    gap: 12px;
  }

  .session-host-panel .host-actions {
    flex-direction: column;
  }

  /* Tap-target floor for city-result-item: 10+14 padding gave ~42px; bump */
  .session-join-form .city-result-item {
    padding: 12px 14px;
    min-height: 44px;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }

  /* The claim banner stacks tighter on small screens */
  .session-claim-banner {
    flex-wrap: wrap;
  }

  .session-claim-banner-actions {
    width: 100%;
    margin-top: 6px;
    justify-content: flex-end;
  }
}

/* ============================================================
 * Guest-view brand polish (scoped to .session-guest-view so
 * the host-side session modal — which shares this stylesheet —
 * is not affected). Aligns palette with website tokens:
 *   --primary-500 #14b8a6 (teal) / --accent-500 #06b6d4 (cyan)
 *   slate text + soft surfaces.
 * ============================================================ */

.session-guest-view {
  /* Soft tinted backdrop — pairs with the white guest card. */
  background:
    radial-gradient(ellipse at top, #ecfeff 0%, transparent 60%),
    linear-gradient(180deg, #f8fafc 0%, #ffffff 60%);
}

/* Lift the whole guest container into a single rounded "page card"
   so the assorted sub-cards read as one surface, not a stack. */
.session-guest-view .guest-container {
  background: #ffffff;
  border: 1px solid #e2e8f0;
  border-radius: 20px;
  box-shadow: 0 10px 40px -10px rgba(15, 23, 42, 0.08);
  padding: 36px 28px 28px;
  margin-top: 28px;
  margin-bottom: 28px;
}

.session-guest-view .guest-header h1 {
  font-size: 26px;
  letter-spacing: -0.01em;
  background: linear-gradient(90deg, #0d9488 0%, #06b6d4 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* BRANDING ON THE GUEST PAGE (2026-08-24, owner: "still no branding or
   logo", photo of a live link).
   The mark and wordmark WERE present — at 14px in #94a3b8 muted grey, which
   read as a caption rather than a brand. This page is the product's main
   shop window: it is what a non-user sees first, and often all they ever
   see. Give it real presence: larger, brand-teal, properly weighted, with
   the clock mark scaled to match the wordmark's cap height. */
/* ⭐ 2026-08-30 — THE SAME WORDMARK AS THE APP, not a teal-coloured word.
   This set flat #0f766e at weight 700. The product's wordmark is a
   teal->cyan GRADIENT at weight 800 with -0.03em tracking (style.css
   .app-brand__name), so the guest page -- the surface a stranger judges the
   product by -- was wearing a different logo from the app it advertises.
   Same gradient, same weight, same tracking, driven by the real tokens. */
.session-guest-view .guest-header .app-logo {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  margin-bottom: 10px;
}

.session-guest-view .guest-header .app-logo a {
  display: inline-flex;
  align-items: center;
  /* Solid fallback first, for engines without background-clip:text. */
  color: var(--primary-600, #0d9488);
  background: linear-gradient(135deg,
    var(--primary-700, #0f766e) 0%,
    var(--primary-500, #14b8a6) 50%,
    var(--accent-500, #06b6d4) 100%);
  -webkit-background-clip: text;
  background-clip: text;
}
/* ⚠️ Scoped to the TEXT, never the wrapper: -webkit-text-fill-color on a
   parent of the SVG would erase the mark's own fills. */
.session-guest-view .guest-header .app-logo a {
  -webkit-text-fill-color: transparent;
}
.session-guest-view .guest-header .app-logo .fr-brand-mark {
  -webkit-text-fill-color: initial;
}
body.dark-mode .session-guest-view .guest-header .app-logo a {
  color: var(--primary-300, #5eead4);
  background: linear-gradient(135deg,
    var(--primary-300, #5eead4) 0%,
    var(--primary-400, #2dd4bf) 50%,
    var(--accent-400, #22d3ee) 100%);
  -webkit-background-clip: text;
  background-clip: text;
}

/* Sized to the wordmark's cap height. 26px viewBox (the four-bar mark), so
   it reads as the logo rather than as a bullet before the word. */
.session-guest-view .guest-header .fr-brand-mark {
  width: 22px;
  height: 22px;
  margin-right: 8px;
  flex: 0 0 auto;
}

/* MOBILE (2026-08-30, owner: "the size isn't optimized for mobile").
   The guest page IS the booking link on a phone, and the header was sized
   for desktop. Tighten the lockup and the surrounding rhythm so the join
   form is nearer the fold -- unlike the app header, the mark STAYS here:
   this is the one surface where a stranger needs to see whose product it
   is, and there is no toolbar competing for the width. */
@media (max-width: 480px) {
  .session-guest-view .guest-header .app-logo {
    font-size: 17px;
    margin-bottom: 8px;
  }
  .session-guest-view .guest-header .fr-brand-mark {
    width: 19px;
    height: 19px;
    margin-right: 6px;
  }
  .session-guest-view .guest-header h1 {
    font-size: 19px;
    margin-bottom: 6px;
  }
}

.session-guest-view .guest-header .session-meta {
  color: #475569;
  font-weight: 500;
}

.session-guest-view .guest-header .session-meta i {
  color: #14b8a6;
}

/* Event details card */
.session-guest-view .session-event-card {
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  border-radius: 16px;
}

.session-guest-view .session-event-card .event-detail-row i {
  color: #14b8a6;
}

/* Timezone strip cards — soften borders, brand-tint the avatar. */
.session-guest-view .session-tz-card {
  border: 1px solid #e2e8f0;
  border-radius: 14px;
}

.session-guest-view .session-tz-card .tz-avatar {
  background: linear-gradient(135deg, #14b8a6 0%, #06b6d4 100%);
}

/* RSVP buttons — Accept becomes the brand gradient CTA, Decline a
   ghost-secondary in teal. Matches website btn-primary / btn-secondary. */
.session-guest-view .session-rsvp-buttons .rsvp-btn {
  border-radius: 12px;
  padding: 14px 20px;
  border: 1.5px solid transparent;
  letter-spacing: -0.01em;
}

.session-guest-view .session-rsvp-buttons .rsvp-btn.accept {
  background: linear-gradient(135deg, #14b8a6 0%, #06b6d4 100%);
  color: #ffffff;
  box-shadow: 0 4px 14px -4px rgba(20, 184, 166, 0.45);
}

.session-guest-view .session-rsvp-buttons .rsvp-btn.accept:hover {
  background: linear-gradient(135deg, #0d9488 0%, #0891b2 100%);
  box-shadow: 0 6px 18px -4px rgba(20, 184, 166, 0.55);
}

.session-guest-view .session-rsvp-buttons .rsvp-btn.decline {
  background: #ffffff;
  color: #475569;
  border-color: #e2e8f0;
}

.session-guest-view .session-rsvp-buttons .rsvp-btn.decline:hover {
  background: #f8fafc;
  border-color: #cbd5e1;
  color: #0f172a;
}

.session-guest-view .session-rsvp-buttons .rsvp-btn.accept.selected {
  background: #ccfbf1;
  color: #115e59;
  border-color: #14b8a6;
  box-shadow: none;
}

.session-guest-view .session-rsvp-buttons .rsvp-btn.decline.selected {
  background: #f1f5f9;
  color: #475569;
  border-color: #cbd5e1;
}

/* Join form — brand-tinted focus ring. */
.session-guest-view .session-join-form {
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  border-radius: 16px;
}

.session-guest-view .session-join-form input:focus,
.session-guest-view .session-join-form select:focus {
  border-color: var(--focus-ring);
  box-shadow: var(--focus-ring-shadow);
}

.session-guest-view .session-join-form .join-btn {
  background: linear-gradient(135deg, #14b8a6 0%, #06b6d4 100%);
  border-radius: 12px;
  box-shadow: 0 4px 14px -4px rgba(20, 184, 166, 0.45);
}

.session-guest-view .session-join-form .join-btn:hover {
  background: linear-gradient(135deg, #0d9488 0%, #0891b2 100%);
  box-shadow: 0 6px 18px -4px rgba(20, 184, 166, 0.55);
}

.session-guest-view .session-join-form .city-result-item:hover,
.session-guest-view .session-join-form .city-result-item.active {
  background: #f0fdfa;
}

/* Participant-list section heading */
.session-guest-view .session-participant-list h3 {
  color: #64748b;
}

/* ---- "Suggest from my calendar" button + hint ----
   A muted secondary action under the Date & time row (and inside the Mode A
   window panel). Only rendered when a calendar is connected, so its presence
   always maps to a real readable calendar. Left-aligned, quieter than the
   posture/duration pills so it reads as an assist, not a primary choice. */
.suggest-from-cal-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  padding: 6px 12px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--primary-600, #0d9488);
  background: rgba(20, 184, 166, 0.08);
  border: 1px solid rgba(20, 184, 166, 0.25);
  border-radius: var(--radius-lg, 12px);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.suggest-from-cal-btn:hover {
  background: rgba(20, 184, 166, 0.14);
  border-color: rgba(20, 184, 166, 0.4);
}

.suggest-from-cal-btn[hidden] {
  display: none;
}

.suggest-from-cal-hint {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  color: var(--text-secondary, #475569);
}

body.dark-mode .suggest-from-cal-btn {
  color: #2dd4bf;
  background: rgba(45, 212, 191, 0.1);
  border-color: rgba(45, 212, 191, 0.3);
}


/* ── Poll slots on the temp-group create step (2026-08-23) ──────────────────
   The posture card "Guests vote on times" reveals this editor. Before it, the
   create step told the host to go and use the Propose tab instead — a dead end
   on the very screen where they were choosing how the time gets decided.
   pollMode + POST /:code/slot-votes had existed server-side since 2026-08-17;
   only the authoring UI was missing. */
.temp-poll-slots {
  border: 1px dashed var(--border-color, #e2e8f0);
  border-radius: 10px;
  padding: 12px 14px;
  margin-top: 10px;
}
body.dark-mode .temp-poll-slots { border-color: var(--slate-700, #334155); }

/* ---- Create-step timeline picker (2026-08-29) ----
   The drag-over-the-group's-day surface that replaced the posture cards and the
   bare date/time inputs. Layout only: the grid rows, the drag bar and the
   verdict pill all inject their own canonical styles. */
.temp-timeline-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}

.temp-timeline-head > label {
  margin: 0;
}

.temp-timeline-daynav {
  display: flex;
  align-items: center;
  gap: 2px;
}

.temp-day-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: 1px solid var(--slate-200, #e2e8f0);
  border-radius: 6px;
  background: transparent;
  color: var(--slate-600, #475569);
  cursor: pointer;
  font-size: 11px;
}

.temp-day-btn:hover:not(:disabled) {
  background: var(--slate-100, #f1f5f9);
}

.temp-day-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.temp-day-label {
  min-width: 92px;
  text-align: center;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--slate-700, #334155);
}

/* The grid renders its own rows; this just gives it breathing room and lets a
   long roster scroll instead of pushing the create button off-screen.

   ⚠️ The cap must clear a realistic roster, or a member is silently cut in half
   at the fold and reads as absent — found by screenshot 2026-08-29 at 190px,
   which clipped the 4th of 4 rows. ~46px per row + caption + hour ruler, so
   this shows six rows before it scrolls, and the scrollbar itself is then the
   signal that more exist. */
.temp-timeline-grid {
  margin: 10px 0 4px;
  max-height: 340px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Length chips, inline above the bar they size. Compact so they read as a
   modifier of the timeline rather than a second major question. */
.temp-timeline-length {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
  flex-wrap: wrap;
}

.temp-timeline-length-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--slate-500, #64748b);
  flex: none;
}

.temp-timeline-length-chips {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
  flex: 1 1 auto;
  margin: 0;
}

.temp-timeline-length-chips .duration-pill {
  padding: 4px 10px;
  font-size: 12px;
}

body.dark-mode .temp-timeline-length-label {
  color: var(--slate-400, #94a3b8);
}

/* ⚠️ ALIGNED TO THE CELL COLUMNS, not the container.
   SessionGuestCellGrid lays each row out as `140px 1fr 64px` (name gutter,
   hours, local-time gutter) with an 8px grid gap, and its own hour axis is
   inset by exactly those gutters. A full-width bar therefore sat OFFSET from
   the hours it selects: the block did not line up with the columns it was
   choosing, which defeats the whole "see the time in the context of the group"
   premise. Keep in lockstep with .sgcg-row's template and its 640px
   breakpoint. */
.temp-timeline-bar {
  margin: 4px 0 8px;
  /* 140px name gutter + 8px grid gap + 16px .sgcg-grid padding + 1px border.
     The padding and border are easy to forget and cost 17px at each end — the
     bar looked aligned but sat just off the columns it selects. */
  padding-left: calc(140px + 8px + 17px);
  padding-right: calc(64px + 8px + 17px);
}

@media (max-width: 640px) {
  .temp-timeline-bar {
    padding-left: calc(100px + 8px + 17px);
    padding-right: calc(48px + 8px + 17px);
  }
}

/* Below 480px the local-time gutter costs more than it earns: at 360px the 24
   hour columns are down to ~4px each. Drop it and let the drag tooltip carry
   the time, which it already does. Must match the grid's own template. */
@media (max-width: 480px) {
  /* Match the grid's phone layout: 72px gutter + 6px gap + 6px card padding
     (+1px border). Keep in lockstep with the 480px block in
     session-guest-cell-grid.js — if one moves and the other does not, the bar
     sits off the columns it selects. */
  .temp-timeline-bar {
    padding-left: calc(72px + 6px + 7px);
    padding-right: 7px;
  }

  /* Give the timeline back the nested padding that was costing it 88px of a
     360px screen. The panel and the section keep their vertical rhythm; only
     the horizontal squeeze goes. */
  .temp-time-panel {
    padding-left: 8px;
    padding-right: 8px;
  }

  #temp-group-timeline-group {
    margin-left: -4px;
    margin-right: -4px;
  }
}

/* Banked candidate times on the CREATE step: read-only chips, because the
   timeline above is the editor. (The share step still renders real inputs.) */
.temp-poll-chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 6px 5px 10px;
  margin: 0 6px 6px 0;
  border: 1px solid var(--primary-200, #99f6e4);
  border-radius: 999px;
  background: var(--primary-50, #f0fdfa);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--primary-700, #0f766e);
}

.temp-poll-chip-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--primary-700, #0f766e);
  font-size: 10px;
  cursor: pointer;
  opacity: 0.65;
}

.temp-poll-chip-remove:hover {
  opacity: 1;
  background: var(--primary-100, #ccfbf1);
}

body.dark-mode .temp-poll-chip {
  border-color: var(--slate-600, #475569);
  background: rgba(20, 184, 166, 0.14);
  color: var(--primary-300, #5eead4);
}

body.dark-mode .temp-poll-chip-remove {
  color: var(--primary-300, #5eead4);
}

body.dark-mode .temp-poll-chip-remove:hover {
  background: rgba(20, 184, 166, 0.25);
}

/* Solo-roster note. `hidden` needs its own guard here too, since the rule sets
   an author display. */
.temp-timeline-solo {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--slate-500, #64748b);
}

.temp-timeline-solo[hidden] {
  display: none;
}

body.dark-mode .temp-timeline-solo {
  color: var(--slate-400, #94a3b8);
}

/* Share step: confirmation of who was added to the group. */
.temp-group-share-roster {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  margin: 12px 0 0;
  padding: 9px 11px;
  border-radius: 8px;
  background: var(--primary-50, #f0fdfa);
  font-size: 12.5px;
  color: var(--slate-600, #475569);
}

.temp-group-share-roster > i {
  margin-top: 2px;
  color: var(--primary-600, #0d9488);
}

.temp-group-share-roster[hidden] {
  display: none;
}

body.dark-mode .temp-group-share-roster {
  background: rgba(20, 184, 166, 0.12);
  color: var(--slate-300, #cbd5e1);
}

/* Inline failure notice for the extend action (no toasts). */
.session-host-panel .session-expiry-error {
  flex-basis: 100%;
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--danger-600, #dc2626);
}

.temp-timeline-verdict {
  min-height: 26px;
  margin-bottom: 4px;
}

.temp-timeline-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 8px;
  flex-wrap: wrap;
}

/* A quiet text button — "Decide later" and "Pick a time after all" are escapes,
   not calls to action, so they must not compete with Create & Share. */
.btn-link-quiet {
  border: none;
  background: none;
  padding: 4px 2px;
  color: var(--slate-500, #64748b);
  font-size: 12.5px;
  font-family: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.btn-link-quiet:hover {
  color: var(--slate-700, #334155);
}

/* ⚠️ `display:block` beats the `hidden` ATTRIBUTE (hidden is only a UA rule of
   display:none, which any author display wins). Without the [hidden] guard this
   button showed permanently, offering to undo a "Decide later" nobody chose.
   Same trap as hidden-attr-defeated-by-display elsewhere in this repo. */
.temp-timeline-undo {
  display: block;
  margin: 2px 0 10px;
}

.temp-timeline-undo[hidden] {
  display: none;
}

body.dark-mode .temp-day-btn {
  border-color: var(--slate-700, #334155);
  color: var(--slate-300, #cbd5e1);
}

body.dark-mode .temp-day-btn:hover:not(:disabled) {
  background: var(--slate-700, #334155);
}

body.dark-mode .temp-day-label {
  color: var(--slate-200, #e2e8f0);
}

body.dark-mode .btn-link-quiet {
  color: var(--slate-400, #94a3b8);
}

body.dark-mode .btn-link-quiet:hover {
  color: var(--slate-200, #e2e8f0);
}

.temp-poll-slot-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 8px 0 10px;
}
.temp-poll-slot {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* The two inputs share the row and must survive a 320px phone: flex-basis 0
   with min-width 0 lets them shrink rather than push the remove button off
   screen, which is the classic overflow this layout would otherwise have. */
.temp-poll-slot .temp-poll-date,
.temp-poll-slot .temp-poll-time {
  flex: 1 1 0;
  min-width: 0;
}
/* DatePicker.enhance (2026-08-24) moves the date input into a
   .date-picker-wrapper — the wrapper inherits the input's flex slot so the
   row's 320px-safe layout holds, and the input fills the wrapper. */
.temp-poll-slot .date-picker-wrapper {
  flex: 1 1 0;
  min-width: 0;
}
.temp-poll-slot .date-picker-wrapper .temp-poll-date {
  width: 100%;
}
.temp-poll-slot .temp-poll-remove {
  flex: 0 0 auto;
  /* WCAG 2.2 (2.5.8) minimum target — this is a destructive control on a
     touch surface, so it must not be a hairline hit area. */
  min-width: 32px;
  min-height: 32px;
  color: var(--text-secondary, #64748b);
}
.temp-poll-slot .temp-poll-remove:hover { color: var(--status-busy, #b91c1c); }

.temp-poll-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
/* Dark coverage (2026-08-24): these three used light-only literals via the
   --text-secondary fallback, the exact "1 dark rule vs 15 in the file" gap
   the quality audit flagged. Same slate tones the rest of the file uses. */
body.dark-mode .temp-poll-empty { color: var(--slate-400, #94a3b8); }
body.dark-mode .temp-poll-remove { color: var(--slate-400, #94a3b8); }
body.dark-mode .temp-poll-remove:hover { color: #f87171; }

.temp-poll-empty {
  margin: 0;
  font-size: 12.5px;
  color: var(--text-secondary, #64748b);
}

@media (max-width: 380px) {
  /* Below ~380px the date+time+remove row genuinely cannot fit side by side;
     stack the inputs and let the remove button sit with the time. The
     date-picker wrapper stacks the same way once enhance() owns the input. */
  .temp-poll-slot { flex-wrap: wrap; }
  .temp-poll-slot .temp-poll-date,
  .temp-poll-slot .date-picker-wrapper { flex: 1 1 100%; }
}

/* ── Invited, awaiting their answer (consent, 2026-09-02) ───────────────────
   Teammates the host invited but who have not accepted. Not participants:
   listed above the roster, dimmed, with an envelope instead of an RSVP. */
.session-invited-list { margin: 0 0 10px; }
.session-invited-list[hidden] { display: none; }
.session-invited-head { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-secondary, #6b7280); margin: 0 0 6px; }
.session-participant-item--invited { opacity: .85; }
.session-invited-note { margin: 6px 0 0; font-size: 12px; color: var(--text-secondary, #6b7280); }
