/* =============================================================================
   Header, mobile navigation and the auth modal.

   Loaded after components.css and deliberately overrides the earlier header rules:
   the previous header put every nav link inline at every width, which on a phone
   produced three stacked rows of links and a 210px-tall bar. That is the single
   worst thing about the old mobile experience.
   ============================================================================= */

/* --- Header ------------------------------------------------------------------- */
.site-header {
  transition: background var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.site-header.is-scrolled {
  background: rgba(14, 14, 16, .92);
  backdrop-filter: blur(10px);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .08), var(--shadow-2);
}

.site-header__inner { gap: var(--space-xs); }

/* Nav links get a sliding underline rather than a colour change — a colour-only
   hover is invisible to anyone who cannot distinguish the two purples. */
.site-nav--desktop a { position: relative; }
.site-nav--desktop a::after {
  content: "";
  position: absolute;
  left: var(--space-2xs);
  right: var(--space-2xs);
  bottom: 10px;
  height: 2px;
  background: var(--brand-400);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .28s var(--ease);
}
.site-nav--desktop a:hover::after,
.site-nav--desktop a:focus-visible::after,
.site-nav--desktop a[aria-current="page"]::after { transform: scaleX(1); }

/* Below 75rem the inline nav goes away and the hamburger takes over.
   This was briefly 80rem, because at its normal spacing the row needs 1280px and
   "Contact Us" wrapped under the logo from 1200 to 1279. Raising the breakpoint fixed the
   wrap by showing a hamburger on a 1256px desktop window, which is the wrong trade — a
   laptop is not a phone. The row fits at 75rem again because the four secondary pages
   collapse into the "More" disclosure below and only the six services stay inline.
   That is the inverse of the old site's "More", which buried Karaoke, Jukebox Bingo and
   Foam Parties — the two services running 22 nights a month, which MILESTONE-1-SPEC C1
   exists to surface. Every service is still one click at every width above the breakpoint.
   Keep this value and components.css in step. */
.burger { display: none; }

@media (max-width: 75rem) {
  .site-nav--desktop { display: none; }
  .burger { display: inline-flex; }
  .site-header__inner { flex-wrap: nowrap; }
  .site-header { position: sticky; top: 0; }

  /* 64px, not the 80px the desktop bar uses. With the nav gone the bar holds a 32px
     logo and two 44px controls, and 80px of chrome pinned to the top of a phone is a
     fifth of the viewport spent on a row with three things in it. 64px is the height
     a mobile app bar is expected to be. The line above claimed "~64px tall" before
     this existed, which is why it could stay sticky — now that is actually true.

     Set as the token so hero.css's calc(100svh - var(--header-h)) follows it; the
     hero would otherwise reserve 16px it no longer needs.

     On :root, not bare inside the media query — a custom property still needs a
     selector, and a loose declaration here is simply dropped. */
  :root { --header-h: 4rem; }
}

@media (max-width: 30rem) {
  .site-header__logo .logo { height: 32px; }
}

/* --- Account button ----------------------------------------------------------- */
.account-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border: 0;
  background: none;
  color: var(--ink-000);
  cursor: pointer;
  border-radius: 50%;
}
.account-btn__avatar {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.28);
  background: rgba(255,255,255,.08);
  font-family: var(--font-display);
  font-size: var(--step--1);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
.account-btn:hover .account-btn__avatar {
  background: var(--brand-600);
  border-color: var(--brand-600);
  transform: scale(1.06);
}

/* --- Hamburger ---------------------------------------------------------------- */
.burger {
  position: relative;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--ink-000);
  border-radius: var(--radius-md);
}
/* The same 34px disc the account control wears. These two sit side by side as peers,
   and one having a ring while the other floated bare made them read as different
   classes of thing. A pseudo-element rather than markup, and rather than restyling
   .burger itself, because the button stays a 44px tap target while the visible disc
   is 34px — exactly how .account-btn and .account-btn__avatar are separated. */
.burger::before {
  content: "";
  position: absolute;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,.28);
  background: rgba(255,255,255,.08);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
.burger:hover::before {
  background: var(--brand-600);
  border-color: var(--brand-600);
  transform: scale(1.06);
}
/* Open state fills too, not just hover. This control lives on touch, where there is no
   hover — without this an open menu's button looks the same as a closed one apart from
   the bars having crossed, which is the smallest possible signal for the largest state
   change on the page. */
