/* ==========================================================================
   overlays.css — modal, drawer, popover, tooltip, toast, nav sheet
   Everything here is built on native <dialog> or <details>. No JS is needed
   to open or close them, and focus trapping comes free with showModal().
   ========================================================================== */

/* --- Modal ---------------------------------------------------------------
   Native <dialog>. Open it with .showModal(), never with a class — that is
   what gives you the top layer, the focus trap and Esc-to-close. */
.modal {
  /* base.css resets `* { margin: 0 }`, which kills the UA stylesheet's
     `dialog { margin: auto }` and pins the dialog to the corner. Restore it
     here — this one line is what centres the modal. */
  margin: auto;
  inline-size: min(92vw, 520px);
  /* dvh, not vh: on a phone vh ignores the browser chrome, so a tall modal
     runs its footer underneath the address bar. */
  max-block-size: min(86dvh, 720px);
  padding: 0;
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  background: var(--bg-elevated);
  color: var(--text);
  box-shadow: var(--sh-lg);
  overflow: hidden;
}
/* Scoped to [open] on purpose: an unqualified `display:flex` would override
   the UA's `dialog:not([open]) { display: none }` and leave it on screen. */
.modal[open] { display: flex; flex-direction: column; }
.modal::backdrop { background: #0000008c; }
@supports (backdrop-filter: blur(1px)) {
  .modal::backdrop { backdrop-filter: blur(3px); }
}
.modal[open] { animation: modal-in var(--dur) var(--ease) both; }
.modal[open]::backdrop { animation: fade-in var(--dur) var(--ease) both; }

.modal__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-6) var(--s-6) var(--s-4);
}
.modal__title { font-size: var(--fs-h3); font-weight: 600; letter-spacing: -0.014em; }
.modal__desc  { margin-block-start: var(--s-2); font-size: var(--fs-sm); color: var(--text-2); }
/* flex:1 + min-block-size:0 is what lets the body scroll while the head and
   foot stay pinned. Without the min-block-size a flex child refuses to
   shrink below its content and the modal grows past the viewport instead. */
.modal__body  { flex: 1; min-block-size: 0; padding: 0 var(--s-6) var(--s-6); overflow-y: auto; }
.modal__head, .modal__foot { flex: none; }
.modal__foot {
  display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--s-3);
  padding: var(--s-4) var(--s-6);
  border-block-start: 1px solid var(--hairline-soft);
  background: var(--bg-sunken);
}
.modal--wide { inline-size: min(92vw, 760px); }

/* Below 480px a centred modal wastes the edges. Pin it to the bottom as a
   sheet — the thumb is already there, and it gets the full width. */
@media (width < 480px) {
  .modal {
    inline-size: 100%;
    max-block-size: 92dvh;
    margin: auto 0 0;
    border-inline: 0;
    border-block-end: 0;
    border-start-start-radius: var(--r-xl);
    border-start-end-radius: var(--r-xl);
    border-end-start-radius: 0;
    border-end-end-radius: 0;
  }
  .modal[open] { animation: sheet-up var(--dur) var(--ease) both; }
  .modal__foot { padding-block-end: max(var(--s-4), env(safe-area-inset-bottom)); }
}

/* --- Drawer / sheet ------------------------------------------------------
   A dialog pinned to the inline-end edge, full height. Same element as the
   modal — only the geometry differs. */
