@layer base {
  /* ── Page transitions ─────────────────────────────────────────────
     Turbo 8 wraps Drive navigations in document.startViewTransition
     (enabled by <meta name="view-transition" content="same-origin">).
     The browser's default root crossfade runs ~250ms, which feels
     floaty; tighten it so navigation reads as snappy. Opacity-only
     (no slide) keeps it calm and avoids fighting the stay-board modal
     slide physics. One place to tune the whole-app feel. */
  @media (prefers-reduced-motion: no-preference) {
    ::view-transition-old(root),
    ::view-transition-new(root) {
      animation-duration: 160ms;
      animation-timing-function: ease;
    }
  }

  /* Respect reduced-motion — cut the crossfade, snap instantly. */
  @media (prefers-reduced-motion: reduce) {
    ::view-transition-old(root),
    ::view-transition-new(root) {
      animation: none;
    }
  }
}

/* ── THE MOTION LAYER ──────────────────────────────────────────────
   Everything below is deliberately UNLAYERED so it wins over the
   @layer components rules it retunes (same trick as the Lexxy
   overrides in chat.css). Motion vocabulary lives in tokens.css
   (--dur-*, --ease-*). All of it opts IN via no-preference; users
   who asked for reduced motion get the plain, instant app. */

/* The progress bar — Turbo's loading strip, restyled from its default
   blue to the brand's magenta. Lives outside the reduced-motion guard:
   it's a loading indicator, not decoration. Turbo injects its own
   default rules at runtime and mounts the bar as html's first child;
   the html> combinator outranks them no matter where they land. */
html > .turbo-progress-bar {
  height: 2px;
  background: var(--pink);
}

@media (prefers-reduced-motion: no-preference) {

  /* Press states — the tap talks back. Compositor-only (transform),
     100ms out so the control moves the instant it's touched. The
     transition list re-declares each family's color moves so this
     unlayered rule doesn't strand them. */
  :is(.btn, .btn-paper, .btn-slate-paper, .btn-pink, .g-toggle-btn,
      .rooms-pill, .avatar-menu-item, .home-nav-cta) {
    transition: background var(--dur-fast) ease, color var(--dur-fast) ease,
                border-color var(--dur-fast) ease, filter var(--dur-fast) ease,
                transform var(--dur-instant) var(--ease-out);
  }
  /* The stamp presses INTO the page — a 1px compress reads as ink
     meeting paper, where the old uniform shrink read as retreat.
     (home-pulse motion pass; covers .btn and .btn--go alike.) */
  :is(.btn, .btn-paper, .btn-slate-paper, .btn-pink, .g-toggle-btn,
      .rooms-pill, .avatar-menu-item, .home-nav-cta):active:not(:disabled) {
    transform: translateY(1px);
  }
  /* Icon tools (paperclip, mic, the A) press deeper — they're small. */
  .chat-tool { transition: color var(--dur-fast) ease, background var(--dur-fast) ease,
                           transform var(--dur-instant) var(--ease-out); }
  .chat-tool:active { transform: scale(0.88); }

  /* Chat arrival — every streamed-in message rises from where the
     composer sits. A keyframe (not @starting-style) because Safari 17
     only runs @starting-style on page load, and keyframes chat on
     insert everywhere. */
  .chat-msg { animation: chat-msg-in var(--dur-gentle) var(--ease-out) both; }
  @keyframes chat-msg-in {
    from { opacity: 0; translate: 0 10px; }
  }

  /* The folder rail — drill-ins slide in from the right edge where
     the rail lives, quick enough to read as "already there". */
  .folder-rail-card { animation: rail-in var(--dur-base) var(--ease-out) both; }
  @keyframes rail-in {
    from { opacity: 0; translate: 12px 0; }
  }

  /* The dock — the pings column settles in like an iOS sheet. The
     body margin snaps (layout properties never animate); the column
     itself carries all the motion. */
  .chat-dock:not([hidden]) { animation: dock-in var(--dur-settle) var(--ease-drawer) both; }
  @keyframes dock-in {
    from { opacity: 0; translate: 24px 0; }
  }

  /* Turbo cache previews re-render entry keyframes a second time,
     which reads as a stutter. Previews render final states, plain. */
  html[data-turbo-preview] :is(.chat-msg, .folder-rail-card, .chat-dock) {
    animation: none;
  }

  /* Lodge cards lift a hair on pointer hover — desktop only, or iOS
     taps leave the card stuck mid-air. The lift carries a shadow step
     so the card visibly leaves the desk (home-pulse motion pass). */
  @media (hover: hover) {
    .bc-card { transition: transform var(--dur-base) var(--ease-out),
                           border-color var(--dur-fast) ease,
                           box-shadow var(--dur-base) var(--ease-out); }
    .bc-card:hover { transform: translateY(-1px); box-shadow: var(--shadow-paper); }

    /* The prep itinerary's cards answer the pointer the same way,
       gentler — they're rows on a rail, not doors off the page. */
    .week-line-card--link { transition: transform var(--dur-base) var(--ease-out),
                                        box-shadow var(--dur-base) var(--ease-out),
                                        border-color var(--dur-fast) ease; }
    .week-line-card--link:hover { transform: translateY(-1px); border-color: var(--hover-edge); }
  }
}

