/* ── nav-island.css — alerts strip on top, nav floats in as an island on scroll ──
   Home page only (js/nav-island.js?v=10 sets html[data-navmode]; `classic` = the old look, and
   with no attribute nothing here applies). Variants (lab bar): data-navappear, -navwidth,
   -navshape, -navglass, -alerts.

   The island is the existing .nav (same cells, hairline dividers, same menu behaviour)
   re-positioned, so nothing about its markup or nav.js changes. Parked above the viewport
   until `.is-island-on`; ONE transition (a transform slide) handles both directions, so floating out is
   exactly floating in, reversed.

   Two things to remember when editing:
   - no transform / filter on .nav, and backdrop-filter only while it is NOT open: on phones the open
     menu is a position:fixed full-screen panel INSIDE .nav, and any of those would turn .nav into
     its containing block. `top` (not transform) is what animates.
   - every island rule is scoped :not(.is-open):not(.is-closing); an open menu is the
     ordinary full-screen panel from nav.css. */

/* ── Alerts strip ────────────────────────────────────────────────────────── */
.alert-strip { display: none; }
html[data-navmode="island"] .alert-strip,
html[data-alertonly] .alert-strip {
  min-height: var(--alert-h);
  --alert-h: 3.2rem;
  display: block; position: relative; background: var(--fg); color: var(--ground);
  font-family: var(--font-data); font-size: var(--fs-data); letter-spacing: var(--track-data); text-transform: uppercase;
  border-bottom: 1px solid var(--rule);
}
@media (min-width: 48em) { html[data-navmode="island"] .alert-strip, html[data-alertonly] .alert-strip { --alert-h: 4rem; } }
.alert-list { list-style: none; margin: 0; padding: 0; position: relative; height: var(--alert-h); overflow: hidden; }   /* hides the slide's off-screen half */
.alert { position: absolute; inset: 0; opacity: 0; pointer-events: none; background: var(--fg); color: var(--ground); }   /* the sideways slide is a WAAPI animation in nav-island.js */
.alert.is-on { opacity: 1; pointer-events: auto; }
/* tones: each alert paints its own strip (they crossfade). ink = the site's inverse; the others use
   the --alert-* tokens (tokens.css). */
.alert--hophop    { background: var(--alert-hophop);    color: var(--alert-on); }
.alert--resultant { background: var(--alert-resultant); color: var(--alert-on); }
.alert--sillyslices { background: var(--alert-sillyslices); color: var(--alert-on); }
.alert a { display: flex; align-items: center; justify-content: center; gap: .8em 1.2em; height: 100%; min-height: 0; padding: 0 calc(var(--gutter) + 7rem); color: inherit; text-decoration: none; text-align: center; white-space: nowrap; overflow: hidden; }
.alert-label { font-weight: 600; }
.alert-text { overflow: hidden; text-overflow: ellipsis; opacity: .86; }
.alert-cta { text-decoration: underline; text-underline-offset: .4em; }
@media (max-width: 47.99em) { .alert-text, .alert-cta { display: none; } .alert a { padding: 0 calc(var(--gutter) + 6rem); } }
/* prev / count / next, right end of the strip */
.alert-nav { position: absolute; right: var(--gutter); top: 0; bottom: 0; z-index: 2; display: flex; align-items: center; gap: .2rem; color: var(--ground); }
html[data-alerts="rotate"] .alert-list:has(.alert--hophop.is-on) ~ .alert-nav,
html[data-alerts="rotate"] .alert-list:has(.alert--resultant.is-on) ~ .alert-nav { color: var(--alert-on); }
.alert-nav button { min-height: 0; min-width: 0; width: 2.8rem; height: 2.8rem; display: grid; place-items: center; padding: 0; border: 0; background: transparent; color: inherit; font: inherit; font-size: 2rem; line-height: 1; cursor: pointer; opacity: .75; }
.alert-nav button:hover, .alert-nav button:focus-visible { opacity: 1; }
.alert-count { font-size: 1rem; opacity: .65; min-width: 3ch; text-align: center; }
@media (max-width: 47.99em) { .alert-count { display: none; } }
/* stack: every alert visible, one thin row each, no arrows */
html[data-alerts="stack"] .alert-list { height: auto; overflow: visible; }
html[data-alerts="stack"] .alert { position: static; opacity: 1; pointer-events: auto; height: var(--alert-h); transition: none; }
html[data-alerts="stack"] .alert + .alert { border-top: 1px solid color-mix(in srgb, var(--ground) 25%, transparent); }
html[data-alerts="stack"] .alert-nav { display: none; }
html[data-alerts="stack"] .alert a { padding: 0 var(--gutter); }
@media (max-width: 47.99em) { html[data-alerts="stack"] .alert-text { display: inline; } html[data-alerts="stack"] .alert-cta { display: none; } }
/* pinned All-Access: its own permanent thin row under the rotating one */
.alert-pin .alert a { padding: 0 var(--gutter); }
.alert-pin { border-top: 1px solid color-mix(in srgb, var(--ground) 25%, transparent); }