.drawer {
  inline-size: min(92vw, 420px);
  max-inline-size: none;
  block-size: 100dvh; max-block-size: 100dvh;
  /* Pin to the end edge. The explicit margin is required for the same reason
     as the modal's: base.css has already zeroed the UA `margin: auto`. */
  margin: 0 0 0 auto;
  padding: 0;
  border: 0;
  border-inline-start: 1px solid var(--hairline);
  border-radius: 0;
  background: var(--bg-elevated);
  color: var(--text);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.drawer::backdrop { background: #0000008c; }
@supports (backdrop-filter: blur(1px)) { .drawer::backdrop { backdrop-filter: blur(2px); } }
.drawer[open] { animation: sheet-in var(--dur-slow) var(--ease) both; }
.drawer[open]::backdrop { animation: fade-in var(--dur) var(--ease) both; }
.drawer__body {
  padding: var(--s-6);
  padding-block-end: max(var(--s-6), env(safe-area-inset-bottom));
}
/* Anchor the drawer to the start edge instead. */
.drawer--start {
  margin: 0 auto 0 0;
  border-inline: 0;
  border-inline-end: 1px solid var(--hairline);
}
.drawer--start[open] { animation: sheet-in-start var(--dur-slow) var(--ease) both; }

/* --- Nav sheet -----------------------------------------------------------
   The mobile menu, as a full-height <dialog class="drawer">.

   🔴 It MUST live outside <header class="site-head">, as a sibling. The header
   sets backdrop-filter, and any filter or backdrop-filter makes an element a
   containing block for its position:fixed descendants — so a sheet nested
   inside it gets trapped in the 56px header box in the top corner instead of
   covering the viewport. Using a <dialog> in the top layer sidesteps the
   problem entirely; keeping it out of the header keeps it sidestepped. */
/* The trigger is an .iconbtn in the header's normal flow, sitting beside the
   theme toggle. It was briefly position:fixed, which meant it floated over
   whatever was in the top corner instead of lining up with its sibling. */
.navsheet__trigger { display: grid; }

.navsheet { inline-size: min(86vw, 360px); }
.navsheet__panel {
  display: flex; flex-direction: column;
  min-block-size: 100%;
  padding: var(--s-4) var(--s-6) max(var(--s-8), env(safe-area-inset-bottom));
}
.navsheet__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4);
  min-block-size: var(--nav-h);
  margin-block-end: var(--s-4);
}
.navsheet__title { font-size: var(--fs-sm); font-weight: 600; color: var(--text-3); }

.sheet-row {
  display: flex; align-items: center; justify-content: space-between;
  min-height: 56px;
  border-block-end: 1px solid var(--hairline-soft);
  color: var(--text);
  font-size: 1.0625rem; font-weight: 500;
}
.sheet-row:hover { color: var(--accent); text-decoration: none; }
.sheet-tools {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-4);
  margin-block-start: var(--s-8);
}

/* --- Popover / dropdown menu ---------------------------------------------
   <details> + <summary>. Anchor it with position:relative on the details. */
.menu { position: relative; }
.menu > summary { list-style: none; cursor: pointer; }
.menu > summary::-webkit-details-marker { display: none; }
.menu__list {
  position: absolute;
  inset-block-start: calc(100% + 6px);
  inset-inline-start: 0;
  z-index: 10;
  min-inline-size: 190px;
  padding: 6px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  background: var(--bg-elevated);
  box-shadow: var(--sh-lg);
  animation: pop-in var(--dur-fast) var(--ease) both;
}
.menu__list--end { inset-inline-start: auto; inset-inline-end: 0; }
.menu__list a, .menu__list button {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  inline-size: 100%; min-height: 40px;
  padding: var(--s-2) var(--s-3);
  border: 0; border-radius: var(--r-sm);
  background: none; cursor: pointer;
  color: var(--text-2); font-size: var(--fs-sm); font-weight: 500;
  white-space: nowrap; text-align: start;
}
.menu__list a:hover, .menu__list button:hover {
  color: var(--text); text-decoration: none;
  background: color-mix(in oklab, var(--text) 5%, transparent);
}
.menu__list a[aria-current] { color: var(--text); font-weight: 600; }
.menu__sep { block-size: 1px; margin: 6px 0; background: var(--hairline-soft); }

/* --- Tooltip -------------------------------------------------------------
   Decorative only. Anything essential belongs in visible copy — a tooltip
   is unreachable on touch and unreliable for screen readers. */