/* Send dims while there's nothing to send (class toggled by
   chat#composerChanged). Opacity only — never a lock. */
.chat-send { transition: opacity var(--dur-fast) ease; }
.chat-composer--blank .chat-send { opacity: 0.45; }

/* The drill-in acknowledges the click the moment it's made: while the
   rail frame is fetching, the master starts its dim instead of sitting
   inert for the round trip. */
.folder-split:has(#folder-rail[busy]) .folder-master { opacity: 0.7; }

/* Keyboard focus on the stamped buttons — buttons.css covers the quiet
   variants; these are the filled/outline stamps. Not motion, always on. */
:is(.btn, .btn-paper, .btn-slate-paper, .btn-pink, .hero-chooser-pill):focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* ── MODERN CSS PASS 2 (Jul 16) — zero JavaScript, all progressive
   enhancement: browsers that don't know a property render exactly
   what shipped this morning. ── */

/* Typography that reads set, not poured: balanced display headings,
   orphan-free prose. No-ops on engines without text-wrap keywords. */
.ann-full-title, .folder-letter-head, .home-bc-greeting,
.todo-title, .prep-identity-title, .home-bc-empty-headline,
.invite2 h1, .manage-page-h {
  text-wrap: balance;
}
.folder-letter-p, .ann-full-body p, .home-bc-empty-soft,
.chat-intro, .manage-page-rollup {
  text-wrap: pretty;
}

/* Selection carries the brand. */
::selection {
  background: color-mix(in srgb, var(--pink) 22%, transparent);
}

/* The caret writes in magenta — the composer's quietest signature. */
lexxy-editor, .nom-input, .nom-textarea, input[type="text"],
input[type="email"], textarea {
  caret-color: var(--pink);
}

/* Native controls wear the accent — checkboxes on ride rosters,
   invite toggles, radio pills — without repainting each one. */
:root { accent-color: var(--pink); }

/* Keyboard focus on links, not just buttons. */
a:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Chat panes and the dock keep their scroll to themselves — no
   chaining into the page when you hit the end of the messages. */
.chat-pane, .chat-dock, .folder-rail-card {
  overscroll-behavior: contain;
}

/* Details blocks (the sends matrix, declined lists, the address
   card) open smoothly where the engine can interpolate to auto —
   Chrome 129+/Safari 26; everywhere else they simply snap as before. */
@media (prefers-reduced-motion: no-preference) {
  details {
    interpolate-size: allow-keywords;
  }
  details::details-content {
    opacity: 0;
    block-size: 0;
    overflow-y: clip;
    transition: content-visibility var(--dur-base) allow-discrete,
                opacity var(--dur-base) var(--ease-out),
                block-size var(--dur-base) var(--ease-out);
  }
  details[open]::details-content {
    opacity: 1;
    block-size: auto;
  }

  /* Anchor and back-to-top jumps glide instead of teleporting. */
  html { scroll-behavior: smooth; }

  /* Underlines settle in rather than appear — links feel machined. */
  .home-around-door, .g-rail-back, .home-bc-viewall, .your-host-write {
    transition: text-underline-offset var(--dur-fast) var(--ease-out);
  }
  .home-around-door:hover, .g-rail-back:hover, .your-host-write:hover {
    text-underline-offset: 4px;
  }
}

/* The folder's tab bar earns a hairline shadow once the page is
   actually scrolled — scroll-driven, compositor-only, iOS 26+/Chrome;
   elsewhere the bar stays flat exactly as today. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    @keyframes tabs-condense {
      to { box-shadow: 0 6px 16px -12px var(--paper-deep-shadow); }
    }
    .host-tabs-wrap {
      animation: tabs-condense linear both;
      animation-timeline: scroll();
      animation-range: 0 80px;
    }
  }
}

/* Row affordance where rows are doors: a quiet wash on pointer hover. */
@media (hover: hover) {
  .ann-row-link:hover, .home-around-row:hover {
    background: var(--hover-wash);
    border-radius: var(--radius-md);
  }
}
