/* ==========================================================================
   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.

   🔴 Its display comes from .iconbtn. Do not restate it here — this file only
   takes it away above the nav breakpoint. And that hide rule must live HERE,
   not in layout.css beside the rest of the header, because layout.css loads
   third and components.css fourth: a `display: none` written there is beaten
   by .iconbtn's `inline-flex` on source order alone. Same 0,1,0 specificity,
   later file wins, and wrapping it in a media query adds nothing. That is
   what kept the hamburger on screen beside the full nav at every width until
   2026-09-06.

   Hide the trigger, not the sheet: the sheet is a <dialog>, and its own
   display is controlled by the UA's dialog:not([open]) rule. */
@media (width >= 900px) {
  .navsheet__trigger { display: none; }
}

.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; } }
