/* =============================================================
   Vrolu — base styles
   Imports tokens, resets, base typography, and Bootstrap overrides
   so auth pages (which still use Bootstrap classes) inherit brand.
   ============================================================= */

@import url('css/tokens.css');

/* ---------- Reset / base ---------- */

*, *::before, *::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

html, body {
  margin: 0;
  padding: 0;
  min-height: 100%;
  background: var(--color-bg-base);
  color: var(--color-text-primary);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.6;
  font-feature-settings: 'cv02', 'cv11';  /* Inter stylistic alternates */
  transition: background-color var(--duration-base) var(--ease-out),
              color var(--duration-base) var(--ease-out);
}

a {
  color: var(--color-primary);
  text-decoration: none;
  transition: color var(--duration-fast) var(--ease-out);
}

a:hover {
  color: var(--color-primary-strong);
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-4);
  font-variation-settings: 'opsz' 144;  /* Fraunces optical sizing for display */
}

h1 { font-size: var(--text-5xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); font-variation-settings: 'opsz' 36; }
h4 { font-size: var(--text-xl); font-variation-settings: 'opsz' 14; }

h1:focus, h2:focus { outline: none; }

p { margin: 0 0 var(--space-4); }

code, pre, .mono {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

::selection {
  background: var(--color-primary-soft);
  color: var(--color-text-primary);
}

/* ---------- Brand button + form primitives ---------- */

.btn {
  font-family: var(--font-body);
  font-weight: 500;
  border-radius: var(--radius-pill);
  padding: var(--space-3) var(--space-5);
  border: 1px solid transparent;
  transition: transform var(--duration-fast) var(--ease-out),
              background-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}

.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn-primary {
  background: var(--color-primary);
  color: var(--color-text-inverse);
  border-color: var(--color-primary);
}

.btn-primary:hover {
  background: var(--color-primary-strong);
  border-color: var(--color-primary-strong);
  color: var(--color-text-inverse);
  box-shadow: var(--shadow-glow);
}

.btn:disabled,
.btn.disabled,
.btn-primary:disabled,
.btn-primary.disabled {
  background: var(--color-bg-elevated);
  color: var(--color-text-muted);
  border-color: var(--color-border);
  cursor: not-allowed;
  opacity: 1;
  box-shadow: none;
  transform: none;
}

.btn:disabled:hover,
.btn.disabled:hover {
  background: var(--color-bg-elevated);
  color: var(--color-text-muted);
  border-color: var(--color-border);
  transform: none;
  box-shadow: none;
}

.btn-link, a.btn-link { color: var(--color-primary); }
.btn-link:hover { color: var(--color-primary-strong); }

.btn:focus, .btn:active:focus,
.form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 3px var(--color-primary-soft);
  outline: none;
}

/* ---------- Header icon button — unified top-toolbar primitive ----------
   Single primitive for icon-only header affordances (theme toggle, nav
   links collapsed to icons on mobile, avatar link, sign-out). 44x44
   satisfies iOS HIG; transparent border becomes a soft-coral fill on
   hover and active-route states. Brand CTAs that DO appear in headers
   (e.g. the marketing "Dashboard" pill for signed-in guests on the
   funnel) keep .btn / .btn-primary so the toolbar reads as a row of
   quiet icon affordances + one loud CTA where applicable.
   See UI_STYLE_GUIDE.md "Top toolbar" for the contract. */
.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--color-text-secondary);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  /* transform is in the list so the global tap-feedback :active rule
     (see "Tap feedback" block below) animates the scale-down smoothly
     on both press AND release. */
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}

.icon-button:hover {
  background: var(--color-primary-soft);
  color: var(--color-primary);
}

/* Active-route state: same visual language as .trip-tabs__tab--active
   (gold-accent border + subtle accent fill + coral icon). One selected-
   state vocabulary across the app — pills and icon-buttons read as
   selected the same way. Previous version used a semi-transparent gray
   fill which got lost at 44x44 surface; the visible border cue is what
   carries "you are here" on small targets. */
.icon-button.active {
  border-color: color-mix(in srgb, var(--color-accent) 50%, var(--color-border));
  background: color-mix(in srgb, var(--color-accent) 8%, var(--color-bg-elevated));
  color: var(--color-primary);
}

.icon-button:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.icon-button > svg {
  width: 20px;
  height: 20px;
}

.form-control,
.form-select {
  background: var(--color-bg-elevated);
  color: var(--color-text-primary);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
}

.form-control:focus,
.form-select:focus {
  background: var(--color-bg-elevated);
  color: var(--color-text-primary);
  border-color: var(--color-primary);
}

.form-control::placeholder { color: var(--color-text-muted); }

.form-label {
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  /* Bootstrap defaults to margin-bottom: 0.5rem; we use flex gap on form rows
     instead, so explicitly null this out — otherwise the label sits 16px
     above its input (8px margin + 8px flex gap), orphaning it visually. */
  margin-bottom: 0;
}

/* Bootstrap card / list rebrand for auth pages */
.card {
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  color: var(--color-text-primary);
}

.card-body { padding: var(--space-6); }

hr { border-color: var(--color-border); }

/* Validation */
.valid.modified:not([type=checkbox]) { outline: 1px solid var(--color-success); }
.invalid { outline: 1px solid var(--color-danger); }
.validation-message { color: var(--color-danger); }

/* ---------- Auth pages (Identity-scaffolded surfaces) ---------- */

.auth {
  max-width: 440px;
  margin: var(--space-8) auto;
  padding: 0 var(--space-5);
}

.auth__header { margin-bottom: var(--space-6); }

.auth__eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--color-primary);
  margin: 0 0 var(--space-2);
  text-transform: lowercase;
}

.auth__title {
  font-size: var(--text-4xl);
  margin: 0 0 var(--space-3);
  font-variation-settings: 'opsz' 96;
}

.auth__lede {
  color: var(--color-text-secondary);
  margin: 0;
}

.auth__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* ---------- Brand form primitives ----------
   Live in global app.css (not component-scoped) because Blazor's scoped CSS
   markers don't reach the <form> element rendered by the EditForm component
   — the rewritten selector wouldn't match. These classes are reused across
   New Trip, Add Traveler, Edit Traveler, etc., so global is also the right
   home architecturally. */

.form-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  max-width: 640px;
}

.form-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.form-row--split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}

.form-row--split > div {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.form-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.form-error {
  color: var(--color-danger);
  background: var(--color-primary-soft);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
}

.form-info {
  color: var(--color-text-primary);
  background: var(--color-bg-sunken);
  border-left: 3px solid var(--color-primary);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
}

.form-label-optional {
  margin-left: var(--space-2);
  color: var(--color-text-muted);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.validation-message {
  color: var(--color-danger);
  font-size: var(--text-sm);
  margin: 0;
}

@media (max-width: 540px) {
  .form-row--split { grid-template-columns: 1fr; }
}

.auth__row {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.auth__error {
  color: var(--color-danger);
  font-size: var(--text-sm);
  margin: 0;
}

.auth__summary {
  color: var(--color-danger);
  font-size: var(--text-sm);
  margin: 0;
}

.auth__remember {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  cursor: pointer;
}

.auth__submit {
  width: 100%;
  margin-top: var(--space-2);
  padding-top: var(--space-3);
  padding-bottom: var(--space-3);
}

.auth__divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  margin: var(--space-3) 0;
}

.auth__divider::before,
.auth__divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--color-border);
}

.auth__passkey {
  background: transparent;
  color: var(--color-text-primary);
  border: 1px solid var(--color-border-strong);
  width: 100%;
  padding: var(--space-3);
}

.auth__passkey:hover {
  background: var(--color-bg-elevated);
  border-color: var(--color-primary-soft);
  color: var(--color-text-primary);
}

/* Phase 1.x — external-provider button row (Google, Apple).
   Wraps the picker form so multiple buttons stack with consistent spacing.
   `.auth__external-btn` matches the visual weight of `.auth__passkey` so
   the three sign-in methods (password, external, passkey) read as peers. */