html[data-navmode="island"] .access-banner,
html[data-navmode="island"] .legal-notice { display: none; }   /* the alerts strip covers both */
html[data-navmode="island"] .sticky-head { position: static; }

/* ── The island ─────────────────────────────────────────────────────────── */
html[data-navmode="island"] {
  --isl-ease: cubic-bezier(.45, 0, .2, 1);
  --isl-dur: 520ms; --isl-dur-out: 240ms; --isl-fade: ease-out;
  --isl-top: var(--s3);
  --isl-bg: 74%; --isl-blur: 16px;
}
html[data-navmode="island"][data-navglass="solid"] { --isl-bg: 100%; --isl-blur: 0px; }
html[data-navmode="island"][data-navglass="clear"] { --isl-bg: 42%;  --isl-blur: 22px; }
html[data-navmode="island"][data-navshape="square"] { --isl-r: 0; }
html[data-navmode="island"][data-navshape="soft"], html[data-navmode="island"]:not([data-navshape]) { --isl-r: var(--r-card); }
html[data-navmode="island"][data-navshape="pill"] { --isl-r: var(--r-tray); }

html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) {
  position: fixed; z-index: 90; left: 0; right: 0; margin-inline: auto;
  /* Parked = slid fully above the viewport by a GPU transform (not by animating `top`, which re-lays-out every
     frame and stutters on phones). opacity flips only at the ends of the slide (no fade: a fade on top of the
     backdrop blur glitches on iOS). Open/closing menu states are excluded by :not(), so the transform never
     reaches the full-screen panel. */
  top: var(--isl-top); transform: translate3d(0, -1.2rem, 0); /* a short drop plus a fade, not a fly-in from off-screen */
  opacity: 0; pointer-events: none;
  width: fit-content; max-width: calc(100% - 2 * var(--gutter));
  isolation: isolate;
  border-radius: var(--isl-r, var(--r-card));
  --nav-box: 6.4rem; --dial: 4.4rem;
  transition: transform var(--isl-dur) var(--isl-ease), opacity var(--isl-dur) var(--isl-fade);
}
html[data-navmode="island"] .nav.is-island-on:not(.is-open):not(.is-closing),
html[data-navmode="island"] .nav:focus-within:not(.is-open):not(.is-closing) { transform: none; opacity: 1; pointer-events: auto; transition: transform var(--isl-dur) var(--isl-ease), opacity var(--isl-dur) var(--isl-fade); }
@media (prefers-reduced-motion: reduce) { html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) { transition: none !important; } }

/* the glass: ring (the site's hairline border language) + soft lift. On .nav itself (a pseudo-element
   with backdrop-filter did not blur in Chromium). Safe for the phone menu: the open/closing states are
   excluded by :not(), so the full-screen panel never has a backdrop-filter ancestor. */