.burger[aria-expanded="true"]::before {
  background: var(--brand-600);
  border-color: var(--brand-600);
}
/* 18px, not 22px: inside the 34px disc the wider bars ran almost to the edge while
   the account glyph sat comfortably inside its own. Width only — the gap stays 5px
   because the cross transform below is derived from it (bar height 2 + gap 5 = the
   7px each outer bar travels). */
.burger__box { position: relative; display: grid; gap: 5px; width: 18px; }
.burger__bar {
  height: 2px;
  background: currentColor;
  border-radius: 2px;
  transition: transform .3s var(--ease), opacity .2s var(--ease);
}
/* Morphs into a cross, so the control that opened the panel is visibly the one that
   closes it. */
[aria-expanded="true"] .burger__bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
[aria-expanded="true"] .burger__bar:nth-child(2) { opacity: 0; }
[aria-expanded="true"] .burger__bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* --- Mobile panel ------------------------------------------------------------- */
.mobile-nav {
  position: fixed;
  inset: 64px 0 0;
  z-index: 40;
  background: var(--ink-900);
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity .28s var(--ease), transform .28s var(--ease);
}
.mobile-nav.is-open { opacity: 1; transform: none; }
.mobile-nav__inner { padding-block: var(--space-l) var(--space-2xl); }

.mobile-nav__heading {
  font-size: var(--step--2);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--brand-200);
  margin: var(--space-l) 0 var(--space-2xs);
}
.mobile-nav__heading:first-child { margin-top: 0; }

/* The event types are the primary journey, so they are cards on a phone too, not a
   list item lost among the service links. */
.mobile-nav__events {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-2xs);
  list-style: none; margin: 0; padding: 0;
}
.mobile-nav__events a {
  display: flex;
  align-items: center;
  min-height: 56px;
  padding: var(--space-2xs) var(--space-s);
  border-radius: var(--radius-md);
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.10);
  color: var(--ink-000);
  font-weight: var(--weight-bold);
  font-size: var(--step--1);
  text-decoration: none;
}
.mobile-nav__events a:hover { background: var(--brand-700); border-color: var(--brand-600); }

.mobile-nav__links { list-style: none; margin: 0; padding: 0; }
.mobile-nav__links a {
  display: flex;
  align-items: center;
  min-height: var(--tap-min);
  padding-block: var(--space-3xs);
  color: rgba(255,255,255,.9);
  font-size: var(--step-1);
  text-decoration: none;
  border-bottom: 1px solid rgba(255,255,255,.08);
}
.mobile-nav__links a[aria-current="page"] { color: var(--brand-200); }

.mobile-nav__foot {
  display: grid;
  gap: var(--space-s);
  margin-top: var(--space-xl);
}
.mobile-nav__foot .btn { justify-content: center; text-align: center; }
.mobile-nav__phone {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  min-height: var(--tap-min);
  color: var(--ink-000);
  font-weight: var(--weight-bold);
  text-decoration: none;
}

/* Lock the page behind the panel. */
html.nav-open, html.nav-open body { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .mobile-nav, .burger__bar, .site-nav--desktop a::after,
  .account-btn__avatar { transition: none; }
}

/* --- Auth modal --------------------------------------------------------------- */
.authm {
  border: 0;
  padding: 0;
  background: transparent;
  max-width: min(92vw, 27rem);
  width: 100%;
}
.authm::backdrop {
  background: rgba(8, 4, 12, .68);
  backdrop-filter: blur(3px);
}
.authm[open] { animation: authm-in .26s var(--ease); }
.authm[open]::backdrop { animation: fade-in .26s var(--ease); }
@keyframes authm-in {
  from { opacity: 0; transform: translateY(12px) scale(.98); }
  to   { opacity: 1; transform: none; }
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .authm[open], .authm[open]::backdrop { animation: none; }
}

.authm__panel {
  position: relative;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-l);
  box-shadow: var(--shadow-3);
}
@media (forced-colors: active) { .authm__panel { border-color: CanvasText; } }

/* The logo is drawn white -- it was made for the near-black header and footer, and
   carries color="#ffffff" as a presentation attribute. On this panel that is white on
   white, i.e. nothing at all. CSS beats a presentation attribute, so recolouring here is
   enough; --brand-ink rather than a fixed purple because it flips with the theme
   (brand-600 on light, brand-200 on dark) and is already covered by check_contrast.
   Inset on the right so it cannot run under the close button. */
.authm__brand {
  display: flex;
  justify-content: center;
  margin: 0 var(--tap-min) var(--space-s);
}
.authm__brand .logo { height: 34px; width: auto; color: var(--brand-ink); }