.tip { position: relative; display: inline-flex; anchor-name: --tip; }
.tip__bubble {
  position: absolute;
  inset-block-end: calc(100% + 8px);
  inset-inline-start: 50%;
  translate: -50% 0;
  z-index: 20;
  padding: 6px var(--s-3);
  border-radius: var(--r-sm);
  background: var(--text);
  color: var(--bg);
  font-size: var(--fs-xs); line-height: 1.4;
  /* Wrapping, not nowrap: a long single-line bubble is what pushes past the
     viewport edge in the first place. Cap it and let it break. */
  inline-size: max-content;
  max-inline-size: min(260px, 70vw);
  text-align: center; text-wrap: pretty;
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease);
}
.tip:hover .tip__bubble, .tip:focus-within .tip__bubble { opacity: 1; }

/* Manual edge modifiers — the reliable fallback everywhere. Use --end on a
   tip near the inline-end edge, --start near the start, --below under a tip
   in the first row of the viewport. */
.tip--end   .tip__bubble { inset-inline: auto 0; translate: 0 0; text-align: start; }
.tip--start .tip__bubble { inset-inline: 0 auto; translate: 0 0; text-align: start; }
.tip--below .tip__bubble { inset-block: calc(100% + 8px) auto; }

/* Where CSS anchor positioning is supported the browser does the collision
   detection itself and the modifiers above become unnecessary. */
@supports (position-try-fallbacks: flip-block) {
  .tip__bubble {
    position: fixed;
    position-anchor: --tip;
    position-area: block-start center;
    inset: auto; translate: none;
    margin-block-end: 8px;
    position-try-fallbacks: flip-block, block-start span-inline-start, block-start span-inline-end;
  }
}

/* --- Toast ---------------------------------------------------------------
   Stack them bottom-up. Announce with role="status" so it is read aloud. */
/* Top-centre. It clears the sticky header, and it is where the eye already
   is after clicking something — a bottom toast is routinely missed. */
.toasts {
  position: fixed;
  inset-block-start: calc(var(--nav-h) + env(safe-area-inset-top) + var(--s-3));
  inset-inline: var(--s-4);
  z-index: var(--z-toast);
  display: flex; flex-direction: column; gap: var(--s-2);
  align-items: center;
  pointer-events: none;
}
.toast {
  display: flex; align-items: center; gap: var(--s-3);
  inline-size: min(100%, 420px);
  padding: var(--s-3) var(--s-5);
  border: 1px solid var(--hairline);
  border-radius: var(--r-chip);
  background: var(--bg-elevated);
  box-shadow: var(--sh-lg);
  font-size: var(--fs-sm);
  pointer-events: auto;
  animation: toast-in var(--dur) var(--ease) both;
}
.toast__icon { flex: none; color: var(--accent); }
.toast--danger .toast__icon { color: var(--danger); }
.toast--warn   .toast__icon { color: var(--warn); }

/* --- Accordion -----------------------------------------------------------  */
.accordion { border-block-start: 1px solid var(--hairline); }
.accordion__item { border-block-end: 1px solid var(--hairline); }
.accordion__item > summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  min-height: 56px; padding-block: var(--s-3);
  list-style: none; cursor: pointer;
  font-weight: 550; letter-spacing: -0.01em;
}
.accordion__item > summary::-webkit-details-marker { display: none; }
.accordion__item > summary:hover { color: var(--accent); }
.accordion__chev { flex: none; color: var(--text-3); transition: rotate var(--dur) var(--ease); }
.accordion__item[open] .accordion__chev { rotate: 180deg; }
.accordion__body { padding-block-end: var(--s-5); color: var(--text-2); font-size: var(--fs-sm); }

/* --- Animations ----------------------------------------------------------  */
@keyframes fade-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes modal-in { from { opacity: 0; scale: 0.97; } to { opacity: 1; scale: 1; } }
@keyframes sheet-in { from { transform: translateX(100%); } to { transform: none; } }
@keyframes sheet-in-start { from { transform: translateX(-100%); } to { transform: none; } }
@keyframes sheet-up  { from { transform: translateY(100%); } to { transform: none; } }
@keyframes pop-in   { from { opacity: 0; translate: 0 -4px; } to { opacity: 1; translate: 0 0; } }
/* Enters downward now that the stack lives at the top of the viewport. */
@keyframes toast-in { from { opacity: 0; translate: 0 -8px; } to { opacity: 1; translate: 0 0; } }