.auth__external {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.auth__external-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-3);
  background: #ffffff;
  /* Locked dark label: the white background is brand-mandated by Google
     (and any future white-button provider), so the text color must be a
     theme-independent dark — using --color-text-primary inverts to white
     in dark mode and the label disappears against the white button. */
  color: #1f1f1f;
  border: 1px solid #dadce0;
  font-weight: 600;
}

.auth__external-btn:hover {
  /* Subtle off-white hover that preserves contrast with the locked dark
     label. Google's own sign-in buttons use the same grey-50 hover state.
     `color` is explicitly restated because Bootstrap's .btn:hover ships
     `color: var(--bs-btn-hover-color)` which falls back to an undefined
     value here (no .btn-X variant is in play) and overwrites our rest-
     state #1f1f1f with effectively-white — text vanishes against the
     near-white hover background. */
  background: #f8f9fa;
  border-color: #c1c5c9;
  color: #1f1f1f;
}

/* Google's branding guidelines require their multicolor "G" on a white
   button with no surrounding tint. The default rule above already gives us
   white-on-white; this is a hook for future per-provider tweaks. */
.auth__external-btn--google { /* identical to default; kept as hook */ }

/* Apple's HIG requires their wordmark on a solid black (light theme) or
   white (dark theme) button. We stay simple here and invert the standard
   styling — chunk 4 may refine once the Apple provider lands. */
.auth__external-btn--apple {
  background: #000000;
  color: #ffffff;
  border-color: #000000;
}

.auth__external-btn--apple:hover {
  background: #1a1a1a;
  border-color: #1a1a1a;
  color: #ffffff;
}

/* "Not you? Use a different account" escape hatch under the OAuth row.
   Visually quiet — sits between the OAuth buttons and the divider so it
   reads as a secondary affordance, not a competing CTA. */
.auth__external-switch {
  display: inline-block;
  margin: var(--space-2) 0 var(--space-3);
  color: var(--color-text-secondary);
  font-size: var(--text-xs);
  text-decoration: none;
}

.auth__external-switch:hover {
  color: var(--color-text-primary);
  text-decoration: underline;
}

.auth__footnote {
  margin: var(--space-4) 0 0;
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  text-align: center;
}

.auth__links {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-3);
  font-size: var(--text-sm);
  text-align: center;
}

.auth__links a { color: var(--color-text-secondary); }
.auth__links a:hover { color: var(--color-primary); }

/* ---------- Segment landing pages (/for/*) ----------
   Shared structure across bachelorette / destination-wedding / family-
   reunion landing pages. Hero on top, three-card pitch grid, closing CTA. */

.segment-hero {
  padding: var(--space-10) 0 var(--space-8);
  position: relative;
  overflow: hidden;
}

.segment-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(70% 50% at 80% 0%, var(--color-primary-soft), transparent 60%);
  pointer-events: none;
  z-index: 0;
}

.segment-hero__inner {
  max-width: 880px;
  position: relative;
  z-index: 1;
}

.segment-hero__eyebrow {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--color-primary);
  text-transform: lowercase;
  letter-spacing: 0.04em;
  margin-bottom: var(--space-4);
}

.segment-hero__title {
  font-family: var(--font-display);
  font-size: clamp(var(--text-3xl), 5vw, var(--text-5xl));
  line-height: 1.1;
  letter-spacing: -0.015em;
  margin: 0 0 var(--space-5);
  font-variation-settings: 'opsz' 144;
}

.segment-hero__title-accent {
  background: var(--gradient-sunset);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-style: italic;
  /* Italic right-side bearing rescue. Serif italics ("sacred", "honest",
     "actually") have ink that extends past the glyph's advance width;
     background-clip: text only paints up to the inline box's edge, so
     without this the trailing serif of the last letter gets cropped
     where the next sibling (period, space, normal-style text) starts.
     0.08em is below the perceptibility threshold for inter-word spacing
     even at the 5xl hero size and keeps the italic letter intact.
     Mirror this padding on every gradient + italic accent class —
     .dash-header__name, .home-hero__title-accent, .pricing-card__amount
     all carry the same fix. */
  padding-right: 0.08em;
}

.segment-hero__lede {
  font-size: var(--text-lg);
  color: var(--color-text-secondary);
  max-width: 56ch;
  margin: 0 0 var(--space-6);
  line-height: 1.55;
}

.segment-hero__ctas {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  flex-wrap: wrap;
}

.segment-hero__cta {
  font-size: var(--text-base);
  padding: var(--space-3) var(--space-6);
}

.segment-hero__secondary {
  color: var(--color-text-secondary);
  font-weight: 500;
  text-decoration: none;
}

.segment-hero__secondary:hover { color: var(--color-text-primary); }

.segment-pitch {
  padding: var(--space-8) 0 var(--space-10);
}

.segment-pitch__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-5);
}

.segment-pitch__card {
  padding: var(--space-6);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg-elevated);
  transition: border-color var(--duration-base) var(--ease-out),
              transform var(--duration-base) var(--ease-out);
}

.segment-pitch__card:hover {
  border-color: var(--color-border-strong);
  transform: translateY(-2px);
}

.segment-pitch__eyebrow {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  margin: 0 0 var(--space-3);
  color: var(--color-text-primary);
  font-variation-settings: 'opsz' 36;
  line-height: 1.2;
}

.segment-pitch__body {
  color: var(--color-text-secondary);
  margin: 0;
  font-size: var(--text-base);
  line-height: 1.6;
}

.segment-cta {
  padding: var(--space-10) 0 var(--space-12);
  border-top: 1px solid var(--color-border);
  text-align: center;
}

.segment-cta__title {
  font-family: var(--font-display);
  font-size: clamp(var(--text-2xl), 3vw, var(--text-4xl));
  margin: 0 0 var(--space-4);
  font-variation-settings: 'opsz' 96;
}

.segment-cta__lede {
  color: var(--color-text-secondary);
  max-width: 48ch;
  margin: 0 auto var(--space-6);
  font-size: var(--text-lg);
  line-height: 1.55;
}

.segment-cta__price {
  display: block;
  margin-top: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* ---------- Timeline (per-day grouping) ----------
   Reusable across the organizer trip detail and the public /t/{slug} surface.
   Lives in global CSS because Blazor scoped CSS doesn't reach the rendered
   children of EditForm and similar wrapper components — same reason the
   form-stack / form-row primitives are global.
   See documents/HANDOFF.md "Known gotchas" for the full rationale.

   Each day group is a native <details>/<summary> disclosure. Browser-native
   open/close state, accessible by default, no JS required (so the public
   view stays pure static SSR). Initial open state set per-day by the
   server-rendered `open` attribute. */

.timeline-day {
    margin-bottom: var(--space-6);
}

.timeline-day__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    cursor: pointer;
    user-select: none;
    list-style: none; /* hide the default ▸ marker on Firefox */
    margin: 0 0 var(--space-3);
    /* Promote the disclosure to a clearly tappable strip — soft surface,
       full padding, 44px+ tap target, brighter chevron. Reads as a button.
       When the day is open (see further down), the header loses its
       standalone border-radius and merges visually with the panel below,
       so the day reads as a single grouped surface. */
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-elevated);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--color-primary);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    /* `width: 100%` and font: inherit because TripDetail now uses a
       <button> here (vs the prior <summary>) — button defaults shrink to
       content width and use the user-agent font. */
    width: 100%;
    font-family: var(--font-mono);
    cursor: pointer;
    text-align: left;
    /* transform for the tap-feedback :active rule (see "Tap feedback"
       block below). */
    transition: background-color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.timeline-day__header::-webkit-details-marker { display: none; } /* hide default ▸ marker on Safari */

.timeline-day__header:hover {
    background: var(--color-primary-soft);
    border-color: var(--color-primary-soft);
}

/* Open state — selectors target BOTH legacy <details>[open] (used by
   PublicTrip /t/{slug}) AND the new button + data-expanded pattern
   (TripDetail). One CSS, two markup hosts. */

.timeline-day[open],
.timeline-day[data-expanded="true"] {
    border: 1px solid color-mix(in srgb, var(--color-accent) 28%, var(--color-border));
    border-radius: var(--radius-md);
    background: var(--color-bg-elevated);
    overflow: hidden;
}