.authm__close {
  position: absolute;
  top: var(--space-2xs);
  right: var(--space-2xs);
  width: var(--tap-min); height: var(--tap-min);
  display: grid; place-items: center;
  border: 0; background: none; cursor: pointer;
  color: var(--text-muted);
  border-radius: 50%;
}
.authm__close:hover { background: var(--surface-muted); color: var(--text); }

.authm__tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  padding: 4px;
  background: var(--surface-muted);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-m);
  max-width: 17rem;
}
.authm__tab {
  min-height: 40px;
  border: 0;
  border-radius: calc(var(--radius-md) - 3px);
  background: none;
  font: inherit;
  font-size: var(--step--1);
  font-weight: var(--weight-bold);
  color: var(--text-muted);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.authm__tab.is-active { background: var(--surface); color: var(--brand-ink-strong); box-shadow: var(--shadow-1); }

.authm__title { font-size: var(--step-2); letter-spacing: var(--tracking-tight); margin: 0 0 var(--space-3xs); }
.authm__note, .authm__who {
  margin: 0 0 var(--space-m);
  color: var(--text-muted);
  font-size: var(--step--1);
}
.authm__who { font-weight: var(--weight-bold); color: var(--text); }

.authm__form { display: grid; gap: var(--space-3xs); }
.authm__form label {
  font-size: var(--step--1);
  font-weight: var(--weight-bold);
  margin-top: var(--space-2xs);
}
.authm__form input {
  width: 100%;
  min-height: var(--tap-min);
  padding: var(--space-2xs) var(--space-xs);
  border: 1px solid var(--border-control);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: max(1rem, var(--step-0));   /* 16px floor stops iOS zooming on focus */
}
.authm__form input:focus-visible {
  outline: 3px solid var(--brand-500);
  outline-offset: 1px;
  border-color: var(--brand-500);
}
.authm__wide { width: 100%; justify-content: center; margin-top: var(--space-s); }

.authm__links { display: grid; gap: 2px; margin-bottom: var(--space-s); }
.authm__link {
  display: flex; align-items: center;
  min-height: var(--tap-min);
  padding-inline: var(--space-2xs);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: var(--step--1);
  text-decoration: none;
}
.authm__link:hover { background: var(--brand-wash); color: var(--brand-ink-strong); }

.authm__alt { margin: var(--space-s) 0 0; font-size: var(--step--1); }
.authm__alt--muted { color: var(--text-muted); }
.authm__pane[hidden] { display: none; }

/* --- Flash messages -------------------------------------------------------------
   One region, at the top of <main>, on every page.

   It replaces .profile__messages and .auth-card__messages, which between them covered
   two pages out of eighteen. Everywhere else the messages were never rendered, and a
   message that is never rendered is never consumed -- so they accumulated in the session
   and arrived in a heap on whichever account page the visitor reached next.

   Sized like a notice rather than a banner: this is confirmation of something the person
   just did, and it should not be the largest thing on the page they asked for. */
/* A toast at the top right, out of the document flow.
   -------------------------------------------------------------------------------
   This used to be a block at the top of <main>, which meant "Successfully signed in
   as ..." pushed the whole homepage hero down by its own height and left a band of
   empty page above the photograph. Fixed, so it floats over the page instead of
   rearranging it.

   Sits under the header rather than over it: z-index 35 is above ordinary content and
   below the mobile menu (40), the header (50) and the dropdown panels (60), so it can
   never cover the navigation a visitor is reaching for. */
.site-messages {
  position: fixed;
  top: calc(var(--header-h) + var(--space-2xs));
  right: var(--space-s);
  left: var(--space-s);
  z-index: 35;
  display: grid;
  gap: var(--space-2xs);
  justify-items: end;
  /* The strip is a positioner, not a surface. Without this the invisible full-width
     box would swallow every click along the top of the page -- the same defect the
     concierge launcher had. Each toast opts back in. */
  pointer-events: none;
}
/* Full width on a phone, a column at the right once there is room for one. */
@media (min-width: 34rem) {
  .site-messages { left: auto; width: min(26rem, calc(100vw - 2 * var(--space-s))); }
}
.site-messages__item {
  pointer-events: auto;
  width: 100%;
  display: flex;
  align-items: flex-start;
  gap: var(--space-2xs);
  padding: var(--space-xs) var(--space-s);
  border-radius: var(--radius-md);
  background: var(--surface);
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--brand-500);
  box-shadow: var(--shadow-3);
  color: var(--text);
  font-size: var(--step--1);
  animation: toast-in var(--dur) var(--ease) both;
}
.site-messages__text { margin: 0; flex: 1; min-width: 0; overflow-wrap: anywhere; }
.site-messages__close {
  flex: none;
  display: grid;
  place-items: center;
  width: var(--tap-min);
  height: var(--tap-min);
  margin: calc(var(--space-2xs) * -1) calc(var(--space-2xs) * -1) 0 0;
  padding: 0;
  border: 0;
  background: none;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  cursor: pointer;
}
.site-messages__close:is(:hover, :focus-visible) { color: var(--text); }
.site-messages__close .icon { width: 16px; height: 16px; }
/* Failure does not get to look like confirmation. allauth raises both through the same
   channel, and "Your password could not be changed" in brand purple reads as success at
   a glance. Both tokens flip with the theme. */