html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) {
  background: color-mix(in srgb, var(--ground) var(--isl-bg), transparent);
  -webkit-backdrop-filter: blur(var(--isl-blur)) saturate(1.25); backdrop-filter: blur(var(--isl-blur)) saturate(1.25);
  box-shadow: 0 0 0 1px var(--rule-strong), var(--shadow-float);
}
/* cells: dividers stay, bottom rules go (the ring closes the shape) */
html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) > *,
html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) .nav-brand,
html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) .nav-brand-group > .theme-knob { border-bottom: 0; }
html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) > :last-child { border-right: 0; }
html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) .knob-tip { display: none; }

/* layout: a flex row from 40em up (the cell count is variable: the All-Access cell is optional);
   phones keep nav.css's three-column bar. fit = as wide as its cells; mid / wide stretch the links. */
@media (min-width: 40em) {
  html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) { display: flex; flex-wrap: wrap; align-items: stretch; width: fit-content; }
  html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) > * { flex: 0 0 auto; }
  html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) .nav-brand { grid-column: auto; }
  html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) .theme-knob { width: var(--nav-box); justify-content: center; }
  html[data-navmode="island"][data-navwidth="mid"]  .nav:not(.is-open):not(.is-closing) { width: min(100rem, calc(100% - 2 * var(--gutter))); }
  html[data-navmode="island"][data-navwidth="wide"] .nav:not(.is-open):not(.is-closing) { width: calc(100% - 2 * var(--gutter)); }
  html[data-navmode="island"]:is([data-navwidth="mid"], [data-navwidth="wide"]) .nav:not(.is-open):not(.is-closing) > .nav-link { flex: 1 1 0; }
}
@media (max-width: 39.99em) {
  html[data-navmode="island"] .nav:not(.is-open):not(.is-closing) { width: calc(100% - 2 * var(--gutter)); --isl-top: var(--s2); border-bottom: 0; }
}
/* landing on #plugins: clear the island, not the old banner + nav */
html[data-navmode="island"] #plugins.rx-cathead { scroll-margin-top: calc(var(--island-h, 8rem) + var(--s6)); }

/* Failsafe (the page must survive a blocked script): index.html ships data-navmode="island" so first paint
   has no layout shift. If nav-island.js never runs (data-island-ready never appears), after 3s the empty
   announcement slot collapses and the nav is revealed in its island position. */
@keyframes island-failsafe-nav { to { top: var(--isl-top); opacity: 1; pointer-events: auto; } }
@keyframes island-failsafe-slot { to { min-height: 0; height: 0; border: 0; } }
html[data-navmode="island"]:not([data-island-ready]) .nav:not(.is-open):not(.is-closing) { animation: island-failsafe-nav 0s linear 3s forwards; }
html[data-navmode="island"]:not([data-island-ready]) .alert-strip[data-alert-slot] { animation: island-failsafe-slot 0s linear 3s forwards; }

/* The announcement slot is in the page's HTML (so first paint has no layout shift) but is empty until
   nav-island.js fills it ~0.1s later; empty, it was painted with the strip's bright background, so every
   load flashed a white bar at the top before the real alert arrived. Empty = the page's own dark ground. */
html[data-navmode="island"] .alert-strip[data-alert-slot]:not(:has(.alert-list)),
html[data-alertonly] .alert-strip[data-alert-slot]:not(:has(.alert-list)) { background: var(--ground); }
/* phones: a slower, softer glide so the bar doesn't snap in on a quick flick (long eases are in the redesign motion brief) */
/* phones: quick exit (140ms) so the in-page bar returns fast */
@media (max-width: 47.99em) { html[data-navmode="island"] { --isl-dur-out: 140ms; } }

/* Homepage (strip only, static nav + nav-float): the strip covers the terms notice and the All-Access pitch. */
html[data-alertonly="home"] .legal-notice, html[data-alertonly="home"] [data-access-banner] { display: none; }