.timeline-day[open] .timeline-day__header,
.timeline-day[data-expanded="true"] .timeline-day__header {
    background: var(--color-bg-elevated);
    border: 0;
    border-bottom: 1px solid color-mix(in srgb, var(--color-accent) 22%, var(--color-border));
    border-radius: 0;
    margin: 0;
}

.timeline-day[open] .timeline-day__header:hover,
.timeline-day[data-expanded="true"] .timeline-day__header:hover {
    background: color-mix(in srgb, var(--color-accent) 8%, var(--color-bg-elevated));
}

/* Phase 9 — today's day group. A stronger accent border + soft fill
   so the eye lands on it in a multi-day trip timeline. Combined with
   the auto-expand-today seeding in both Razor pages, an organizer
   landing on the Itinerary tab during the trip sees today's events
   without any taps. "Today" is anchored to Trip.DestinationTimeZone
   — same single anchor the People-tab rails use. */
.timeline-day--today {
    border: 1px solid color-mix(in srgb, var(--color-accent) 55%, transparent);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--color-accent) 4%, var(--color-bg-elevated));
}
.timeline-day--today .timeline-day__header {
    background: color-mix(in srgb, var(--color-accent) 6%, transparent);
}
/* Keep the strong border even in the open state (the default open
   rule above mixes only 28% accent into the border, which is fainter
   than what we want for the "this is the day" treatment). */
.timeline-day--today[data-expanded="true"] {
    border-color: color-mix(in srgb, var(--color-accent) 55%, transparent);
}

.timeline-day__today-pill {
    display: inline-flex;
    align-items: center;
    margin-left: var(--space-2);
    padding: 2px var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--color-accent);
    color: var(--color-text-inverse);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    line-height: 1.4;
}

/* Panel — present only on the TripDetail markup variant. The grid-
   template-rows 0fr -> 1fr trick is the same primitive used by the
   traveler row; see the .traveler-row__panel comment in
   TripDetail.razor.css for the full rationale. Inner div clips children
   during the sweep; opacity offset 80ms behind the height so the
   unfurl reads as "space opens, then content settles". */
.timeline-day__panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--duration-base) var(--ease-out);
}

.timeline-day[data-expanded="true"] .timeline-day__panel {
    grid-template-rows: 1fr;
}

.timeline-day__panel-inner {
    min-height: 0;
    overflow: hidden;
    opacity: 0;
    transition: opacity var(--duration-fast) 80ms var(--ease-out);
}

.timeline-day[data-expanded="true"] .timeline-day__panel-inner {
    opacity: 1;
}

.timeline-day__header-label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    flex: 1;
    min-width: 0;
}

.timeline-day__chevron {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    color: var(--color-primary);
    transition: transform var(--duration-fast) var(--ease-out);
}

.timeline-day[open] .timeline-day__chevron,
.timeline-day[data-expanded="true"] .timeline-day__chevron {
    transform: rotate(90deg);
}

.timeline-day__date {
    /* inherit from header (uppercase, mono, primary color) */
}

.timeline-day__summary {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    text-transform: none;
    letter-spacing: normal;
    flex-shrink: 0;
}

.timeline-day__list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* When the parent day is open the list flows inside the panel: tighter
   padding around the edge, no gap (rows are flush against each other
   and separated by sibling dividers below). */
.timeline-day[open] .timeline-day__list,
.timeline-day[data-expanded="true"] .timeline-day__list {
    padding: var(--space-1) var(--space-3);
    gap: 0;
}

.timeline-row {
    display: grid;
    grid-template-columns: 80px auto 1fr auto auto;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-elevated);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

/* Inside an open day, regular rows lose their floating-card treatment
   (the parent panel provides the chrome) and stack flush. The
   all-arrived celebratory row is excluded — its sunset gradient is the
   whole point of the moment and reads cleanly as an accent inset card
   within the panel. */
.timeline-day[open] .timeline-row:not(.timeline-row--all-arrived),
.timeline-day[data-expanded="true"] .timeline-row:not(.timeline-row--all-arrived) {
    background: transparent;
    border: 0;
    border-radius: 0;
}

.timeline-day[open] .timeline-row + .timeline-row:not(.timeline-row--all-arrived),
.timeline-day[data-expanded="true"] .timeline-row + .timeline-row:not(.timeline-row--all-arrived) {
    border-top: 1px solid var(--color-border);
}

.timeline-row__time {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    text-align: right;
}

.timeline-row__icon {
    color: var(--color-text-muted);
    width: 24px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.timeline-row__icon svg {
    width: 18px;
    height: 18px;
}

.timeline-row--event .timeline-row__icon {
    color: var(--color-primary);
}

/* Emoji-glyph variant — used on event rows to mirror the type picker
   (🍽 dinner, 🥐 lunch, 🍹 drinks, 🎯 activity, 🚐 transport, ✏️ other).
   Sets a font-size matching the SVG icons it replaced; flex centering
   on .timeline-row__icon keeps the glyph aligned with time + title. */
.timeline-row__icon--glyph {
    font-size: 16px;
    line-height: 1;
}

.timeline-row__body { min-width: 0; }

.timeline-row__title {
    margin: 0;
    color: var(--color-text-primary);
    font-weight: 500;
    font-size: var(--text-sm);
    overflow: hidden;
    text-overflow: ellipsis;
}

.timeline-row__meta,
.timeline-row__notes {
    margin: var(--space-1) 0 0;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.timeline-row__notes {
    color: var(--color-text-secondary);
    font-style: italic;
}

.timeline-row__links {
    margin: var(--space-2) 0 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.timeline-row__chip {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    background: var(--color-bg-sunken);
    color: var(--color-text-secondary);
    border: 1px solid var(--color-border);
    font-size: var(--text-xs);
    font-weight: 500;
    text-decoration: none;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

.timeline-row__chip:hover {
    background: var(--color-primary-soft);
    color: var(--color-primary);
    border-color: var(--color-primary-soft);
}

.timeline-row__sep { color: var(--color-text-muted); opacity: 0.5; margin: 0 var(--space-1); }

.timeline-row__flight-traveler { color: var(--color-text-primary); font-weight: 500; }
.timeline-row__flight-route { font-family: var(--font-mono); color: var(--color-text-secondary); }
.timeline-row__flight-code { font-family: var(--font-mono); color: var(--color-text-muted); font-size: var(--text-xs); }

.timeline-row__pill {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    background: var(--color-bg-sunken);
    color: var(--color-text-secondary);
    border: 1px solid var(--color-border);
    white-space: nowrap;
}

.timeline-row__pill--boarding,
.timeline-row__pill--departed {
    background: var(--color-primary-soft);
    color: var(--color-primary);
    border-color: transparent;
}

.timeline-row__pill--delayed {
    background: rgba(255, 179, 71, 0.16);
    color: var(--color-accent);
    border-color: transparent;
}

.timeline-row__pill--cancelled,
.timeline-row__pill--diverted {
    background: rgba(232, 52, 78, 0.16);
    color: var(--color-secondary);
    border-color: transparent;
}

.timeline-row__pill--landed {
    background: rgba(74, 222, 128, 0.16);
    color: var(--color-success);
    border-color: transparent;
}

/* Day-3 — per-flight live-data freshness badge. Sits next to the
   status pill on the timeline row. Neutral (Stale) and warning
   (VeryStale) variants only — Fresh and NeverFetched render nothing.
   Uses brand tokens; do not introduce new colors here. */
.timeline-row__freshness {
    display: inline-flex;
    align-items: center;
    font-family: var(--font-body);
    font-size: var(--text-xs);
    padding: 2px var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--color-bg-sunken);
    color: var(--color-text-muted);
    border: 1px solid var(--color-border);
    white-space: nowrap;
    margin-left: var(--space-2);
}

.timeline-row__freshness--warning {
    background: rgba(255, 179, 71, 0.16);
    color: var(--color-warning, var(--color-accent));
    border-color: transparent;
}

/* Flight-history affordance — the entire flight row is the click target
   (opens the read-only history drawer). A chevron pinned to the right edge
   signals it; the row lifts on hover. The chevron is absolutely positioned
   so it stays OUT of the row's 5-column grid flow — otherwise it lands in an
   undefined 6th cell and wraps to its own line. Events share the row markup
   but aren't clickable. */
.timeline-row--clickable {
    cursor: pointer;
    position: relative;
    padding-right: calc(var(--space-4) + 26px);
}
@media (hover: hover) {
    .timeline-row--clickable:hover { background: var(--color-bg-sunken); }
    .timeline-row--clickable:hover .timeline-row__chevron { color: var(--color-text); }
}
.timeline-row--clickable:focus-visible {
    outline: 2px solid var(--color-accent, #ff7a59);
    outline-offset: 2px;
}
.timeline-row__chevron {
    position: absolute;
    right: var(--space-4);
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    color: var(--color-text-muted);
}
.timeline-row__chevron svg { width: 18px; height: 18px; }

/* Read-only flight-history drawer timeline. */
.flight-history { display: flex; flex-direction: column; gap: var(--space-4); }
.flight-history__summary { display: flex; flex-direction: column; gap: var(--space-2); align-items: flex-start; }
.flight-history__route { margin: 0; font-weight: 600; }
.flight-history__empty { margin: 0; color: var(--color-text-muted); font-size: var(--text-sm); }
.flight-history__list { list-style: none; margin: 0; padding: 0; }
.flight-history__item {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-2) 0 var(--space-2) var(--space-4);
    margin-left: 5px;
    border-left: 2px solid var(--color-border);
}
.flight-history__item:last-child { border-left-color: transparent; }
.flight-history__dot {
    position: absolute;
    left: -5px;
    top: 14px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--color-accent);
}
.flight-history__body { flex: 1 1 auto; min-width: 0; }
.flight-history__label { margin: 0; font-weight: 500; }
.flight-history__meta { margin: 2px 0 0; color: var(--color-text-muted); font-size: var(--text-sm); }
.flight-history__when { flex-shrink: 0; color: var(--color-text-muted); font-size: var(--text-xs); white-space: nowrap; }

/* Day-3 — trip-wide outage banner. Renders just above the itinerary
   section when CircuitBreakerState.IsOpen, dismissable per-session.
   Tone: informational, not alarming. Uses --color-warning for the
   icon tint and a soft warning background; copy frames it as a
   "hiccup," not a failure. Schedules/reminders keep working. */
.trip-outage {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    margin: 0 0 var(--space-4) 0;
    background: rgba(255, 179, 71, 0.12);
    border: 1px solid rgba(255, 179, 71, 0.32);
    border-radius: var(--radius-lg, 12px);
    color: var(--color-text-primary);
}

.trip-outage__icon {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    color: var(--color-warning, var(--color-accent));
}

.trip-outage__icon svg {
    width: 22px;
    height: 22px;
}

.trip-outage__body {
    flex: 1 1 auto;
    min-width: 0;
}

.trip-outage__title {
    margin: 0 0 2px 0;
    font-family: var(--font-body);
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--color-text-primary);
}

.trip-outage__copy {
    margin: 0;
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--color-text-secondary);
}