.site-messages__item--error,
.site-messages__item--warning {
  border-inline-start-color: var(--danger);
  color: var(--danger);
  font-weight: var(--weight-semibold);
}
.site-messages__item.is-leaving { animation: toast-out var(--dur) var(--ease) both; }
@keyframes toast-in  { from { opacity: 0; transform: translateY(-.4rem); } }
@keyframes toast-out { to   { opacity: 0; transform: translateY(-.4rem); } }
@media (prefers-reduced-motion: reduce) {
  .site-messages__item,
  .site-messages__item.is-leaving { animation: none; }
}
@media (forced-colors: active) { .site-messages__item { border-color: CanvasText; } }

/* --- Ghost button -------------------------------------------------------------
   The secondary hero action. .btn--ghost was used in templates before it existed, so
   those links rendered as plain text and did not read as controls at all. On a dark
   hero it is an outlined button; on a light surface it inverts, because a white
   outline on white is invisible. */
.btn--ghost {
  background: transparent;
  color: var(--ink-000);
  border: 1.5px solid rgba(255, 255, 255, .38);
}
.btn--ghost:hover {
  background: rgba(255, 255, 255, .12);
  border-color: rgba(255, 255, 255, .7);
  color: var(--ink-000);
}
.block--cta .btn--ghost,
.bg-brand .btn--ghost { border-color: rgba(255, 255, 255, .55); }

/* On a light background the same class has to flip, or it disappears. */
.section:not(.bg-dark):not(.bg-brand) .btn--ghost {
  color: var(--brand-ink-strong);
  border-color: var(--brand-300, var(--brand-400));
}
.section:not(.bg-dark):not(.bg-brand) .btn--ghost:hover {
  background: var(--brand-wash);
  color: var(--brand-ink-strong);
}
@media (forced-colors: active) { .btn--ghost { border-color: ButtonText; } }

/* --- Destructive button ----------------------------------------------------------
   Remove an email address, deactivate two-factor. allauth tags these `danger` and this
   site had nothing to map that onto, so before allauth/elements/button.html existed they
   rendered as browser defaults and afterwards they would have rendered as the primary
   CTA — a delete button that looks exactly like "Save" is how somebody removes the
   address their account is matched on by accident.

   Outlined rather than filled, and coloured from --danger rather than from white-on-red,
   because --danger flips from #b3261e to #ff9a90 in the dark theme: one filled rule
   cannot serve both (white on the dark-theme salmon fails outright), while the outline
   reads correctly in each. 5.90:1 on white, and the light red on the dark surface is
   higher still. */
.btn--danger {
  background: transparent;
  color: var(--danger);
  border-color: var(--danger);
}
.btn--danger:hover {
  background: var(--danger-wash);
  color: var(--danger);
  border-color: var(--danger);
}
@media (forced-colors: active) { .btn--danger { border-color: ButtonText; } }

/* A link allauth tagged `link` — "back to sign in" and friends. It is a link, not a
   button, but it stands alone in its own line, so WCAG 2.5.8's exception for links inside
   a sentence does not cover it and it needs a real target height. Same rule as
   .auth-card__alt a, which exists for exactly this. */
.auth-card__inline-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
}

/* --- Cross-document page transitions ------------------------------------------
   Clicking a header link now cross-fades between pages instead of the browser's
   white flash. This is the native View Transitions API in its cross-document form:
   no router, no JavaScript, no single-page-app. Browsers without it navigate
   exactly as before — there is nothing to fall back FROM, which is why this is
   safe on a server-rendered site whose SEO is the whole point of the rebuild. */
@view-transition { navigation: auto; }

