/* Framed sheet · feedback under the hand. No animation holds content hidden. */
:root {
  --ease-in-out: cubic-bezier(.65, 0, .35, 1);
  --t-press: 140ms;
  --t-panel: 280ms;
  --t-exit: 160ms;
}

/* Entrances use WAAPI after content renders. Without JS, content stays visible. */
.reveal { opacity: 1; transform: none; animation: none; }
/* Badge, chart and cursor animations retain their app.css definitions. */
/* Preserve the signature orbit, online pulse and slow cover drift from app.css. */
.pulse.off::after { display: none; }
.stream { overflow-anchor: none; scrollbar-gutter: stable; scroll-behavior: auto; }
.btn, .icon-btn, .opt, .linkish, .topics button, .nav-item, .trow, .seg button {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.icon-btn, .opt, .linkish, .nav-item, .trow, .seg button {
  transition: color var(--t-hover) ease, background-color var(--t-hover) ease,
    opacity var(--t-hover) ease, transform var(--t-press) var(--ease-out);
}
.topics button { transition: border-color var(--t-hover) ease, background-color var(--t-hover) ease, transform var(--t-press) var(--ease-out); }
.topics button:hover, .panel-hover:hover { transform: none; }
.btn:active:not(:disabled), .icon-btn:active:not(:disabled), .opt:active:not(:disabled),
.topics button:active:not(:disabled) { transform: scale(.975); }
.trow:active { transform: scale(.995); }
.btn[aria-busy="true"] { cursor: progress; }
.composer:focus-within { border-color: var(--accent); }
.composer { transition: border-color var(--t-hover) ease; }
.seg { position: relative; }
.seg button { position: relative; }
.conversation-mark { display: grid; place-items: center; flex: none; width: 36px; height: 36px; color: var(--accent); }
.conversation-mark > svg { width: 32px; height: 32px; }
.topics button:focus-visible svg { color: var(--accent); transform: translateX(3px); }

/* Keep the original sent/received message entrances; message IDs prevent replay. */
.toast { animation: toast-enter var(--t-ui) var(--ease-out); }
@keyframes toast-enter { from { opacity: 0; transform: translate(-50%, 7px) scale(.985); } to { opacity: 1; transform: translateX(-50%); } }
.menu { animation: menu-enter var(--t-ui) var(--ease-out); transform-origin: left bottom; }
@keyframes menu-enter { from { opacity: 0; transform: translateY(5px) scale(.98); } to { opacity: 1; transform: none; } }
dialog[open], dialog.dlg[open] { animation: dialog-enter var(--t-panel) var(--ease-out); }
dialog::backdrop { animation: backdrop-enter var(--t-ui) ease; }
@keyframes dialog-enter { from { opacity: 0; transform: translateY(10px) scale(.98); } to { opacity: 1; transform: none; } }
@keyframes backdrop-enter { from { opacity: 0; } to { opacity: 1; } }

/* Native top-layer/discrete transitions keep Escape, focus restoration and
   modal semantics intact. Older browsers use the entrance above. */
@supports (transition-behavior: allow-discrete) {
  dialog, dialog.dlg {
    opacity: 0;
    transform: translateY(6px) scale(.985);
    transition: opacity var(--t-exit) ease, transform var(--t-exit) var(--ease-out),
      display var(--t-panel) allow-discrete, overlay var(--t-panel) allow-discrete;
  }
  dialog[open], dialog.dlg[open] {
    opacity: 1; transform: none; animation: none;
    transition-duration: var(--t-panel);
  }
  dialog::backdrop {
    opacity: 0; animation: none;
    transition: opacity var(--t-ui) ease, display var(--t-panel) allow-discrete, overlay var(--t-panel) allow-discrete;
  }
  dialog[open]::backdrop { opacity: 1; }
  @starting-style {
    dialog[open], dialog.dlg[open] { opacity: 0; transform: translateY(10px) scale(.98); }
    dialog[open]::backdrop { opacity: 0; }
  }
}

/* Details and mobile navigation open as layers, never by animating grid widths. */
.detail-close { display: none; }
@media (max-width: 1180px) {
  .detail-close { display: inline-grid; position: absolute; top: 10px; right: 10px; z-index: 1; }
  .details > section:first-of-type > h3 { padding-right: 36px; }
  .inbox:not(.no-details) .details { animation: details-enter var(--t-panel) var(--ease-out); }
  @keyframes details-enter { from { opacity: 0; transform: translateX(14px); } to { opacity: 1; transform: none; } }
  @supports (transition-behavior: allow-discrete) {
    .details { transition: opacity var(--t-exit) ease, transform var(--t-exit) var(--ease-out), display var(--t-panel) allow-discrete; }
    .inbox.no-details .details { opacity: 0; transform: translateX(14px); }
    .inbox:not(.no-details) .details { opacity: 1; transform: none; animation: none; transition-duration: var(--t-panel); }
    @starting-style { .inbox:not(.no-details) .details { opacity: 0; transform: translateX(14px); } }
  }
}
@media (max-width: 860px) {
  .a-side { visibility: hidden; pointer-events: none; transition: transform var(--t-panel) var(--ease-out), visibility 0s var(--t-panel); }
  .a-side.open { visibility: visible; pointer-events: auto; transition-delay: 0s; }
  .btn, .icon-btn, .opt { min-height: 40px; }
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .topics button:hover, .panel-hover:hover { transform: translateY(-2px); }
}
@media (hover: none) {
  .topics button:hover { background: var(--surface); border-color: var(--border); transform: none; }
  .topics button:hover svg { color: var(--faint); transform: none; }
  .btn.primary:hover svg { transform: none; }
}
.motion-paused *, .motion-paused *::before, .motion-paused *::after { animation-play-state: paused !important; }
dialog.dlg-fallback[open] { transform: translate(-50%, -50%); animation: fallback-dialog-enter var(--t-panel) var(--ease-out); }
@keyframes fallback-dialog-enter { from { opacity: 0; transform: translate(-50%, calc(-50% + 10px)) scale(.98); } to { opacity: 1; transform: translate(-50%, -50%); } }

/* The lake is a postcard; the existing photo drift stays on the inner image. */
.cover { transition: transform 500ms var(--ease-out); }
.cover.lake-tilt { transform: perspective(850px) rotateX(var(--lake-rx, 0deg)) rotateY(var(--lake-ry, 0deg)); }
.topics button:hover svg, .topics button:focus-visible svg { transform: translateX(4px); color: var(--accent); }

/* A line is drawn where the visitor starts writing; a packet scans the line. */
.composer::before, .composer::after { content: ''; position: absolute; z-index: 1; pointer-events: none; background: var(--accent); }
.composer::before { left: 16px; right: 16px; top: -1px; height: 2px; transform: scaleX(0); transform-origin: left; opacity: 0; transition: transform 420ms var(--ease-out), opacity 180ms ease; }
.composer::after { left: 16px; top: -2px; width: 5px; height: 4px; border-radius: 2px; opacity: 0; }
.composer:focus-within::before { transform: scaleX(1); opacity: .65; }
.composer:focus-within::after { animation: data-scan 1900ms linear infinite; }
@keyframes data-scan { 0% { transform: translateX(0); opacity: 0; } 12%, 80% { opacity: 1; } 100% { transform: translateX(var(--ink-run, 160px)); opacity: 0; } }

/* The folded-note mark draws in like a small circuit booting up. */
.conversation-mark > svg path { stroke-dasharray: 180; stroke-dashoffset: 0; animation: note-trace 1300ms var(--ease-out) both; }
.conversation-mark > svg path:nth-child(2) { animation-delay: 100ms; }
.conversation-mark > svg path:nth-child(3) { animation-delay: 200ms; }
@keyframes note-trace { from { stroke-dashoffset: 180; opacity: .3; } to { stroke-dashoffset: 0; opacity: 1; } }
.data-packet { position: fixed; z-index: 69; width: 4px; height: 4px; border-radius: 50%; background: var(--accent); pointer-events: none; }

/* Each delivery mode keeps its own gesture instead of one universal bounce. */
.opt[data-act="burn"][aria-pressed="true"] svg { animation: flame-wake 440ms var(--ease-out); transform-origin: 50% 100%; }
.opt[data-act="schedule"][aria-pressed="true"] svg { animation: clock-wind 480ms var(--ease-out); }
.opt[data-act="drift"][aria-pressed="true"] svg { animation: bottle-launch 600ms var(--ease-out); }
@keyframes flame-wake { from { transform: scaleY(.65) scaleX(.9); opacity: .45; } to { transform: none; opacity: 1; } }
@keyframes clock-wind { from { transform: rotate(-65deg); } to { transform: rotate(0); } }
@keyframes bottle-launch { 0% { transform: translateY(2px) rotate(-12deg); } 55% { transform: translateY(-2px) rotate(8deg); } 100% { transform: none; } }
[data-act="send"]:not(:disabled):hover svg { transform: translate(2px, -1px) rotate(-8deg); }

/* Day and night spread from the visible theme control, with a plain fallback. */
::view-transition-old(root) { animation: none; }
::view-transition-new(root) { animation: theme-unfold 580ms var(--ease-out); mix-blend-mode: normal; }
@keyframes theme-unfold { from { clip-path: circle(0 at var(--theme-x, 50%) var(--theme-y, 24px)); } to { clip-path: circle(150vmax at var(--theme-x, 50%) var(--theme-y, 24px)); } }

/* Final rule deliberately follows every animation, including page-local CSS.
   The former .reveal opacity:0 must never survive in this mode. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
  .reveal { opacity: 1 !important; transform: none !important; }
  .cover, .cover img, .topics button:hover, .btn:active, .icon-btn:active, .opt:active, .trow:active { transform: none !important; }
  .composer::before, .composer::after { display: none; }
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
  .typing i { opacity: .65; }
}