.trip-outage__dismiss {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--color-text-muted);
    border: 1px solid transparent;
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.trip-outage__dismiss:hover {
    background: rgba(255, 248, 242, 0.08);
    color: var(--color-text-primary);
}

.trip-outage__dismiss svg {
    width: 16px;
    height: 16px;
}

@media (max-width: 480px) {
    .trip-outage {
        padding: var(--space-3);
    }
    .timeline-row__freshness {
        font-size: 10px;
        padding: 1px var(--space-2);
    }
}

.timeline-row__actions {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
}

.timeline-row__icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--color-text-muted);
    border: 1px solid transparent;
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.timeline-row__icon-btn:hover:not(:disabled) {
    background: var(--color-bg-sunken);
    color: var(--color-text-primary);
}

.timeline-row__icon-btn--danger:hover:not(:disabled) {
    background: var(--color-primary-soft);
    color: var(--color-danger);
}

.timeline-row__icon-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.timeline-row__icon-btn svg { width: 16px; height: 16px; }

.timeline-row__edit {
    grid-column: 1 / -1;
    background: var(--color-bg-sunken);
    border: 1px solid var(--color-primary-soft);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    margin: calc(-1 * var(--space-3)) calc(-1 * var(--space-4));
}

/* Phase 8 polish — "Everyone's here ✨" celebratory marker rendered as the
   final entry on the day every traveler's last leg has landed. Visual
   weight: warmer than a regular row, but not so loud it competes with the
   day's actual content. The ✨ sits in the time slot, the title says it
   plain. No actions, no pill — the moment is the whole row. */
.timeline-row--all-arrived {
    background: linear-gradient(
        135deg,
        color-mix(in srgb, var(--color-accent) 22%, transparent),
        color-mix(in srgb, var(--color-primary) 14%, transparent)
    );
    border-top: 1px solid color-mix(in srgb, var(--color-accent) 40%, transparent);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
    margin-top: var(--space-2);
}

.timeline-row--all-arrived .timeline-row__time {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    color: var(--color-accent);
}

.timeline-row--all-arrived .timeline-row__title {
    color: var(--color-text-primary);
    font-family: var(--font-display);
    font-weight: 500;
    font-style: italic;
    font-variation-settings: 'opsz' 36;
}

/* Hide the empty icon cell on the celebratory row — its visual weight
   already lives in the ✨ in the time slot. */
.timeline-row--all-arrived .timeline-row__icon--all-arrived {
    visibility: hidden;
}

@media (max-width: 720px) {
    .timeline-row {
        grid-template-columns: auto 1fr auto;
        grid-template-rows: auto auto auto;
        gap: var(--space-2) var(--space-3);
    }
    .timeline-row__time { grid-column: 1; grid-row: 1; text-align: left; }
    .timeline-row__icon { grid-column: 2; grid-row: 1; text-align: left; }
    .timeline-row__pill {
        grid-column: 3;
        grid-row: 1;
        justify-self: end;
        /* Compact on mobile so it has breathing room from the viewport
           edge — was rendering tight against the right side at 375px. */
        font-size: 10px;
        padding: 2px var(--space-2);
        letter-spacing: 0.04em;
    }
    .timeline-row__body { grid-column: 1 / -1; grid-row: 2; }
    /* Freshness pill — long "Live data unavailable — last updated N min
       ago" copy with white-space:nowrap was overflowing its auto-flow
       grid cell on mobile, pushing the row width past the viewport.
       Span full width on its own row and allow wrapping. */
    .timeline-row__freshness {
        grid-column: 1 / -1;
        margin-left: 0;
        white-space: normal;
        line-height: 1.4;
        align-self: start;
    }
    .timeline-row__actions { grid-column: 1 / -1; justify-self: end; }
    .timeline-row__edit { margin: 0; }
}

.auth__devnote {
  margin-top: var(--space-6);
  padding: var(--space-5);
  background: var(--color-bg-elevated);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
}

.auth__devnote p { margin: 0 0 var(--space-3); color: var(--color-text-secondary); }
.auth__devnote p:last-child { margin: 0; }

/* ---------- Utility classes used across layouts ---------- */

.container-page {
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding-left: var(--space-5);
  padding-right: var(--space-5);
}

.text-muted { color: var(--color-text-muted); }
.text-secondary { color: var(--color-text-secondary); }
.font-display { font-family: var(--font-display); }
.font-mono { font-family: var(--font-mono); }

/* ---------- AppLayout NavLink-target classes ----------
   The following classes are applied to elements rendered by the
   Blazor <NavLink> component (the <a> tag). Blazor scoped CSS does
   NOT propagate to child-component-rendered elements, so these rules
   MUST live in global CSS — earlier attempts to scope them inside
   AppLayout.razor.css silently never matched. Per Microsoft's
   docs: "Elements rendered from child components don't have CSS
   isolation applied." Reach the elements either with ::deep from
   the parent's scoped file or (cleaner) place the rules globally.

   Applies to:
     .app__nav-link    — suitcase (Dashboard) + book (Stories) nav links
     .app__user        — the avatar + email link to /Account/Manage

   Mobile-collapse overrides for these classes also live below in the
   shared media query so the rules apply where they're needed. */