/* The header must not fade with the rest of the page, or it flickers on every
   navigation. Naming it makes the browser treat it as the same element across
   documents and animate it independently — which here means not at all. */
.site-header { view-transition-name: site-header; }
.site-footer { view-transition-name: site-footer; }

::view-transition-old(site-header),
::view-transition-new(site-header),
::view-transition-old(site-footer),
::view-transition-new(site-footer) { animation: none; mix-blend-mode: normal; }

::view-transition-old(root) { animation: vt-out .18s var(--ease) both; }
::view-transition-new(root) { animation: vt-in .28s var(--ease) both; }

@keyframes vt-out { to { opacity: 0; transform: translateY(-6px); } }
@keyframes vt-in { from { opacity: 0; transform: translateY(8px); } }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
}

/* Buttons and links get a press response. Without it a tap on a phone feels dead
   for the 300ms before the next page paints. */
.btn { transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
                   transform .12s var(--ease), box-shadow var(--dur) var(--ease); }
.btn:active { transform: translateY(1px) scale(.985); }
.site-nav--desktop a:active,
.mobile-nav__links a:active,
.mobile-nav__events a:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) {
  .btn, .btn:active { transition: none; transform: none; }
}

/* The fixed point of the site should feel calm while the content moves beneath it.
   A subtle glass edge appears only after scrolling, then the bar tightens slightly on
   wide screens. Mobile keeps a stable 64px target area. */
.site-header {
  border-bottom: 1px solid transparent;
  transition: background .28s var(--ease), border-color .28s var(--ease),
              box-shadow .28s var(--ease);
}
.site-header.is-scrolled {
  background: rgba(22,22,22,.94);
  border-bottom-color: rgba(255,255,255,.10);
  box-shadow: 0 10px 32px rgba(0,0,0,.16);
  backdrop-filter: blur(14px);
}
@media (min-width: 75.01rem) {
  .site-header__inner { transition: min-height .28s var(--ease), padding .28s var(--ease); }
  .site-header.is-scrolled .site-header__inner { min-height: 70px; padding-block: var(--space-3xs); }
}
@media (prefers-reduced-motion: reduce) {
  .site-header, .site-header__inner { transition: none; }
}

/* --- Header overflow menu -------------------------------------------------------
   The nav grew to ten items alongside two calls to action and an account control, and
   was wrapping onto a second row at every viewport. Services stay inline; the secondary
   pages sit under here. Built on <details> like the account control, so the browser owns
   the open state and it works with JavaScript off. */
.nav-menu { position: relative; }
.nav-menu > details > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  min-height: var(--tap-min);
  padding-inline: var(--space-2xs);
  border-radius: var(--radius-md);
  color: var(--text-on-inverse);
  font-size: var(--step--1);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  white-space: nowrap;
  cursor: pointer;
  list-style: none;                 /* Safari still paints a triangle without this */
  transition: background var(--dur) var(--ease);
}
.nav-menu > details > summary::-webkit-details-marker { display: none; }
.nav-menu > details > summary:hover { background: rgba(255,255,255,.10); }
.nav-menu > details[open] > summary .icon--chevron { transform: rotate(180deg); }
.nav-menu .icon--chevron { transition: transform var(--dur) var(--ease); }

.nav-menu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + var(--space-3xs));
  z-index: 60;
  min-width: 13rem;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2xs);
  margin: 0;
  list-style: none;
  background: var(--ink-800);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-3);
}
.nav-menu__panel a {
  display: flex;
  align-items: center;
  min-height: var(--tap-min);
  padding-inline: var(--space-xs);
  border-radius: var(--radius-sm);
  color: var(--text-on-inverse);
  text-decoration: none;
  white-space: nowrap;
}
.nav-menu__panel a:hover { background: rgba(255,255,255,.10); }
.nav-menu__panel a[aria-current="page"] { background: var(--brand-500); }


/* --- Account menu ------------------------------------------------------------- */
/* The signed-in half of what used to be the auth modal. Same <details> mechanics and the
   same dismissal JS as .nav-menu, so only the trigger and the panel's contents differ:
   the trigger is the 34px avatar disc rather than a text label, and the panel carries a
   header and a form as well as links. */
.account-menu { position: relative; display: inline-flex; }
.account-menu > details > summary {
  list-style: none;
  cursor: pointer;
}
.account-menu > details > summary::-webkit-details-marker { display: none; }
/* The disc reads as pressed while its menu is open — without it the only feedback is the
   panel itself, which on a phone can be most of the screen and easy to mistake for a
   page. */
.account-menu > details[open] > summary .account-btn__avatar {
  background: var(--brand-600);
  border-color: var(--brand-600);
}

.account-menu__panel {
  position: absolute;
  right: 0;
  top: calc(100% + var(--space-3xs));
  z-index: 60;
  min-width: 15rem;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2xs);
  background: var(--ink-800);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-3);
}
.account-menu__who {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  padding: var(--space-2xs) var(--space-xs) var(--space-xs);
  border-bottom: 1px solid rgba(255,255,255,.12);
  margin-bottom: var(--space-3xs);
}
.account-menu__label {
  font-size: var(--step--2);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: rgba(255,255,255,.62);
}
.account-menu__email {
  font-size: var(--step--1);
  font-weight: var(--weight-semibold);
  color: var(--text-on-inverse);
  /* An email address is one unbroken token and will happily push the panel wider than
     the viewport on a phone. */
  overflow-wrap: anywhere;
}
.account-menu__link {
  display: flex;
  align-items: center;
  min-height: var(--tap-min);
  padding-inline: var(--space-xs);
  border-radius: var(--radius-sm);
  color: var(--text-on-inverse);
  text-decoration: none;
  white-space: nowrap;
}
/* The colour has to be repeated on every state, and that is not belt-and-braces.
   `a:hover` in base.css sets --link-hover (a deep brand purple, for links on a white
   page) and its specificity is (0,1,1). Every sibling menu outranks it by accident:
   `.site-nav a` and `.nav-menu__panel a` name the element too, so they tie and win on
   source order. This one is a bare class, (0,1,0), so it LOSES — and the panel's own
   colour was dropped on hover for deep purple on a near-black panel: 1.07:1, measured,
   against the 4.5:1 AA needs. The link went blank under the cursor.
   The same trap was patched once already at .site-footer .site-nav a:hover. */
.account-menu__link:hover,
.account-menu__link:focus,
.account-menu__link:focus-visible,
.account-menu__link:active { color: var(--text-on-inverse); }
.account-menu__link:hover { background: rgba(255,255,255,.10); }
/* Appearance, in the account panel.

   The panel is a DARK surface in both themes (--ink-800), so this control is styled
   against that rather than against the page — which is why it uses white-alpha values
   and not --surface tokens. It is one of the few places where "dark" is not a theme,
   it is just what the thing is.

   The radio itself is hidden with appearance:none rather than display:none: a
   display:none input is removed from the accessibility tree and cannot be reached by
   the keyboard, which would take the arrow-key behaviour the fieldset was chosen for
   and throw it away. :focus-visible is drawn on the LABEL, since that is what a
   visitor sees. */
.theme-choice {
  margin: var(--space-2xs) 0 0;
  padding: var(--space-2xs) 0 0;
  border: 0;
  border-top: 1px solid rgba(255,255,255,.12);
}
.theme-choice__legend {
  padding: 0 0 var(--space-3xs);
  color: rgba(255,255,255,.66);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
}
.theme-choice__options {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  padding: 2px;
  border-radius: var(--radius-pill);
  background: rgba(255,255,255,.08);
}
.theme-choice__option {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 32px;
  border-radius: var(--radius-pill);
  color: rgba(255,255,255,.78);
  font-size: var(--step--1);
  font-weight: var(--weight-semibold);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.theme-choice__option input {
  position: absolute;
  width: 1px; height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}
.theme-choice__option:hover { color: var(--ink-000); background: rgba(255,255,255,.10); }
.theme-choice__option:has(input:checked) {
  background: var(--brand-400);
  color: var(--ink-000);
}
.theme-choice__option:has(input:focus-visible) {
  outline: 2px solid var(--focus-ring-on-brand);
  outline-offset: 1px;
}
.account-menu__link[aria-current="page"] { background: var(--brand-500); }
.account-menu__signout {
  margin: var(--space-3xs) 0 0;
  padding-top: var(--space-3xs);
  border-top: 1px solid rgba(255,255,255,.12);
}
.account-menu__wide { width: 100%; justify-content: center; }

/* On a narrow phone the panel would otherwise hang off the right edge, because it is
   anchored to a control sitting in the last 44px of the bar. */
@media (max-width: 26rem) {
  .account-menu__panel {
    position: fixed;
    left: var(--space-xs);
    right: var(--space-xs);
    top: calc(var(--header-h) + var(--space-3xs));
    min-width: 0;
  }
}


/* --- Menu open / close motion ------------------------------------------------- */
/* Both header menus and the account menu, one rule.
 *
 * An ANIMATION, not a transition. A transition needs the element to exist in its start
 * state first, and <details> inserts its panel already open — there is nothing to
 * transition from. An animation runs on appearance, which is exactly the moment wanted.
 *
 * The way out is the harder half: <details> removes the panel the instant `open` flips,
 * so nothing can animate. nav.js adds .is-closing, lets this play, and only then flips
 * the attribute. transform-origin sits at the top because the panel hangs from the bar —
 * scaling from its centre reads as the menu growing out of the middle of the page. */
@keyframes nav-menu-in {
  from { opacity: 0; transform: translateY(-6px) scale(.98); }
  to   { opacity: 1; transform: none; }
}
@keyframes nav-menu-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-6px) scale(.98); }
}