.app__nav-link {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    /* Transparent border reserves the 2px box so toggling .active
       doesn't cause a layout shift. */
    border: 1px solid transparent;
    color: var(--color-text-secondary);
    text-decoration: none;
    font-weight: 500;
    font-size: var(--text-sm);
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.app__nav-link:hover {
    background: var(--color-bg-elevated);
    color: var(--color-text-primary);
}

/* Active-route style — gold-accent border + subtle accent fill +
   coral text. Same vocabulary as .trip-tabs__tab--active and
   .icon-button.active so the app uses one "selected" language. */
.app__nav-link.active {
    border-color: color-mix(in srgb, var(--color-accent) 50%, var(--color-border));
    background: color-mix(in srgb, var(--color-accent) 8%, var(--color-bg-elevated));
    color: var(--color-primary);
}

/* Desktop sidebar section label ("Learn more" above the
   marketing-adjacent destinations). Matches the visual
   vocabulary of .nav-drawer-panel__section-label so the mobile
   drawer and the desktop sidebar use the same orientation cues. */
.app__nav-section-label {
    margin: var(--space-3) 0 var(--space-1);
    padding: 0 var(--space-4);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-muted);
}

.app__user {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    border: 1px solid transparent;
    text-decoration: none;
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.app__user:hover {
    background: var(--color-bg-elevated);
    color: var(--color-text-primary);
}

.app__user.active {
    border-color: color-mix(in srgb, var(--color-accent) 50%, var(--color-border));
    background: color-mix(in srgb, var(--color-accent) 8%, var(--color-bg-elevated));
    color: var(--color-primary);
}

/* Mobile collapse — the NavLink-rendered elements morph from
   icon+text rows (desktop sidebar) to 44x44 icon-only buttons
   (mobile top bar). Same target classes as above; same global-
   CSS reasoning. */
@media (max-width: 720px) {
    .app__nav-link,
    .app__user {
        width: 44px;
        height: 44px;
        padding: 0;
        gap: 0;
        border-radius: var(--radius-pill);
        border: 1px solid transparent;
        justify-content: center;
    }

    /* Hide the text label inside the suitcase / stories NavLinks on
       mobile — the icon-only collapsed shape doesn't have room for
       "Dashboard" or "Stories". The <span> here is rendered as
       NavLink ChildContent so it lives in the global rule alongside
       the rest of the mobile collapse. */
    .app__nav-link span { display: none; }

    .app__nav-link:hover,
    .app__user:hover {
        background: var(--color-primary-soft);
        color: var(--color-primary);
    }

    .app__nav-link.active,
    .app__user.active {
        border-color: color-mix(in srgb, var(--color-accent) 50%, var(--color-border));
        background: color-mix(in srgb, var(--color-accent) 8%, var(--color-bg-elevated));
        color: var(--color-primary);
    }
}

/* ---------- Tap feedback ----------
   Subtle scale-down on :active for interactive primitives. Gives the
   "the app heard me" feel native iOS apps have — every tap registers
   visually before any actual transition fires (route change, drawer
   open, expand). The press scales the element to 97% of its size for
   the duration of the press; release returns to baseline.

   Smoothness:
   - Elements whose base `transition` list includes `transform` (.btn,
     .icon-button, .app__nav-link) animate the scale-down + scale-up
     over --duration-fast.
   - Elements without transform in their transition snap instantly.
     That's still acceptable feedback — the press IS the cue.

   Disabled elements skipped via :not(:disabled). .btn's existing
   active style was `transform: translateY(0)` to undo the hover lift;
   stacked with scale(0.97) below so a button press both snaps down
   AND shrinks for a tactile feel.

   iOS Mobile Safari quirk: :active does NOT fire reliably on tap
   unless the element has `cursor: pointer`. Without it, iOS treats
   taps as too brief to enter the active state — visually the scale-
   down animation never plays. Edge / Chrome desktop simulators
   don't reproduce this. The matching cursor declaration immediately
   below the :active block ensures the press-feedback rule actually
   fires on real iPhones, not just in dev tools simulation. */

button:not(:disabled),
[role="button"]:not(:disabled),
.icon-button:not(:disabled),
.traveler-row__chip:not(:disabled),
.timeline-day__header:not(:disabled),
.trip-tabs__tab:not(:disabled),
.dash-trip-card,
.home-segments__card,
.traveler-row__action:not(:disabled),
.traveler-row__add-flight:not(:disabled) {
    cursor: pointer;
}

button:not(:disabled):active,
[role="button"]:not(:disabled):active,
.icon-button:not(:disabled):active,
.traveler-row__chip:not(:disabled):active,
.timeline-day__header:not(:disabled):active,
.trip-tabs__tab:not(:disabled):active,
.dash-trip-card:active,
.home-segments__card:active,
.traveler-row__action:not(:disabled):active,
.traveler-row__add-flight:not(:disabled):active {
    transform: scale(0.97);
}

.btn:not(:disabled):not(.disabled):active {
    transform: translateY(0) scale(0.97);
}


/* ---------- Blazor reconnect / error UI ---------- */

#blazor-error-ui {
  background: var(--color-bg-elevated);
  color: var(--color-text-primary);
  border-top: 2px solid var(--color-danger);
  bottom: 0;
  display: none;
  left: 0;
  padding: var(--space-3) var(--space-5);
  position: fixed;
  width: 100%;
  z-index: 1000;
  box-shadow: var(--shadow-md);
}

#blazor-error-ui .dismiss {
  cursor: pointer;
  position: absolute;
  right: var(--space-4);
  top: var(--space-3);
}

.blazor-error-boundary {
  background: var(--color-danger);
  color: var(--color-text-inverse);
  padding: var(--space-4);
  border-radius: var(--radius-md);
}

.blazor-error-boundary::after { content: "An error has occurred."; }

.darker-border-checkbox.form-check-input { border-color: var(--color-border-strong); }

/* ────────── Places typeahead dropdown ──────────
   Used by <PlaceTypeahead> (NewTrip destination, AddEvent / EditEvent
   location). The visible <input> already styles itself via .form-control
   — these rules only target the suggestion menu that hangs underneath. */

.place-typeahead {
    position: relative;
}