.nav-menu > details[open] > .nav-menu__panel,
.account-menu > details[open] > .account-menu__panel {
  transform-origin: top center;
  animation: nav-menu-in .16s var(--ease) both;
}
.nav-menu > details.is-closing > .nav-menu__panel,
.account-menu > details.is-closing > .account-menu__panel {
  transform-origin: top center;
  animation: nav-menu-out .14s var(--ease) both;
  /* The panel is on its way out and must not swallow the click that follows it. */
  pointer-events: none;
}

/* The chevron follows the panel rather than the attribute: while .is-closing is still
   set, `open` is technically true, so without this the arrow would sit flipped for the
   whole of the closing animation and snap back at the end. */
.nav-menu > details.is-closing > summary .icon--chevron { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .nav-menu > details[open] > .nav-menu__panel,
  .account-menu > details[open] > .account-menu__panel,
  .nav-menu > details.is-closing > .nav-menu__panel,
  .account-menu > details.is-closing > .account-menu__panel {
    animation: none;
  }
}

/* The funnel is a tool, not an occasion — the six above it are things a visitor is
   planning, this is the thing that helps them choose. Separated the way the account
   menu separates Sign out from the links above it. */
/* The rule divides the standalone item from the occasions, so it has to sit on whichever
   side the occasions are on. It moved from the bottom of the menu to the top, and a
   border-top on a first child draws a line against the panel's own edge instead. */
.nav-menu__panel .nav-menu__standalone:last-child {
  margin-top: var(--space-3xs);
  padding-top: var(--space-3xs);
  border-top: 1px solid rgba(255,255,255,.12);
}
.nav-menu__panel .nav-menu__standalone:first-child {
  margin-bottom: var(--space-3xs);
  padding-bottom: var(--space-3xs);
  border-bottom: 1px solid rgba(255,255,255,.12);
}


/* The same separation in the two other places the plan menu is rendered.
   `standalone` was carried only by the desktop panel, so on a phone and in the footer
   "Start Plan" sat first in a list of occasions with nothing marking it as the odd one
   out — an imperative reading as though it were another kind of party. Same idea, drawn
   against each surface's own ground rather than the panel's dark one. */
.mobile-nav__events .mobile-nav__standalone,
.site-footer__col .site-footer__standalone {
  margin-bottom: var(--space-3xs);
  padding-bottom: var(--space-3xs);
  border-bottom: 1px solid currentColor;
  border-bottom-color: color-mix(in srgb, currentColor 18%, transparent);
}

/* The described variant of the menu panel — "What we do" only. Wider, because a line of
   description in a 13rem column wraps to three. */
.nav-menu__panel--described { min-width: 20rem; }
.nav-menu__panel--described a {
  /* Overrides the single-line row above: two stacked lines need their own box. */
  display: grid;
  gap: 1px;
  align-content: center;
  min-height: var(--tap-min);
  padding-block: var(--space-2xs);
  white-space: normal;
}
.nav-menu__title { font-weight: var(--weight-semibold); }
.nav-menu__meta {
  font-size: var(--step--2);
  line-height: 1.35;
  color: rgba(255,255,255,.62);
}
/* On the current page the row is brand purple, and .62 white on that is too dim to read. */
.nav-menu__panel a[aria-current="page"] .nav-menu__meta { color: rgba(255,255,255,.85); }


/* --- Signed-in avatar --------------------------------------------------------- */
/* It was a translucent disc with a thin ring and a letter in it, which read as an empty
   placeholder rather than as "you are signed in". Filled with the brand gradient it is
   unmistakably an account, and the initial sits on it rather than in a hole. */