.place-typeahead__suggestions {
    list-style: none;
    margin: var(--space-1) 0 0;
    padding: var(--space-1);
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 30;
    background: var(--color-bg-elevated);
    border: 1px solid color-mix(in srgb, var(--color-accent) 28%, var(--color-border));
    border-radius: var(--radius-md);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
    max-height: 320px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

.place-typeahead__suggestion {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    cursor: pointer;
    min-height: 44px;          /* iOS tap-target floor */
    justify-content: center;
}

.place-typeahead__suggestion:hover,
.place-typeahead__suggestion--active {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
}

.place-typeahead__suggestion-main {
    color: var(--color-text-primary);
    font-weight: 500;
    font-size: var(--text-sm);
}

.place-typeahead__suggestion-sub {
    color: var(--color-text-muted);
    font-size: var(--text-xs);
}

/* ────────── Trip destination hero photo (Phase 8 polish) ──────────
   Wide image strip at the top of TripDetail and PublicTrip pages when
   the trip's destination has a captured Places photo. Renders nothing
   when DestinationPhotoName is null (legacy trips, free-typed
   destinations) — markup is gated upstream so this CSS only matters
   when an image is present.

   Two variants: organizer view (compact, leaves room for breadcrumb +
   header) and public view (slightly taller, sets the mood for travelers
   landing from an iMessage tap). Both bleed to the page edges for the
   "magazine cover" feel; container-page padding picks up below. */
.trip-hero {
    position: relative;
    margin: 0 0 var(--space-6);
    padding: 0;
    aspect-ratio: 21 / 9;
    max-height: 280px;
    overflow: hidden;
    border-radius: var(--radius-lg);
    background: var(--color-bg-elevated);
    /* Gold-accent border to match the open-panel chrome vocabulary. */
    border: 1px solid color-mix(in srgb, var(--color-accent) 22%, var(--color-border));
}

.trip-hero--public {
    aspect-ratio: 16 / 9;
    max-height: 360px;
}

/* "Magazine cover" variant — image is the canvas; title + meta + status
   pill render inside .trip-hero__overlay on top of a bottom-up dark
   gradient for legibility. Used on TripDetail and PublicTrip when the
   organizer captured a destination photo from Google Places. */
.trip-hero--overlay {
    aspect-ratio: 16 / 9;
    max-height: 360px;
}

.trip-hero__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Bottom-up dark gradient lives on the overlay div itself (was a
   separate .trip-hero__gradient layer, but stacking issues with the
   sibling <img> made it unreliable across browsers). The overlay
   already renders text on top of the image, so we know its z-stack
   is correct — painting the gradient as its background guarantees
   the darkening lands wherever the text sits.

   Tuned for white text on any photo — bright skies, sandy beaches,
   snowy slopes all need a substantial floor of darkening to keep the
   title legible. */
.trip-hero__overlay {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: flex-start;
    gap: var(--space-2);
    padding: var(--space-5) var(--space-6);
    color: #fff;
    pointer-events: none;
    background: linear-gradient(
        to top,
        rgba(0, 0, 0, 0.92) 0%,
        rgba(0, 0, 0, 0.78) 25%,
        rgba(0, 0, 0, 0.55) 50%,
        rgba(0, 0, 0, 0.32) 75%,
        rgba(0, 0, 0, 0.15) 100%
    );
}

.trip-hero__title {
    font-family: var(--font-display);
    font-size: clamp(var(--text-3xl), 5vw, var(--text-5xl));
    line-height: 1.05;
    margin: 0;
    color: #fff;
    font-variation-settings: 'opsz' 144;
    /* Subtle drop-shadow so even busy photos don't break the title. */
    text-shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
}

.trip-hero__meta {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    color: rgba(255, 255, 255, 0.92);
    font-size: var(--text-sm);
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
}

/* Status badge on the hero (replaces the breadcrumb pill when a photo
   is present). Translucent dark fill so the badge reads against any
   photo without fighting the gradient; status-specific tint applied
   on top via the --draft/--archived modifier. */
.trip-hero__status {
    align-self: flex-start;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    background: rgba(0, 0, 0, 0.45);
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.35);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.trip-hero__status--draft {
    background: color-mix(in srgb, var(--color-accent) 78%, transparent);
    color: var(--color-text-primary);
    border-color: transparent;
}

.trip-hero__status--archived {
    background: rgba(0, 0, 0, 0.55);
    color: rgba(255, 255, 255, 0.78);
    border-color: rgba(255, 255, 255, 0.20);
}

@media (max-width: 720px) {
    .trip-hero {
        aspect-ratio: 16 / 10;
        max-height: 220px;
        /* True viewport-edge bleed regardless of the wrapping container's
           padding. .app__content (TripDetail) uses --space-4 horizontal
           padding while .container-page (PublicTrip) uses --space-5, so a
           single negative-margin value can't cancel both. The 50%/50vw
           trick centers a 100vw-wide element relative to its parent's
           content box and ignores container padding entirely. */
        width: 100vw;
        max-width: 100vw;
        margin-left: calc(50% - 50vw);
        margin-right: calc(50% - 50vw);
        border-radius: 0;
        border-left: 0;
        border-right: 0;
    }

    /* Compacted from the original aspect-ratio: 4/5 + max-height: 420px.
       The portrait magazine-cover treatment looked dramatic but ate half
       the mobile viewport before the user could see any trip content,
       and the sticky utility header above now carries the trip name +
       meta anyway. 16/10 + 200px cap keeps the photo as a visual anchor
       at the top without dominating the fold. */
    .trip-hero--overlay {
        aspect-ratio: 16 / 10;
        max-height: 200px;
    }

    .trip-hero__overlay {
        padding: var(--space-3) var(--space-4);
    }

    /* Trim the overlay title in the compacted hero so it doesn't shout
       louder than the sticky bar's small name above. Sticky carries the
       persistent identity; the hero is now mood / context. */
    .trip-hero--overlay .trip-hero__title {
        font-size: var(--text-xl);
    }
}

/* ────────── Account page (Phase 8 polish redesign) ──────────
   The Identity scaffold's Manage pages stacked a marketing-sized
   Fraunces title over a Bootstrap sidebar of every sub-page (Profile /
   Email / Password / 2FA / Personal data / Passkeys / External logins)
   with default-blue <a> links. Replaced with a single self-contained
   page; sub-pages reachable via in-page CTAs. */

.account {
    max-width: 640px;
    margin: 0 auto;
    padding-bottom: var(--space-10);
}

.account__header {
    margin-bottom: var(--space-6);
}

.account__title {
    font-size: var(--text-4xl);
    margin: 0 0 var(--space-2);
    font-variation-settings: 'opsz' 96;
    line-height: 1.05;
}

.account__subtitle {
    margin: 0;
    color: var(--color-text-secondary);
    font-size: var(--text-base);
}

.account__loading {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

/* Identity strip — large gradient avatar + email + member-since. The
   only place on the page where the sunset gradient appears, mirroring
   how the dashboard sidebar's tiny avatar uses the same gradient at
   ~28px. */
.account__identity {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    background: var(--color-bg-elevated);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-8);
}

.account__avatar {
    width: 56px;
    height: 56px;
    border-radius: var(--radius-pill);
    background: var(--gradient-sunset);
    color: var(--color-text-inverse);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-weight: 500;
    font-size: var(--text-2xl);
    font-variation-settings: 'opsz' 36;
    flex-shrink: 0;
}

.account__identity-meta { min-width: 0; }

.account__identity-email {
    margin: 0 0 var(--space-1);
    font-weight: 500;
    color: var(--color-text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.account__identity-since {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

/* Sections — borrow the same panel chrome from open .timeline-day
   (gold-tinted border, header-flush-with-divider treatment) so the
   account surface visually rhymes with the rest of the polish pass. */
.account__section {
    border: 1px solid color-mix(in srgb, var(--color-accent) 28%, var(--color-border));
    border-radius: var(--radius-md);
    background: var(--color-bg-elevated);
    margin-bottom: var(--space-6);
    overflow: hidden;
}

.account__section-header {
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid color-mix(in srgb, var(--color-accent) 22%, var(--color-border));
}

.account__section-title {
    margin: 0 0 var(--space-1);
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text-primary);
}

.account__section-lede {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

/* Method rows — name + detail + "Active" pill. iOS Settings style.
   Linked rows have a primary-soft pill; unlinked rows show no pill so
   the empty status slot reads as "this method isn't set up yet". */
.account__methods {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.account__method {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-5);
    border-top: 1px solid var(--color-border);
}

.account__method:first-child { border-top: 0; }

.account__method-body {
    flex: 1;
    min-width: 0;
}

.account__method-name {
    margin: 0 0 2px;
    font-weight: 500;
    color: var(--color-text-primary);
    font-size: var(--text-sm);
}

.account__method-detail {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.account__method-status {
    flex-shrink: 0;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-muted);
    padding: 2px var(--space-3);
    border-radius: var(--radius-pill);
    min-width: 4ch;
    text-align: center;
}

.account__method--linked .account__method-status {
    background: color-mix(in srgb, var(--color-success) 16%, transparent);
    color: var(--color-success);
}

.account__section-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-5);
    border-top: 1px solid var(--color-border);
}

/* The .account__methods list above already provides its own border-top
   per row; when the actions row follows the list we don't double up. */
.account__methods + .account__section-actions {
    border-top: 1px solid var(--color-border);
}

.account__action {
    display: inline-flex;
    align-items: center;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-pill);
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    font-weight: 500;
    text-decoration: none;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.account__action:hover {
    background: var(--color-bg-sunken);
    color: var(--color-primary);
}

.account__action--danger {
    color: var(--color-danger);
}

.account__action--danger:hover {
    background: color-mix(in srgb, var(--color-danger) 10%, transparent);
    color: var(--color-danger);
}

/* Danger-zone section is muted by default — the section's gold border
   would read as "look at me!" which is exactly wrong for delete-account
   adjacency. Drop to neutral border + secondary-coded title. */
.account__section--danger {
    border-color: var(--color-border-strong);
}

.account__section--danger .account__section-header {
    border-bottom-color: var(--color-border);
}

/* ───── Subscribe toast (Option B confirmation pattern) ─────
   Plain-JS toast for the bell's direct-unsubscribe + Undo flow.
   Lives in app.css (not PublicTrip.razor.css) because subscribe.js
   appends the toast to <body> — Blazor's scoped-CSS attribute on
   PublicTrip's rules wouldn't match a body child. Bottom-center on
   mobile, lifts in from below, auto-removes after 5s. */
.vrolu-subscribe-toast {
    position: fixed;
    left: 50%;
    bottom: max(var(--space-5), env(safe-area-inset-bottom, 0));
    transform: translateX(-50%);
    z-index: 200;
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-pill);
    background: var(--color-bg-elevated);
    color: var(--color-text-primary);
    border: 1px solid var(--color-border-strong);
    box-shadow: 0 10px 30px -8px rgba(0, 0, 0, 0.35);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    max-width: calc(100vw - var(--space-6));
    animation: vrolu-subscribe-toast-in var(--duration-base) var(--ease-out);
}

@keyframes vrolu-subscribe-toast-in {
    from { transform: translate(-50%, 16px); opacity: 0; }
    to   { transform: translate(-50%, 0);    opacity: 1; }
}

.vrolu-subscribe-toast--error {
    border-color: color-mix(in srgb, var(--color-danger) 50%, var(--color-border-strong));
    color: var(--color-danger);
}

.vrolu-subscribe-toast__msg {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.vrolu-subscribe-toast__undo {
    flex-shrink: 0;
    padding: var(--space-1) var(--space-3);
    border: 0;
    background: var(--color-primary);
    color: var(--color-text-inverse);
    border-radius: var(--radius-pill);
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 500;
    cursor: pointer;
    transition: background-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}

.vrolu-subscribe-toast__undo:hover {
    background: var(--color-primary-strong);
}

/* ────────── Trip page panels (Phase 9 — 3-tab IA) ──────────
   TripDetail and PublicTrip render their three section panels (Itinerary,
   People, Stay) into the DOM at once; CSS hides all but the active one
   based on the wrapper's `data-active-tab` attribute. The attribute is
   driven by trip-tabs.js (reads window.location.hash). All-in-DOM means
   tab switches are instant — no re-fetch, no DOM rebuild, in-flight
   drawer state on hidden tabs survives a switch-and-return.

   These rules live in app.css (not in TripTabsNav.razor.css) because they
   target ancestors of the component scope — Blazor CSS isolation can't
   reach upward. The .trip-page wrapper sits on the page (TripDetail /
   PublicTrip), not inside the nav. */

.trip-page [data-tab] { display: none; }

.trip-page[data-active-tab="itinerary"] [data-tab="itinerary"],
.trip-page[data-active-tab="people"] [data-tab="people"],
.trip-page[data-active-tab="stay"] [data-tab="stay"] {
    display: block;
}

/* Default — no JS / before first applyHash. Shows Itinerary so the page
   isn't blank during the first paint of a freshly-loaded view. */
.trip-page:not([data-active-tab]) [data-tab="itinerary"] { display: block; }

/* Mobile bottom-bar clearance — the fixed .trip-tabs-nav floats above
   the viewport's bottom edge and overlays anything that scrolls beneath
   it. Reserve space on the body itself (not on .trip-page) so sibling
   chrome — footers, branding rows, the "Made with Vrolu" line in
   PublicTripLayout — clears the bar too, not just panel content.
   The :has() lookup limits the rule to pages that actually have a
   .trip-page in the DOM; everywhere else, no extra body padding.
   Magic number tracks the nav's min-height (56px) + vertical padding
   (~16px) + safe-area inset. */
@media (max-width: 720px) {
    body:has(.trip-page) {
        padding-bottom: calc(72px + env(safe-area-inset-bottom));
    }
}

/* ────────── People-panel rails + status pills (Phase 9) ──────────
   Arrivals / Departures horizontal-scroll rails at the top of the
   People tab on both TripDetail and PublicTrip. Same markup on both,
   so the styling lives here in app.css instead of duplicating across
   the two scoped CSS files.

   Auto-hides happen at the Razor level (the @if (count > 0) gates).
   No CSS-side empty-state.

   Status-pill classes (.traveler-status--{kind}) double as both the
   rail-chip status indicator AND the meta-line pill on the existing
   traveler-row chip below — one selector, two spots. */

.people-rail {
    margin: 0 0 var(--space-5);
}

.people-rail__title {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin: 0 0 var(--space-3);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 500;
}

.people-rail__title-icon {
    font-size: var(--text-base);
}

/* Horizontal-scroll list of chips. Hide the native scrollbar — the
   chips telegraph that scroll is possible (right edge fades on
   overflow). Touch-scroll snapping rough-aligns each chip on swipe. */
.people-rail__list {
    display: flex;
    gap: var(--space-3);
    padding: 0;
    margin: 0;
    list-style: none;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}

.people-rail__list::-webkit-scrollbar { display: none; }

.people-rail__chip {
    flex-shrink: 0;
    scroll-snap-align: start;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-width: 240px;
    max-width: 320px;
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-elevated);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
}

.people-rail__chip-avatar {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-pill);
    background: linear-gradient(135deg, var(--color-primary-soft), var(--color-accent-soft, var(--color-bg-sunken)));
    color: var(--color-text-primary);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
}

.people-rail__chip-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex: 1;
}

.people-rail__chip-name {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-primary);
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.people-rail__chip-time {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Status pill — base. The traveler-status--{kind} modifiers below
   recolor the pill per state. Same class is used both on rail chips
   and on the meta line of the existing traveler-row chip in the
   panel below; sizing is intentionally uniform so the two surfaces
   read as one vocabulary. */
.traveler-status {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 2px var(--space-2);
    border-radius: var(--radius-pill);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-weight: 500;
    letter-spacing: 0.02em;
    background: var(--color-bg-sunken);
    color: var(--color-text-muted);
    white-space: nowrap;
    flex-shrink: 0;
}

/* Per-kind tints. Tokens map to the existing semantic colors where
   they exist; in-flight uses a sky-blue hardcode since the palette
   doesn't ship a --color-info and reusing primary (coral) collides
   visually with cancelled. The trio reads as a movement gradient:
   orange (boarding/departs) → blue (in-flight) → green (landed). */
.traveler-status--in-flight {
    background: rgba(96, 165, 250, 0.16);
    color: rgb(125, 180, 250);
}

.traveler-status--landed {
    background: color-mix(in srgb, var(--color-success) 14%, transparent);
    color: var(--color-success);
}

.traveler-status--delayed,
.traveler-status--boarding {
    background: color-mix(in srgb, var(--color-warning, #d97706) 14%, transparent);
    color: var(--color-warning, #d97706);
}

.traveler-status--cancelled {
    background: color-mix(in srgb, var(--color-danger, #dc2626) 14%, transparent);
    color: var(--color-danger, #dc2626);
}

.traveler-status--departs-today {
    background: color-mix(in srgb, var(--color-accent) 18%, transparent);
    color: var(--color-text-primary);
}

.traveler-status--trip-ready,
.traveler-status--no-flights,
.traveler-status--local,
.traveler-status--watching {
    background: var(--color-bg-sunken);
    color: var(--color-text-muted);
}

/* Inside the existing traveler-row meta — flatten the pill so it
   reads as label (not a chip badge) when it's nested in a
   compact row. */
.traveler-row__meta.traveler-status {
    background: transparent;
    padding: 0;
    /* Keep the color tints (the per-kind rules above set color); just
       drop the chip chrome. */
}

@media (max-width: 480px) {
    .people-rail__chip {
        min-width: 200px;
    }
}



/* ---------------------------------------------------------------
   Mobile hamburger nav drawer (.nav-drawer)
   ---------------------------------------------------------------
   Global primitive shared by MarketingLayout and AppLayout. Both
   layouts render a `[data-marketing-nav-toggle]` button + a
   `.nav-drawer-overlay` + `.nav-drawer-panel` element; the
   js/marketing-nav.js module (document-level click delegation)
   flips `marketing-nav--open` on <html>, and the rules below
   handle the slide-in animation, backdrop, and scroll lock.
   Same selectors live globally (here) rather than in either
   layout's scoped CSS because both layouts need to match the
   selectors, and Blazor scoped CSS appends a per-layout
   [b-xxxx] attribute that would prevent cross-layout matching.

   Layout-specific overrides (z-index conflicts with sticky
   headers, etc.) stay in the respective .razor.css. The base
   visual + open/close mechanics are right here. */

.nav-drawer-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    opacity: 0;
    pointer-events: none;
    transition: opacity 180ms ease-out;
    z-index: 80;
}

.nav-drawer-panel {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: min(86vw, 360px);
    background: var(--color-bg-base);
    border-right: 1px solid var(--color-border);
    box-shadow: 8px 0 24px rgba(0, 0, 0, 0.3);
    transform: translateX(-100%);
    transition: transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1);
    z-index: 90;
    display: flex;
    flex-direction: column;
    padding: var(--space-4) var(--space-5) var(--space-6);
    gap: var(--space-4);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

.nav-drawer-panel__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.nav-drawer-panel__title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    color: var(--color-text-muted);
    letter-spacing: 0.02em;
}

.nav-drawer-panel__close {
    width: 36px;
    height: 36px;
}

.nav-drawer-panel__nav {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.nav-drawer-panel__nav a {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    color: var(--color-text-primary);
    font-size: var(--text-xl);
    font-weight: 600;
    text-decoration: none;
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--color-border);
}

/* Lucide-style line icon in front of the label. 22px keeps it
   visually tied to the 24px-ish line-height of the label text
   without overpowering it. Stroke matches the brand vocabulary
   used elsewhere (2px Lucide). */
.nav-drawer-panel__nav a svg {
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    fill: none;
}

.nav-drawer-panel__nav a:last-child { border-bottom: none; }

.nav-drawer-panel__nav a:hover,
.nav-drawer-panel__nav a:focus-visible {
    color: var(--color-accent-coral);
    outline: none;
}

/* Active route — matches the desktop sidebar's coral active pill
   (.app__nav-link.active) so both surfaces use one "I am here"
   vocabulary. NavLink auto-applies the .active class when the
   route matches; we wrap the label/icon row in a small horizontal
   pad so the coral border + tint reads as a distinct affordance
   rather than just colored text. */
.nav-drawer-panel__nav a.active {
    color: var(--color-primary);
    background: color-mix(in srgb, var(--color-accent) 8%, transparent);
    border-radius: var(--radius-md);
    padding-left: var(--space-3);
    padding-right: var(--space-3);
    margin-left: calc(-1 * var(--space-3));
    margin-right: calc(-1 * var(--space-3));
}

/* Drop the bottom border on the active link to avoid a doubled
   line where the coral pill ends — same trick the desktop sidebar's
   active state uses (transparent border on base, accent on active). */
.nav-drawer-panel__nav a.active { border-bottom-color: transparent; }

/* Identity strip at the top of the drawer panel — "Signed in as
   {name}" replaces the avatar+sign-out icons that used to sit in
   the toolbar. Avatar circle + display name; the name truncates
   with ellipsis so an unusually long email doesn't break layout. */
.nav-drawer-panel__identity {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) 0 var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

.nav-drawer-panel__identity-avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--color-accent-coral);
    color: var(--color-bg-base);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: var(--text-base);
    flex-shrink: 0;
}

.nav-drawer-panel__identity-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.nav-drawer-panel__identity-label {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.nav-drawer-panel__identity-name {
    font-size: var(--text-base);
    color: var(--color-text-primary);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nav-drawer-panel__section-label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-muted);
    padding-top: var(--space-2);
}

.nav-drawer-panel__divider {
    height: 1px;
    background: var(--color-border);
    margin-top: var(--space-2);
}

.nav-drawer-panel__actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.nav-drawer-panel__cta {
    width: 100%;
    text-align: center;
    padding: var(--space-3) var(--space-5);
}

.nav-drawer-panel__signin,
.nav-drawer-panel__signout {
    color: var(--color-text-secondary);
    font-size: var(--text-base);
    text-align: center;
    padding: var(--space-3);
    background: transparent;
    border: none;
    text-decoration: none;
    cursor: pointer;
    font-family: inherit;
}

.nav-drawer-panel__signin:hover,
.nav-drawer-panel__signout:hover { color: var(--color-text-primary); }

.nav-drawer-panel__signout-form { margin: 0; }

/* Hamburger button — shared shape. Layouts decide WHEN it's
   visible via their own @media rules; the button itself looks
   the same wherever it lands. */
.nav-drawer-toggle {
    display: none; /* layouts opt in at their mobile breakpoint */
    width: 40px;
    height: 40px;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text-primary);
    cursor: pointer;
    flex-direction: column;
    gap: 5px;
}

.nav-drawer-toggle:hover,
.nav-drawer-toggle:focus-visible {
    border-color: var(--color-border-strong);
    outline: none;
}

.nav-drawer-toggle-bar {
    display: block;
    width: 18px;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
}

/* Open state — js/marketing-nav.js toggles `marketing-nav--open`
   on <html>. Background scroll lock applies globally regardless
   of which layout opened the panel. */
:root.marketing-nav--open {
    overflow: hidden;
}

:root.marketing-nav--open .nav-drawer-overlay {
    opacity: 1;
    pointer-events: auto;
}

:root.marketing-nav--open .nav-drawer-panel {
    transform: translateX(0);
}

@media (min-width: 721px) {
    /* Desktop / tablet — hamburger surface is never shown. */
    .nav-drawer-overlay,
    .nav-drawer-panel { display: none; }
}

/* ---------------------------------------------------------------
   Legal / info document prose — shared by the About, Support,
   Privacy, and Terms pages (/about, /support, /privacy, /terms).
   A reader-comfortable single column modelled on the Stories
   .story-body prose; lives globally here (rather than four scoped
   .razor.css copies) since all four pages render identical
   long-form copy. Pairs with the global .segment-hero / .segment-cta
   sections those pages use for their top and bottom.
   ---------------------------------------------------------------- */
.legal-doc {
    padding: var(--space-6) 0 var(--space-10);
}

.legal-doc__inner {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* Constrain the reading measure on the CHILDREN, not the wrapper. The
   wrapper keeps .container-page's full --container-max width so its left
   edge lines up with the .segment-hero header above it; capping each
   block at 760px keeps a comfortable line length, left-aligned (a
   stretched flex item that hits its max-width sits at the cross-start /
   left edge). Putting the 760 cap on the wrapper itself made it a
   centered narrow column that sat indented ~220px from the hero — the
   alignment bug. */
.legal-doc__inner > * {
    max-width: 760px;
}

.legal-doc__meta {
    margin: 0 0 var(--space-2);
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.legal-doc__inner h2 {
    margin: var(--space-5) 0 0;
    font-family: var(--font-display);
    font-size: var(--text-2xl);
    font-variation-settings: 'opsz' 36;
    line-height: 1.25;
    color: var(--color-text-primary);
}

.legal-doc__inner p {
    margin: 0;
    color: var(--color-text-primary);
    font-size: var(--text-lg);
    line-height: 1.65;
}

.legal-doc__inner p em {
    color: var(--color-primary);
    font-style: italic;
}

.legal-doc__inner ul {
    margin: 0;
    padding-left: var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.legal-doc__inner li {
    color: var(--color-text-primary);
    font-size: var(--text-lg);
    line-height: 1.6;
}

.legal-doc__inner a {
    color: var(--color-primary);
}

.legal-doc__inner code {
    font-family: var(--font-mono);
    font-size: 0.92em;
}