.account-btn__avatar {
  background: linear-gradient(145deg, var(--brand-400), var(--brand-600));
  border-color: transparent;
  color: var(--text-on-brand);
  font-weight: var(--weight-bold);
  letter-spacing: 0;
}
.account-btn:hover .account-btn__avatar {
  background: linear-gradient(145deg, var(--brand-300), var(--brand-500));
  border-color: transparent;
}
/* Open, it gets the ring back — now as the "this menu is showing" state rather than as
   the resting look. */
.account-menu > details[open] > summary .account-btn__avatar {
  background: linear-gradient(145deg, var(--brand-400), var(--brand-600));
  box-shadow: 0 0 0 2px rgba(255,255,255,.55);
}

/* --- Notification bell -------------------------------------------------------- */
.notif { position: relative; display: inline-flex; }
.notif > details > summary {
  list-style: none;
  cursor: pointer;
}
.notif > details > summary::-webkit-details-marker { display: none; }
.notif__trigger {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border-radius: 50%;
  color: var(--text-on-inverse);
  transition: background var(--dur) var(--ease);
}
.notif__trigger:hover { background: rgba(255,255,255,.10); }
.notif > details[open] > .notif__trigger { background: rgba(255,255,255,.14); }

/* The count. Positioned on the bell rather than beside it, because a number floating next
   to an icon reads as part of the next control along. */
.notif__badge {
  position: absolute;
  top: 4px;
  right: 3px;
  min-width: 17px;
  height: 17px;
  padding-inline: 4px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-pill);
  background: var(--brand-500);
  color: var(--text-on-brand);
  font-size: 10px;
  font-weight: var(--weight-bold);
  line-height: 1;
  /* Against the dark bar, so the badge reads as sitting on top of the bell rather than
     merging with it. */
  box-shadow: 0 0 0 2px var(--ink-900);
}

.notif__panel {
  position: absolute;
  right: 0;
  top: calc(100% + var(--space-3xs));
  z-index: 60;
  width: min(21rem, calc(100vw - 2 * var(--space-s)));
  padding: var(--space-2xs);
  background: var(--ink-800);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-3);
}
.notif__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xs);
  margin: 0 0 var(--space-3xs);
  padding: var(--space-2xs) var(--space-xs);
  border-bottom: 1px solid rgba(255,255,255,.12);
  font-size: var(--step--2);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: rgba(255,255,255,.62);
}
.notif__clear {
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  color: var(--brand-200);
  font: inherit;
  text-transform: none;
  letter-spacing: 0;
  text-decoration: underline;
}
.notif__clear:hover { color: var(--ink-000); }

.notif__list { list-style: none; margin: 0; padding: 0; max-height: 60vh; overflow-y: auto; }
.notif__item { display: flex; }
.notif__text {
  display: block;
  width: 100%;
  padding: var(--space-2xs) var(--space-xs);
  border-radius: var(--radius-sm);
  color: var(--text-on-inverse);
  text-decoration: none;
  font-size: var(--step--1);
  line-height: 1.45;
}
a.notif__text:hover { background: rgba(255,255,255,.10); }
/* Unread is a dot AND heavier text, never colour alone — the difference has to survive
   someone who cannot separate the two purples. */
.notif__item.is-unread .notif__text {
  font-weight: var(--weight-semibold);
  position: relative;
  padding-left: calc(var(--space-xs) + 12px);
}
.notif__item.is-unread .notif__text::before {
  content: "";
  position: absolute;
  left: var(--space-2xs);
  top: 1.05em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--brand-300);
}
/* The way out of the panel, to the full page. Its own rule above it so it reads as a
   destination rather than as one more notification. */
.notif__all {
  margin: 0;
  padding: var(--space-3xs) var(--space-xs) var(--space-2xs);
  border-top: 1px solid rgba(255,255,255,.12);
  font-size: var(--step--1);
}
.notif__all a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  color: var(--brand-200);
  font-weight: var(--weight-bold);
}
.notif__all a:hover, .notif__all a:focus-visible { color: var(--ink-000); }

.notif__empty {
  padding: var(--space-xs);
  color: rgba(255,255,255,.62);
  font-size: var(--step--1);
}

/* Anchored to a control in the last 44px of a narrow bar, the panel would hang off the
   right edge. */
@media (max-width: 30rem) {
  .notif__panel {
    position: fixed;
    left: var(--space-xs);
    right: var(--space-xs);
    top: calc(var(--header-h) + var(--space-3xs));
    width: auto;
  }
}
