/* ════════════════════════════════════════════════════════════════════════
   shared-prototype.css
   ────────────────────
   Canonical Backbase prototype v4 Variant C design tokens and the
   floating Liquid Glass top nav (.bb-header) + bottom nav (.bb-mobile-nav)
   + sharp CTA primitive (.bb-cta). The theme toggle that used to live here
   moved into the Meer menu on 2026-07-19 (src/shared/theme.js owns it now).

   Loaded by quiz.html / info-weetjes.html / admin.html / boat-info.html /
   live.html as a non-blocking <link> in <head>. Pages that ALREADY ship
   inline copies of the same rules (index.html, status.html) keep theirs;
   the cascade order leaves their inline overrides authoritative.

   Created during the iter-2 prototype-transformation NAV UNIFICATION pass
   (Fix 7). Defines the canonical --bb-* tokens plus the .bb-header and
   .bb-mobile-nav markup that the production pages listed above share.
   ════════════════════════════════════════════════════════════════════════ */

:root,
:root[data-theme="light"]{
  --bb-navy: #091C35;
  --bb-blue: #3366FF;
  --bb-cyan: #69FEFF;
  --bb-red:  #FF6047;

  --bb-bg-page:    #F3F6F9;
  --bb-bg-card:    #FFFFFF;
  --bb-fg-default: #091C35;
  --bb-fg-muted:   rgba(9, 28, 53, 0.65);
  --bb-fg-subtle:  rgba(9, 28, 53, 0.45);
  --bb-border:     rgba(9, 28, 53, 0.08);
  --bb-shadow:     0 4px 16px rgba(9, 28, 53, 0.08);

  --bb-accent-blue-tint:  #E5EBFF;
  --bb-accent-green-tint: #E8F5EE;
  --bb-accent-red-tint:   #FFE8E4;
  --bb-accent-amber-tint: #FFF4D6;
  --bb-accent-purple-tint:#EDE7F6;

  --bb-font: 'Libre Franklin', -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', sans-serif;
  --bb-safe-top:    env(safe-area-inset-top, 0px);
  --bb-safe-bottom: env(safe-area-inset-bottom, 0px);

  --bb-nav-h-desktop: 64px;
  --bb-nav-h-mobile:  60px;

  --bb-ease:      cubic-bezier(.16,.84,.44,1);
  --bb-spring:    cubic-bezier(.2,.7,.3,1.4);

  /* iter-4 FIX 5: unified focus-ring tokens. Soft 3px brand-blue halo on
     light surfaces. The on-navy variant swaps to cyan for inputs sitting
     on locked-navy backgrounds (quiz, admin login screen). */
  --bb-focus-ring:         0 0 0 3px rgba(51, 102, 255, 0.18);
  --bb-focus-ring-on-navy: 0 0 0 3px rgba(105, 254, 255, 0.22);

  /* ── ONE shared glass material  ->  --bb-glass-*  (D1, 2026-06-08) ──────
     A single reusable "Liquid Glass" surface spec for every panel, popup and
     legend in the app, so the in-app glass surfaces read as ONE family.
     THEMED: this LIGHT block = frosted WHITE glass with navy ink + blue
     accent (the map-popup material). The dark block (below) flips the same
     tokens to frosted NAVY glass with light ink + cyan accent, so the SAME
     class follows the app theme - no per-component branch. Mirrors the
     approved reference at pages/proto/bk-glass.html.

        --bb-glass-bg        translucent surface fill
        --bb-glass-blur      backdrop-filter (blur + saturate)
        --bb-glass-border    1px hairline border colour
        --bb-glass-radius    corner radius
        --bb-glass-shadow    drop shadow + inset top highlight
        --bb-glass-ink       default text on the glass
        --bb-glass-ink-muted secondary text on the glass
        --bb-glass-ink-faint tertiary / caption text on the glass
        --bb-glass-hairline  inset divider line colour
        --bb-glass-header-bg header-row tint (top of a panel)
        --bb-glass-accent    brand accent that reads on this glass
                             (blue on light glass, cyan on dark glass)        */
  --bb-glass-bg:         rgba(255, 255, 255, 0.66);
  --bb-glass-blur:       blur(22px) saturate(180%);
  --bb-glass-border:     rgba(255, 255, 255, 0.55);
  --bb-glass-radius:     22px;
  --bb-glass-shadow:     0 14px 44px rgba(9, 28, 53, 0.18), inset 0 1px 0 rgba(255, 255, 255, 0.70);
  --bb-glass-ink:        #091C35;
  --bb-glass-ink-muted:  rgba(9, 28, 53, 0.66);
  --bb-glass-ink-faint:  rgba(9, 28, 53, 0.46);
  --bb-glass-hairline:   rgba(9, 28, 53, 0.10);
  --bb-glass-header-bg:  rgba(255, 255, 255, 0.42);
  --bb-glass-accent:     var(--bb-blue);

  /* ── Always-DARK glass  ->  --bb-glass-dark-*  ──────────────────────────
     Some surfaces are frosted NAVY glass in BOTH app themes by design: the
     on-map legend / control panels (.glass-legend on vaarinfo + vaarverkeer)
     and the live-tour gear / settings panel float over a map that keeps its
     own theme, so they must stay dark-glass even when the app is in light
     mode. These tokens hold the dark-glass values UNCONDITIONALLY (they do
     NOT flip per theme) so those surfaces share the SAME navy-glass material
     as the themed dark tokens above without inheriting the light flip.       */
  --bb-glass-dark-bg:        rgba(9, 28, 53, 0.72);
  --bb-glass-dark-border:    rgba(105, 254, 255, 0.30);
  --bb-glass-dark-ink:       rgba(243, 246, 249, 0.94);
  --bb-glass-dark-ink-muted: rgba(243, 246, 249, 0.66);
  --bb-glass-dark-ink-faint: rgba(243, 246, 249, 0.46);
  --bb-glass-dark-hairline:  rgba(255, 255, 255, 0.12);
  --bb-glass-dark-accent:    var(--bb-cyan);
}

:root[data-theme="dark"]{
  --bb-bg-page:    #05080F;
  --bb-bg-card:    #0E2240;
  --bb-fg-default: #F3F6F9;
  --bb-fg-muted:   rgba(243, 246, 249, 0.72);
  --bb-fg-subtle:  rgba(243, 246, 249, 0.5);
  --bb-border:     rgba(243, 246, 249, 0.12);
  --bb-shadow:     0 4px 16px rgba(0, 0, 0, 0.32);

  --bb-accent-blue-tint:   rgba(51, 102, 255, 0.18);
  --bb-accent-green-tint:  rgba(15, 81, 50, 0.30);
  --bb-accent-red-tint:    rgba(255, 96, 71, 0.18);
  --bb-accent-amber-tint:  rgba(180, 115, 9, 0.24);
  --bb-accent-purple-tint: rgba(94, 53, 177, 0.24);

  /* iter-4 FIX 5: dark-mode focus-ring uses cyan since blue gets lost on
     the dark page surface. */
  --bb-focus-ring: 0 0 0 3px rgba(105, 254, 255, 0.18);

  /* Shared glass material - DARK theme = frosted NAVY glass, light ink,
     cyan hairline + cyan accent (mirrors pages/proto/bk-glass.html dark
     stage). Same six+ tokens as the light block above; only the fill /
     border / ink / accent flip, so every .bb-glass surface and the themed
     InfoWindow popups switch to navy glass with the app theme. */
  --bb-glass-bg:         rgba(9, 28, 53, 0.74);
  --bb-glass-blur:       blur(22px) saturate(180%);
  --bb-glass-border:     rgba(105, 254, 255, 0.30);
  --bb-glass-radius:     22px;
  --bb-glass-shadow:     0 18px 48px rgba(0, 0, 0, 0.46), inset 0 1px 0 rgba(255, 255, 255, 0.08);
  --bb-glass-ink:        rgba(243, 246, 249, 0.94);
  --bb-glass-ink-muted:  rgba(243, 246, 249, 0.66);
  --bb-glass-ink-faint:  rgba(243, 246, 249, 0.46);
  --bb-glass-hairline:   rgba(255, 255, 255, 0.12);
  --bb-glass-header-bg:  rgba(255, 255, 255, 0.05);
  --bb-glass-accent:     var(--bb-cyan);
  /* --bb-glass-dark-* stay as defined in the base block (they are theme-
     independent on purpose) - no override needed here. */
}

/* iter-4 FIX 5: unified input focus ring. Lives on shared-prototype.css
   so quiz, admin login, info-weetjes search and any future text field
   share the same brand halo. Pages that sit on locked-navy override
   with `var(--bb-focus-ring-on-navy)` locally. */
input:focus-visible,
textarea:focus-visible{
  outline:none;
  border-color:var(--bb-blue);
  box-shadow:var(--bb-focus-ring);
}

/* ── .bb-glass reusable helper (D1) ───────────────────────────────────────
   Any panel / popup / legend becomes the shared glass material by adding
   .bb-glass; it reads the themed tokens above so it flips white<->navy with
   the app theme. A solid-fill @supports fallback keeps the surface readable
   where backdrop-filter is unsupported. (Existing surfaces are migrated onto
   the same TOKENS in their own stylesheets rather than this class, to avoid
   touching their markup; this helper exists for new surfaces + parity with
   the bk-glass reference.) */
.bb-glass{
  background:var(--bb-glass-bg);
  -webkit-backdrop-filter:var(--bb-glass-blur);
  backdrop-filter:var(--bb-glass-blur);
  border:1px solid var(--bb-glass-border);
  border-radius:var(--bb-glass-radius);
  box-shadow:var(--bb-glass-shadow);
  color:var(--bb-glass-ink);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  :root .bb-glass,
  :root[data-theme="light"] .bb-glass{ background:rgba(255, 255, 255, 0.94); }
  :root[data-theme="dark"] .bb-glass{ background:rgba(9, 28, 53, 0.96); }
}

/* ── Native tabbalk (iOS): web-balk uit ─────────────────────────────────
   src/shared/native-tabbar.js zet html.bb-native-tabbar zodra de echte
   UIKit Liquid Glass tabbalk daadwerkelijk STAAT (niet eerder - anders zit
   de gebruiker een frame lang zonder menu). Alleen native iOS zet deze
   klasse, dus de web-PWA en Android houden de CSS-glasbalk.
   Scoped op de html-modifier, niet naakt op .bb-mobile-nav, conform de
   CSS Cascade Scoping Rule. */
html.bb-native-tabbar .bb-mobile-nav{ display:none !important; }

/* Smooth color-flip when theme toggles. */
.bb-header,
.bb-mobile-nav{
  transition:
    background-color 240ms var(--bb-ease),
    color 240ms var(--bb-ease),
    border-color 240ms var(--bb-ease);
}

/* ── Cross-document View Transitions (PWA native-feel) ────────────────────
   Captain 2026-06-01: leaving / entering a full-bleed map page flashed the
   navy inter-document background_color. Opting BOTH documents into
   cross-document view transitions (this CSS ships on every page) makes
   Safari 18.2+ / iOS 18.2+ cross-fade page-to-page instead of hard-cutting
   through that navy frame. Browsers without support ignore @view-transition
   and hard-cut exactly as before (graceful).

   IMPORTANT (jump fix): do NOT give the floating header / bottom-nav a
   view-transition-name. Naming them lifts each into its OWN transition group
   that ANIMATES from its old geometry to its new geometry - and because the
   map pages' min-height stage gives the fixed nav a slightly different
   resting position, that animation SLID the nav between the two = the
   captain's "menu springt omhoog". With NO name they ride inside the root
   cross-fade instead: same fixed position in both snapshots, so they
   dissolve in place (active-tab cross-dissolves) with zero slide. The
   map-page bodies also now carry overflow:hidden to remove the safe-area
   scroll-slack, so the resting position is identical across pages too.

   2026-06-01 iter-2: the root cross-fade ALONE still let the nav read as a
   jump (the old + new root snapshots blend the nav at its two page-specific
   positions). So we now ALSO name the chrome and pin its GROUP animation to
   none: the header + bottom-nav are lifted into their own view-transition
   groups whose position does NOT animate - they hold their exact fixed spot
   while ONLY the page body cross-fades behind them. The old/new images still
   cross-fade so the active-tab indicator dissolves nicely, but the bar never
   moves. No slide, no ghost-jump. */
/* 2026-06-01 iter-4: cross-document View Transitions RE-ENABLED.
   The captain pinned the real symptom: a brief BLACK BAR, ONLY in the iOS
   standalone PWA, during navigation. That is the manifest background_color
   (#091C35 navy) that iOS paints BETWEEN documents on a hard cut. A
   cross-document view transition holds the old page's snapshot, loads the new
   page, then cross-fades old -> new - so the inter-document navy frame is never
   shown. Disabling it (iter-3) re-exposed the bar; the earlier "jump" reports
   were almost certainly the SAME hard-cut bar on a STALE-cached build that
   never actually ran the VT.
   2026-06-01 iter-5: the captain's 20.57 standalone-PWA recording DISPROVED
   the "nameless root cross-fade rides at identical position" bet from iter-4.
   On a Live -> Vaarinfo navigation the OLD and NEW bottom-nav rest at
   DIFFERENT y (the pages give the fixed .bb-mobile-nav a slightly different
   bottom offset), so the root cross-fade blended TWO nav bars at two heights
   = the "menu springt omhoog" double-nav. Restoring the iter-2 fix: NAME the
   chrome so each is one matched element across both documents, and pin its
   GROUP animation to none so it holds its exact fixed spot (no slide, no
   double) while ONLY the page content cross-fades. view-transition-name must
   be unique per document - verified: exactly one .bb-header + one
   .bb-mobile-nav per page. Browsers without support hard-cut as before. */
@view-transition { navigation: auto; }
/* Persistent chrome: header + bottom tab-bar hold position across the
   cross-document cross-fade (kills the double-nav jump). */
.bb-header{ view-transition-name: bb-header; }
.bb-mobile-nav{ view-transition-name: bb-mobile-nav; }
::view-transition-group(bb-header),
::view-transition-group(bb-mobile-nav){ animation: none !important; }
/* 2026-06-01 iter-6 (verified on the captain's v307 iOS-26 sim recording):
   the named chrome killed the double-nav, but the page CONTENT still
   cross-faded - mid-transition both pages' content overlapped (ghosting),
   which reads as "niet goed" (a native tab switch snaps, it does not
   cross-fade two pages over each other). Make the content swap INSTANT: the
   VT still holds the old snapshot until the new page has painted, so the
   inter-document navy frame stays hidden - we just skip the cross-fade so the
   two pages never visibly overlap. Result: tap -> clean instant swap, chrome
   stays put, no navy flash, no ghost. */
::view-transition-group(root),
::view-transition-old(root),
::view-transition-new(root){ animation: none !important; }
/* Reduced-motion: complete the navigation but skip the cross-fade animation. */
@media (prefers-reduced-motion: reduce){
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*){ animation: none !important; }
}

/* Wordmark size convention (iter-3 fix 10). Default 20px; home pages
   (index + status, body.is-home) bump to 22px so the entry point reads
   slightly larger. Other pages stay at the 20px sub-page default. */
.bb-wordmark{ height: 20px; }

/* ════════════════════════════════════════════════════════════════════
   .bb-header - floating Liquid Glass top nav. White wordmark + light
   controls float on top, 12px gutters, soft inset top highlight + outer
   drop shadow.

   Captain 2026-07-29 (variant V3, prototype gearchiveerd als
   archive/ui-topbar-proto.html; screenshots + contrastmeting staan in
   docs/reports/topbar-glass-proto-20260729/): de balk
   was in BEIDE modi dekkend navy (#091C35). Hij is nu doorschijnend, met
   een APARTE opgave per modus - dark is nadrukkelijk niet de omgekeerde
   light:
     light  moet DEMPEN. Boven een lichte pagina is er weinig te breken,
            dus 46% navy + brightness(.66) houdt de witte titel leesbaar.
            Gemeten laagste contrast 5,23:1 (na 200px scrollen, Meer-lijst),
            ruim boven de 4,5:1-norm.
     dark   mag geen zwart gat worden. 40% navy + brightness(.74) en een
            cyaan haarlijn in plaats van een witte, zodat de balk boven een
            donkere pagina nog als vorm leest.
   Het effect verdient zich terug waar er iets ONDER de balk ligt: een
   fotopagina, of content die eronder doorscrollt. Boven een egale lichte
   lijstpagina leest hij als een gedempte donkere plaat, en dat is de
   bedoeling.

   iOS-valkuil: backdrop-filter valt STILZWIJGEND weg zodra een voorouder
   zelf filter, transform of opacity<1 draagt. Geef .bb-header dus nooit
   zo'n voorouder.
   ════════════════════════════════════════════════════════════════════ */
.bb-header{
  position:fixed;
  top:max(12px, var(--bb-safe-top));
  left:12px;right:12px;
  z-index:80;
  border-radius:22px;
  color:#fff;
}
:root[data-theme="light"] .bb-header{
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0) 58%),
    rgba(9, 28, 53, 0.46);
  -webkit-backdrop-filter:blur(20px) saturate(200%) brightness(0.66);
  backdrop-filter:blur(20px) saturate(200%) brightness(0.66);
  border:0.5px solid rgba(255, 255, 255, 0.20);
  box-shadow:
    0 6px 22px rgba(9, 28, 53, 0.20),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
:root[data-theme="dark"] .bb-header{
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.09) 0%, rgba(255, 255, 255, 0) 58%),
    rgba(9, 28, 53, 0.40);
  -webkit-backdrop-filter:blur(20px) saturate(220%) brightness(0.74);
  backdrop-filter:blur(20px) saturate(220%) brightness(0.74);
  border:0.5px solid rgba(105, 254, 255, 0.22);
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.46),
    inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
/* Geen backdrop-filter beschikbaar: terug naar een vrijwel dekkende balk,
   want een half-transparante balk ZONDER blur is onleesbaar. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .bb-header{
    background:rgba(9, 28, 53, 0.94);
    border:1px solid rgba(255, 255, 255, 0.08);
  }
}
.bb-header-inner{
  max-width:1280px;margin:0 auto;
  height:var(--bb-nav-h-mobile);
  display:flex;align-items:center;gap:12px;
  padding:0 12px;
}

/* ════════════════════════════════════════════════════════════════════
   Canonical page-content width (captain 2026-05-31: ONE standard width,
   everything aligns to it, esp. desktop). Every page's MAIN content
   wrapper uses .bb-page so the content column is identical site-wide and
   its left edge lines up exactly with the .bb-header wordmark (24px =
   12px bar inset + 12px header-inner padding) at every viewport width.
   1304 = the header inner max-width 1280 + the 24px bar inset folded into
   self-centering, so content-left tracks the wordmark to <1px on wide
   screens too. Pages keep their own vertical padding; this only governs
   horizontal width + centering. Do NOT add narrower per-page max-widths
   on the main column - that is exactly the inconsistency we removed. */
.bb-page{
  width:100%;
  max-width:1304px;
  margin-left:auto;
  margin-right:auto;
  padding-left:24px;
  padding-right:24px;
  box-sizing:border-box;
}

/* ════════════════════════════════════════════════════════════════════
   Canonical WORDMARK-ANCHORED column (TODO #46 voorstel A + C, captain
   2026-06-13). Same horizontal alignment as the wordmark on EVERY width,
   but instead of self-centering in a 1304 box it ANCHORS its left edge to
   the wordmark and grows rightward. This is what the captain-tool pages
   (reports / changelog / todo) use so the content-left == wordmark-left at
   1280/1440/1920 (the Rapporten "+58px scheef" klacht). The gutter is
   viewport-relative so it is box-sizing-independent (no 1304-vs-1328
   breakpoint drift on pages with their own `* { box-sizing }` reset):
     vw <= 1304  ->  24px            (== 12px bar inset + 12px header pad)
     vw  > 1304  ->  (vw-1304)/2 + 24  (tracks the centered wordmark exactly)
   Proven pattern - identical to info-weetjes' --iw-col-pad. The full-bleed
   map pages + centered text pages keep .bb-page; this is only for the dense
   captain-tool content columns. */
.bb-page-wide{
  width:100%;
  max-width:none;
  margin-left:0;
  margin-right:0;
  padding-inline:max(24px, calc((100vw - 1304px)/2 + 24px));
  box-sizing:border-box;
}

/* ════════════════════════════════════════════════════════════════════
   Canonical PAGE HEADER (title + lede + section label). ONE shared
   standard for every content page (captain 2026-05-31: "de stijl van
   routes is goed qua titel en subtekst" - Routes is the reference, every
   other page must match it). Previously each page hardcoded its own
   header values (Routes: clamp/500/1.18; More + Status: fixed 30px/600/
   1.05) which is the per-page drift we keep removing. These grouped
   selectors map each page's existing header class onto the SAME values
   so the title weight/size + subtext never diverge. New pages should add
   their header selector to these groups rather than redefining values. */
.bb-route-cards > h1,
.mr-head h1,
.bb-page-title{
  font-size:clamp(1.6rem, 4.4vw, 2.4rem);
  font-weight:500;
  letter-spacing:-0.018em;
  line-height:1.18;
  margin:0 0 6px;
  color:var(--bb-fg-default);
}
/* Desktop-only in-page page title for the Meer sub-pages (captain 2026-06-12:
   "de titel moet ook bij alle subpaginas terugkomen, alleen op desktop").
   Mobile keeps the title in the navy header (.bb-header-title); desktop shows
   the page name as this h1 at the top of the content. Shares the canonical
   typography above so it never drifts per page. */
.bb-page-title{ display:none; }
@media (min-width:960px){ .bb-page-title{ display:block; } }
.bb-route-cards p.lede,
.mr-head p{
  font-size:0.96rem;
  line-height:1.5;
  color:var(--bb-fg-muted);
  margin:0 0 6px;
  max-width:62ch;
}
.bb-section-label,
.mr-seclbl{
  display:block;
  font-size:0.72rem;
  text-transform:uppercase;
  letter-spacing:0.12em;
  color:var(--bb-fg-muted);
  font-weight:600;
  margin:24px 0 12px;
}
.bb-header-brand{
  display:flex;align-items:center;gap:8px;
  flex:0 0 auto;
  color:#FFFFFF;
  text-decoration:none;
}
/* App icon - now the ONLY brand element in the header (wordmark removed
   site-wide, captain 2026-06-15). One shared rule here applies site-wide -
   never add per-page header markup for this. The canonical PWA install icon
   (the navy B-with-waves mark, /assets/pwa-icon-*) is reused; its own navy
   field matches the navy header so the white B + cyan waves float on the bar
   like a native app glyph in a dark nav. Bumped 32 -> 44 -> 50px now that it
   stands alone (was sized to ~20px optical wordmark height when paired with the
   wordmark); it carries built-in internal padding on the 256px canvas so the
   visible mark reads balanced against the lang-pill. The header
   inner is 60/64px tall so a 50px square sits vertically centred (.bb-header-brand
   is align-items:center) with comfortable clearance - not clipped. High-res
   source scaled down stays crisp; small radius keeps corners tidy on any
   future light header. Absolute /assets path so it resolves identically from
   /pages/* and the root shell. */
.bb-header-brand::before{
  content:"";
  flex:0 0 auto;
  width:50px;height:50px;
  border-radius:13px;
  background:url("/assets/pwa-icon-256.png") center/contain no-repeat;
}
/* Wordmark REMOVED from the header site-wide (captain 2026-06-15): now the
   app-icon is well designed, the floating navy header reads "[app-icon] +
   lang-pill + theme-toggle" with no "Backbase" wordmark - it was too cramped
   on mobile. We hide the .bb-wordmark SVG inside the header rather than strip
   it from every per-page header markup (one CSS rule covers app.html shell +
   all per-page headers). The brand link keeps its aria-label ("Backbase
   Captain"...) so the accessible name is untouched; only the visible glyph is
   removed. Kept display:none (not visibility:hidden) so it occupies no layout
   width and the enlarged icon sits flush. */
.bb-header .bb-wordmark{display:none}
.bb-wordmark{display:block;width:auto;flex:0 0 auto}
.bb-header .bb-wordmark path{fill:#FFFFFF}
/* Subpage back-chip: "< Meer". Shown on MOBILE subpages (Quiz, captain's
   briefing, weetjes, status) where the desktop nav is hidden, so there is
   always one explicit, consistent way back up to the Meer index. Hidden on
   desktop (the nav bar already shows Meer). Pages opt in by placing
   <a class="bb-back" href="/meer"> in .bb-header-inner after the brand. */
.bb-back,
.bb-rd-back{
  /* Round navy-glass back chip with a cyan ring + cyan chevron. Recipe is the
     SAME as the quiz number badge (.qhead .num) and the route stop-pin, so the
     back affordance and the numbered markers read as ONE family (captain
     2026-06-11: "visueel moeten deze hetzelfde, het nummer is de juiste
     stijl"). Sits on the navy glass header so the navy disc + cyan ring pop.
     Shared by .bb-back AND the route-detail .bb-rd-back chip (below); only
     their display gating + svg sizes differ, kept in their own rules. */
  align-items:center;justify-content:center;flex:0 0 auto;
  width:34px;height:34px;padding:0;
  border-radius:50%;
  background:
    radial-gradient(120% 100% at 50% 0%, rgba(105,254,255,0.18) 0%, rgba(9,28,53,0) 45%),
    linear-gradient(180deg, rgba(20,42,76,0.88), rgba(9,28,53,0.94));
  -webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);
  border:1.5px solid rgba(105,254,255,0.50);
  box-shadow:0 1px 4px rgba(0,0,0,0.35), inset 0 1.5px 1.5px rgba(255,255,255,0.26);
  color:var(--bb-cyan);
  text-decoration:none;
  transition:border-color .16s ease, box-shadow .16s ease, transform .12s ease;
}
.bb-back:hover,
.bb-rd-back:hover{border-color:rgba(105,254,255,0.85);box-shadow:0 2px 8px rgba(0,0,0,0.4), inset 0 1.5px 1.5px rgba(255,255,255,0.3)}
.bb-back:active,
.bb-rd-back:active{transform:scale(0.94)}
.bb-back:focus-visible,
.bb-rd-back:focus-visible{outline:2px solid var(--bb-cyan);outline-offset:2px}
/* .bb-back display gating: mobile-only (desktop nav bar already shows Meer). */
.bb-back{display:inline-flex}
.bb-back svg{width:16px;height:16px;stroke:var(--bb-cyan);fill:none;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;flex:0 0 auto}
@media (min-width:960px){ .bb-back{display:none} }
/* On a MOBILE subpage the "< Meer" chip stands in for the wordmark (native
   pushed-view pattern: back affordance instead of the app logo). This also
   frees the header width so the chip + lang pill + theme toggle never crowd
   or clip on a 375px phone. Desktop keeps the wordmark (chip is hidden, the
   nav bar shows Meer). Only pages that opted into .bb-back are affected. */
@media (max-width:959.98px){
  .bb-header-inner:has(.bb-back) .bb-header-brand{ display:none; }
}
/* Route-detail back chip (index.html only). Same glass-icon recipe as .bb-back
   (shared comma-joined rule above) but: shown on ALL viewports, keeps the
   wordmark visible (sits to its LEFT), and gated on html.has-route so it
   appears only when a route is open and never flashes on the routes picker.
   Uses a distinct class so the .bb-back mobile brand-hide rule above never
   matches it. The selector is inert on other pages (they ship no .bb-rd-back
   element) and on /live (no .bb-rd-back markup) even though they may also
   carry ?route=. */
.bb-rd-back{display:none}
html.has-route .bb-rd-back{ display:inline-flex; }
.bb-rd-back svg{width:17px;height:17px;stroke:var(--bb-cyan);fill:none;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;flex:0 0 auto}
/* Subpage page-title inside the navy header bar.
   White on navy is explicitly permitted (CLAUDE.md Colour Rule).
   Appears after the back-chip on subpages; truncates on narrow screens
   rather than wrapping or pushing the lang pill out. */
.bb-header-title{
  display:inline-block;
  min-width:0;
  overflow:hidden;
  white-space:nowrap;
  text-overflow:ellipsis;
  font-size:15px;
  font-weight:500;
  letter-spacing:-0.01em;
  line-height:1.2;
  color:#fff;
}
/* Subtle divider between back-chip / wordmark and the page title. */
.bb-header-divider{
  display:inline-block;
  width:1px;
  height:18px;
  background:rgba(255,255,255,0.22);
  margin:0 11px;
  vertical-align:middle;
  flex:0 0 auto;
}
/* Op de doorschijnende balk (V3) heeft de divider per modus een andere
   sterkte nodig: in light zakt hij weg tegen de gedempte achtergrond, in
   dark wordt hij juist te hard. */
:root[data-theme="light"] .bb-header-divider{ background:rgba(255, 255, 255, 0.26); }
:root[data-theme="dark"]  .bb-header-divider{ background:rgba(255, 255, 255, 0.20); }
/* Captain 2026-06-10: the in-header page title is a MOBILE affordance only.
   On desktop the .bb-desktop-nav already names where you are, so title +
   divider would be dubbelop - hide them at the desktop breakpoint.
   !important on purpose: page/shell rules gate visibility with higher
   specificity (e.g. body.bb-shell-sub in app.html) and must not re-show
   the title on desktop. */
@media (min-width:960px){
  .bb-header .bb-header-title,
  .bb-header .bb-header-divider{display:none !important}
}
.bb-header-spacer{flex:1}
.bb-header-controls{
  display:flex;align-items:center;gap:8px;
  flex:0 0 auto;
}

/* Theme toggle button - sun / moon icons, Liquid Glass scope */

/* ── Language pill (UK/NL flags). Liquid Glass, sits on the navy
   .bb-header so the translucent-white scheme reads in BOTH themes.
   Ported from the prototype shell so every production page renders the
   same glass pill (was previously unstyled / bare flag buttons). The
   ::before is the sliding highlight; it tracks the active button. */
.bb-lang-pill{
  display:inline-flex;align-items:center;position:relative;isolation:isolate;
  background:rgba(255, 255, 255, 0.10);
  border:1px solid rgba(255, 255, 255, 0.12);
  border-radius:999px;padding:0;
  height:34px;
  /* Glow focus (proto Variant 2): subtle inner shadow gives the pill
     recessed depth so the glowing thumb reads as sitting inside it. */
  box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.28), inset 0 0 0 1px rgba(255, 255, 255, 0.04);
}
.bb-lang-pill::before{
  content:'';position:absolute;top:0;left:0;
  width:50%;height:100%;
  /* Glow focus: thumb carries a steady cyan glow (var(--bb-cyan) = #69FEFF). */
  background:rgba(105, 254, 255, 0.14);
  border-radius:999px;
  box-shadow:
    0 1px 3px rgba(0, 0, 0, 0.22),
    0 0 12px rgba(105, 254, 255, 0.45),
    inset 0 0 0 1px rgba(105, 254, 255, 0.30);
  /* smooth power-curve ease, no overshoot/spring */
  transition:transform 0.42s cubic-bezier(0.65,0,0.35,1);
  pointer-events:none;z-index:0;
}
.bb-lang-pill:has(.bb-lang-btn:nth-child(2).active)::before{
  transform:translateX(100%);
}
.bb-lang-btn{
  display:inline-flex;align-items:center;justify-content:center;gap:6px;
  padding:0 12px;height:32px;min-width:44px;
  background:transparent;color:rgba(255, 255, 255, 0.7);
  border:none;cursor:pointer;
  font:600 11px/1 var(--bb-font);letter-spacing:0.04em;
  border-radius:999px;
  position:relative;z-index:1;flex:1;
  transition:color 0.18s var(--bb-ease);
}
.bb-lang-btn svg{
  display:block;border-radius:2px;flex:0 0 auto;
  box-shadow:0 0 0 0.5px rgba(0, 0, 0, 0.18);
  /* Glow focus: the inactive flag is desaturated + dimmed. */
  filter:saturate(0.18) brightness(0.78) opacity(0.6);
  transition:filter 0.3s var(--bb-ease), transform 0.3s var(--bb-ease);
}
/* Captain 2026-05-30: the EN/NL text labels are redundant - the flags are
   enough. Hide the code text site-wide; the pill shows flag-only. */
.bb-lang-btn .bb-lang-code{display:none}
/* The active flag is full colour + a hair larger. */
.bb-lang-btn.active svg{filter:saturate(1) brightness(1) opacity(1);transform:scale(1.06)}
/* Hovering the inactive flag previews it at full colour. */
.bb-lang-btn:hover svg{filter:saturate(1) brightness(1.04) opacity(1);transform:scale(1.06)}
.bb-lang-btn.active{color:#FFFFFF}
.bb-lang-btn:hover{color:#FFFFFF}
.bb-lang-btn:focus-visible{
  outline:2px solid var(--bb-cyan);
  outline-offset:2px;
}

/* ════════════════════════════════════════════════════════════════════
   Tap-target extension (audit 2026-07-13, HIGH). The header controls all
   measured below the 36px tap floor at 375/393: .bb-back + .bb-rd-back
   34x34, .bb-lang-btn 44x32 inside the 34px pill.
   The VISUAL size stays exactly as-is on purpose - the 34px navy-glass
   chip recipe is deliberately identical to the quiz number badge and the
   route stop-pin (captain 2026-06-11: "visueel moeten deze hetzelfde"),
   so resizing would break that family. Instead each control gets an
   invisible ::after hit area that grows the TOUCH target to ~44px
   effective (Apple HIG). The ::after is transparent - it only widens
   hit-testing, never paints. .bb-lang-btn extends VERTICALLY only
   (inset -6px 0): the two flag buttons sit flush side by side, so a
   horizontal bleed would make their hit areas overlap each other.
   None of these classes carried a ::after before (repo-wide grep
   2026-07-13; only .bb-lang-pill::before - the sliding thumb - exists,
   and it is untouched). */
.bb-back,
.bb-rd-back{position:relative}
.bb-back::after,
.bb-rd-back::after{
  /* 34x34 chip -> 44x44 effective */
  content:'';position:absolute;inset:-5px;border-radius:50%;
}
.bb-lang-btn::after{
  /* 32px-high buttons -> 44px effective; vertical only, see block note.
     Buttons keep position:relative + z-index:1 above the pill thumb. */
  content:'';position:absolute;inset:-6px 0;border-radius:999px;
}

/* Desktop nav (hidden under 960px). Sub-screens may not render
   .bb-desktop-nav children but the rule is defined here so any page
   that does will pick it up. */
.bb-desktop-nav{
  display:none;
  align-items:center;gap:4px;
  flex:1;justify-content:center;
}
.bb-nav-link{
  position:relative;
  display:inline-flex;align-items:center;gap:8px;
  padding:8px 14px;border-radius:12px;
  font-size:14px;font-weight:600;letter-spacing:-0.006em;
  color:rgba(255, 255, 255, 0.78);
  background:transparent;
  border:1px solid transparent;
  cursor:pointer;
  text-decoration:none;
  transition:
    transform 240ms cubic-bezier(.2,.7,.3,1.4),
    box-shadow 240ms ease,
    background 200ms ease,
    border-color 200ms ease,
    color 200ms ease;
  white-space:nowrap;
}
.bb-nav-link svg{
  width:16px;height:16px;display:block;
  stroke:currentColor;fill:none;stroke-width:1.7;
  flex:0 0 auto;
}
.bb-nav-link:hover{
  /* Frosted-lens hover (proto Variant 2), matched to the bottom-tab lens so
     desktop + mobile share one cyan-glow language. The matte cyan tint + 0.5px
     cyan border + inner luminescence mirror .bb-mobile-tab::before; the outer
     cyan halo gives the same soft bloom the lens reads as on hover. */
  transform:translateY(-1px) scale(1.02);
  background:
    linear-gradient(180deg, rgba(105, 254, 255, 0.18), rgba(105, 254, 255, 0.08)),
    rgba(105, 254, 255, 0.08);
  color:#FFFFFF;
  border-color:rgba(105, 254, 255, 0.30);
  box-shadow:
    inset 0 0 12px rgba(105, 254, 255, 0.28),
    inset 0 0 0 1px rgba(255, 255, 255, 0.06),
    0 6px 18px rgba(105, 254, 255, 0.20);
}
.bb-nav-link[aria-current="page"]{
  background:rgba(255, 255, 255, 0.08);
  color:#FFFFFF;
}
.bb-nav-link[aria-current="page"]::after{
  content:'';
  position:absolute;
  left:50%;bottom:2px;
  width:4px;height:2px;
  border-radius:2px;
  background:linear-gradient(90deg, var(--bb-cyan), #FFFFFF);
  transform:translateX(-50%);
  transition:width 280ms cubic-bezier(.2,.7,.3,1.4);
}
.bb-nav-link[aria-current="page"]:hover::after,
.bb-nav-link[aria-current="page"]:focus-visible::after{
  width:24px;
}

/* ════════════════════════════════════════════════════════════════════
   Desktop dropdown submenus - REMOVED (captain 2026-06-13, TODO #280)
   The desktop dropdown submenus ("niet handig en niet mooi; weg ermee")
   are gone: the submenu script lived on as a no-op shim until 2026-07-13,
   when the shim + its includes were deleted outright. No element ever
   carries the old submenu classes and the styling block was deleted.
   Each desktop top-nav item is a plain navigable link (Meer -> its own
   /meer page). Nothing left to scope or safety-net here.
   ════════════════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════════════════
   .bb-mobile-nav - floating Liquid Glass bottom tab bar (under 960px)
   ════════════════════════════════════════════════════════════════════ */
.bb-mobile-nav{
  position:fixed;
  left:12px;right:12px;
  bottom:max(12px, var(--bb-safe-bottom));
  z-index:70;
  /* One premium frosted surface - subtle top sheen, no heavy outline.
     TRANSLUCENT frosted glass by default (captain 2026-06-15 wanted the NOS
     native-app glass: content visibly frosts THROUGH the bar). At 0.72 navy it
     reads as deep navy over dark content (dark theme + the route/live screens)
     while the canal/map behind blurs through; brightness(0.85) darkens whatever
     is behind so the navy keeps reading even over lighter content. The two
     carve-outs BELOW keep it SOLID where translucency would still wash out:
     LIGHT theme + the always-light vaarinfo/vaarverkeer maps (the 2026-06-02
     "omgedraaid" case). */
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.07) 0%, rgba(9, 28, 53, 0.0) 42%),
    rgba(9, 28, 53, 0.72);
  -webkit-backdrop-filter:blur(36px) saturate(180%) brightness(0.85);
  backdrop-filter:blur(36px) saturate(180%) brightness(0.85);
  /* Hairline border only - reads as the edge of glass, not a pill outline. */
  border:0.5px solid rgba(255, 255, 255, 0.10);
  border-radius:26px;
  padding:6px 8px;
  display:flex;align-items:stretch;justify-content:space-between;gap:2px;
  /* Softer, single ambient shadow + a thin top inset highlight (liquid glass). */
  box-shadow:
    0 8px 30px rgba(9, 28, 53, 0.28),
    inset 0 1px 0 rgba(255, 255, 255, 0.12);
}
/* Nav-glass carve-out (captain 2026-06-15) - keep the bar SOLID deep navy over the
   ALWAYS-LIGHT vaarinfo map, so the translucent glass doesn't wash the navy out
   there ("omgedraaid"). :has() targets the bar whose ACTIVE tab
   (aria-current=page, set by the shell AND each standalone page) is vaarinfo,
   so it works in the app shell and standalone with no JS. Everywhere else keeps
   the translucent frosted glass (the NOS-style look). !important so this deliberate
   override always beats the translucent base (same approach as .glass-legend).
   (Vaarverkeer left this list 2026-07-19 when its tab moved into Meer - as a
   Meer sub-page the shell hides the page's own nav entirely.) */
.bb-mobile-nav:has(.bb-mobile-tab[href="/vaarinfo"][aria-current="page"]){
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(9, 28, 53, 0.0) 42%),
    rgba(9, 28, 53, 0.94) !important;
}
.bb-mobile-tab{
  position:relative;
  flex:1;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  padding:7px 4px;
  /* No per-tab box: no background, no border. Just icon + label. */
  background:transparent;
  border:0;
  border-radius:16px;
  font-size:10px;font-weight:600;letter-spacing:-0.012em;
  /* Label centering: the label is a bare text node beside the <svg>. align-items
     centres it as a flex item, but a wrapped two-word label ("Waterway info" /
     "Vessel traffic") needs text-align:center so BOTH lines sit centred under the
     icon (default text-align:start left-aligns the ragged second line). A tight
     line-height keeps a two-line label compact, and word-break:keep-all stops a
     single long word from splitting mid-word. */
  text-align:center;
  /* Captain 2026-06-01: every menu label on ONE line, ALWAYS - never wrap. */
  white-space:nowrap;
  line-height:1.1;
  color:rgba(255, 255, 255, 0.56);
  cursor:pointer;
  text-decoration:none;
  -webkit-tap-highlight-color:transparent;
  /* Suppress the iOS long-press link preview / callout + text selection so the
     hold-drag-release gesture (nav-hold-drag.js) owns the press-and-hold instead
     of the system context menu hijacking it. A plain tap is unaffected. */
  -webkit-touch-callout:none;
  -webkit-user-select:none;
  user-select:none;
  transition:
    transform 260ms cubic-bezier(.2,.7,.3,1.2),
    color 220ms ease;
}
/* Frosted-lens slide-in (proto Variant 2 active-lens motion). The proposal's
   single shared lens GLIDES between tabs and squash/stretches mid-flight
   (sx = 1 + stretch*0.30, sy = 1 - stretch*0.18) then settles with a plain
   ease (no overshoot). Production has one lens PER tab (::before) instead of a
   single shared element, so when the active tab changes the new tab's lens
   plays this keyframe: it enters from the side with the proto's squash/stretch
   and settles to rest, reading as the lens "arriving" on the new tab. The
   off-screen entry direction is purely cosmetic; the squash/stretch profile is
   what carries the V2 liquid-settle feel. */
@keyframes bbLensSlideIn{
  0%   { opacity:0; transform:translateX(-26%) scale(1.30, 0.82); }
  55%  { opacity:1; transform:translateX(4%)   scale(0.96, 1.04); }
  100% { opacity:1; transform:translateX(0)    scale(1, 1); }
}
/* Soft "pill" highlight. Lives on every tab but stays invisible (scaled
   down + transparent) until the tab is active - then it springs in. This
   is the Apple-tab-bar active treatment: a quiet rounded glow behind the
   active icon, transform/opacity only so it is GPU-cheap. */
.bb-mobile-tab::before{
  content:'';
  position:absolute;
  /* Capsule geometry matched to the proposal Frosted lens pill:
     8px inset from the bar top/bottom (= 2px inside the tab, since the bar pads
     6px) and a generous full-tab-width capsule. The horizontal inset is kept
     tight (2px, equal to the vertical) so the pill reads as the roomy lens from
     the proposal, not a narrow chip. */
  inset:2px 2px;
  border-radius:16px;
  /* Frosted lens pill (captain pick 2026-05-30): matte cyan-tinted frosted
     glass with its OWN small blur + a soft INNER luminescence only - no shine
     streak and no top-edge specular highlight (the captain killed the glare). */
  background:
    linear-gradient(180deg, rgba(105, 254, 255, 0.20), rgba(105, 254, 255, 0.10)),
    rgba(105, 254, 255, 0.10);
  -webkit-backdrop-filter:blur(6px) saturate(150%) brightness(1.06);
  backdrop-filter:blur(6px) saturate(150%) brightness(1.06);
  border:0.5px solid rgba(105, 254, 255, 0.30);
  box-shadow:
    inset 0 0 12px rgba(105, 254, 255, 0.30),
    inset 0 0 0 1px rgba(255, 255, 255, 0.06);
  opacity:0;
  transform:scale(0.86);
  transition:
    transform 320ms cubic-bezier(.2,.8,.2,1.15),
    opacity 240ms ease;
  pointer-events:none;
  z-index:-1;
}
.bb-mobile-tab svg{
  position:relative;
  z-index:1; /* keep the icon above the ::after hover glow (which sits at z 0) */
  width:23px;height:23px;
  stroke:currentColor;fill:none;stroke-width:1.7;
  transition:transform 280ms var(--bb-spring), color 200ms var(--bb-ease), filter 280ms var(--bb-ease);
}
/* Captain 2026-06-01: the round cyan halo bloom behind the icon (::after) is
   removed. The neon glow the captain likes lives on the ICON itself via
   .bb-mobile-tab:hover svg { color:cyan; filter:drop-shadow(...) } - no circle. */
.bb-mobile-tab::after{ display:none; }
/* Hover is pointer-only - wrap in @media (hover:hover) so touch devices
   never get a stuck-hover state after a tap. */
@media (hover:hover){
  .bb-mobile-tab:hover{
    color:#FFFFFF;
  }
  .bb-mobile-tab:hover svg{
    /* Frosted-lens hover (proto V2): icon springs up + tints cyan + a soft
       cyan drop-shadow halos it. */
    transform:scale(1.14);
    color:var(--bb-cyan);
    filter:drop-shadow(0 2px 5px rgba(105, 254, 255, 0.40));
  }
  /* ::after is display:none (circle removed per captain). */
  /* Frosted-lens hover bloom (proto V2). In the proposal the single shared lens
     GLIDES to whichever tab the pointer is over; with one lens per tab we instead
     bloom the hovered tab's own frosted lens in. On a non-active tab it fades in
     softer (a preview of the lens landing there); on the active tab it blooms a
     touch brighter. Spring scale matches the resting ::before easing. */
  .bb-mobile-tab:hover::before{
    opacity:0.6;
    transform:scale(1);
  }
  .bb-mobile-tab[aria-current="page"]:hover::before,
  .bb-mobile-tab.is-active-group:hover::before{
    opacity:1;
    transform:scale(1.03);
    box-shadow:
      inset 0 0 16px rgba(105, 254, 255, 0.42),
      inset 0 0 0 1px rgba(255, 255, 255, 0.08);
  }
}
/* ── Hold-drag-release tab navigation (nav-hold-drag.js) ──────────────
   Touch twin of the pointer :hover lens above, keyed on .is-drag-hover so
   the tab UNDER the dragging finger lights up live (the pointer hover rules
   sit in a (hover:hover) block and never fire on touch). Identical look to
   the hover preview the design already ships. */
.bb-mobile-tab.is-drag-hover::before{
  opacity:0.6;
  transform:scale(1);
}
.bb-mobile-tab.is-drag-hover svg{
  transform:scale(1.14);
  color:var(--bb-cyan, #69FEFF);
  filter:drop-shadow(0 2px 5px rgba(105, 254, 255, 0.40));
}
.bb-mobile-tab[aria-current="page"].is-drag-hover::before,
.bb-mobile-tab.is-active-group.is-drag-hover::before{
  opacity:1;
  transform:scale(1.03);
  box-shadow:
    inset 0 0 16px rgba(105, 254, 255, 0.42),
    inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}
/* While dragging, suppress the per-tab :active squash so the bar reads as one
   continuous surface the finger glides over, not a sequence of button presses. */
.bb-mobile-nav.is-dragging .bb-mobile-tab:active{ transform:none; }
@media (prefers-reduced-motion: reduce){
  .bb-mobile-tab.is-drag-hover svg{ transform:none; filter:none; }
}

.bb-mobile-tab:active{
  transform:scale(0.94);
}
/* #94 (captain 2026-06-13): the nav labels were shortened (Vaarverkeer ->
   "Verkeer"; EN "Waterway info" -> "Waterways", "Vessel traffic" -> "Traffic")
   so all five tabs fit on one line at the SAME flex:1 width. The old per-tab
   flex-grow:1.7 boost for vaarinfo/vaarverkeer is gone - that asymmetry is what
   squeezed "Meer" (#95). All five tabs are now equal-width. */
.bb-mobile-tab[aria-current="page"],
.bb-mobile-tab.is-active-group{
  color:#FFFFFF;
}
.bb-mobile-tab[aria-current="page"] svg,
.bb-mobile-tab.is-active-group svg{
  /* Active icon gets a faint cyan tint + a gentle raise. */
  color:var(--bb-cyan);
  transform:translateY(-1px) scale(1.04);
}
.bb-mobile-tab[aria-current="page"]::before,
.bb-mobile-tab.is-active-group::before{
  opacity:1;
  transform:scale(1);
  /* Lens arrives with the proto V2 squash/stretch settle (no overshoot). The
     ::before transition above still handles the resting opacity/scale; this
     one-shot keyframe layers the slide-in liquid-settle on top whenever a tab
     newly becomes active. */
  animation:bbLensSlideIn 380ms cubic-bezier(.2,.7,.3,1) both;
}

/* Shared focus-visible cyan halo on all interactive header / nav elements */
.bb-nav-link:focus-visible,
.bb-mobile-tab:focus-visible,
.bb-header-brand:focus-visible,
.bb-cta:focus-visible{
  outline:2px solid var(--bb-cyan);
  outline-offset:2px;
}

/* ════════════════════════════════════════════════════════════════════
   .bb-cta - sharp 0-radius primary CTA. Uppercase, weight 300,
   letter-spacing 0.08em, padding 12px 22px, font-size 12px.
   Matches the v4 Variant C prototype shell.
   ════════════════════════════════════════════════════════════════════ */
.bb-cta{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  background:var(--bb-blue);
  color:#FFFFFF;
  border:0;
  padding:12px 22px;
  border-radius:0;
  font:300 12px/1 var(--bb-font);
  letter-spacing:0.08em;
  text-transform:uppercase;
  text-decoration:none;
  cursor:pointer;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.18),
    0 6px 16px rgba(51,102,255,0.32);
  transition:filter 180ms ease, box-shadow 180ms ease;
}
.bb-cta:hover{
  filter:brightness(1.06);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.22),
    0 10px 22px rgba(51,102,255,0.42);
}
.bb-cta:active{ transform:scale(0.985); }
.bb-cta-secondary{
  background:transparent;
  color:var(--bb-fg-default);
  border:1px solid var(--bb-border);
  box-shadow:none;
}
[data-theme="dark"] .bb-cta-secondary{color:var(--bb-cyan)}
.bb-cta-secondary:hover{
  background:var(--bb-accent-blue-tint);
  filter:none;
  box-shadow:none;
}

/* Reduced-motion: drop spring transforms on interactive elements. The
   active pill + icon raise still appear (state is conveyed), they just
   snap instead of springing. */
@media (prefers-reduced-motion: reduce){
  .bb-nav-link, .bb-mobile-tab, .bb-mobile-tab::before,
  .bb-mobile-tab::after, .bb-mobile-tab svg, .bb-cta,
  .bb-lang-pill::before, .bb-lang-btn svg{
    transition:none;
  }
  /* Drop the frosted-lens slide-in keyframe; the lens still shows on the active
     tab (state preserved), it just snaps in place instead of sliding/squashing. */
  .bb-mobile-tab[aria-current="page"]::before,
  .bb-mobile-tab.is-active-group::before{
    animation:none;
    opacity:1;
    transform:scale(1);
  }
  .bb-nav-link:hover, .bb-mobile-tab:hover,
  .bb-mobile-tab:active{
    transform:none;
  }
  /* Glow focus: keep colour/glow, drop the flag scale-bump motion. */
  .bb-lang-btn.active svg, .bb-lang-btn:hover svg{transform:none}
  /* No glow bloom / icon halo when the user has asked for less motion. */
  .bb-mobile-tab:hover svg{transform:none;filter:none}
  .bb-mobile-tab:hover::after{opacity:0}
  /* Drop the scale-bump motion on hover; the non-active-tab lens PREVIEW (a
     pure affordance, not state) is suppressed entirely so nothing blooms in,
     while the active tab keeps its lens visible (state preserved). */
  .bb-mobile-tab:hover::before{transform:scale(1);opacity:0}
  .bb-mobile-tab[aria-current="page"]:hover::before,
  .bb-mobile-tab.is-active-group:hover::before{transform:scale(1);opacity:1}
}

/* ════════════════════════════════════════════════════════════════════
   RESPONSIVE - 960px breakpoint flips into "desktop" mode (top nav
   only, no bottom bar).
   ════════════════════════════════════════════════════════════════════ */
@media (min-width:960px){
  .bb-header-inner{
    height:var(--bb-nav-h-desktop);
    gap:20px;
  }
  .bb-desktop-nav{display:flex}
  .bb-mobile-nav{display:none}
}

/* ════════════════════════════════════════════════════════════════════
   NARROW PHONES (<=400px) - subpage header title room (audit 2026-07-13,
   HIGH). At 375px the subpage bar has 325px of content (375 - 2x12 bar
   inset - 2x1 border - 2x12 inner padding); back chip 34 + divider
   (1 + 2x11 margin) + pill/toggle controls ~136 + 4x12 flex gaps leave
   ~84px for .bb-header-title, so the longest real titles truncate
   ("System st...", "Captain's briefing" needs ~122px at 15px in Libre
   Franklin 500, measured from the variable font's advance widths). ONE
   shared reclaim standard, no per-page hacks: inner padding -8, gaps
   -16 (4x4), divider margins -12, controls gap -2 = +38px, plus the
   title itself shrinking 15->14px (-8px needed) = ~46px of relief for a
   ~30-38px shortfall. Title space becomes ~120px vs ~114px needed, so
   "Captain's briefing" / "Voor de schipper" fit at 375 with slack.
   Nothing is hidden - the title, lang pill and theme toggle all stay.
   Scoped to <=400px so 393/414+ keep the current look. */
@media (max-width:400px){
  .bb-header-inner{padding:0 8px;gap:8px}
  .bb-header-divider{margin:0 5px}
  .bb-header-title{font-size:14px}
  .bb-header-controls{gap:6px}
}

/* ════════════════════════════════════════════════════════════════════════
   GLASS LEGEND  (.glass-legend)
   ─────────────
   Dark Liquid-Glass map control panel that mirrors the live-tour SETTINGS
   panel (.lt-sim-panel in src/live/live-tour.css): translucent navy glass,
   cyan uppercase section labels, light text, iOS-style switch toggles, and
   a sliding segmented control. Used ONLY by the two AIS / vaarinfo map
   panels on pages/vaarverkeer.html + pages/vaarinfo.html.

   SCOPING: every rule below is prefixed with `.glass-legend` so it can NEVER
   leak into the live-tour or standard-tour `.gmaps-legend` panels (those
   never carry the `.glass-legend` class). The vaarverkeer legend / type
   filter keep their `.gmaps-legend` class for positioning + collapse, and
   add `.glass-legend` purely as the visual skin override.

   The panel is ALWAYS dark glass in both light + dark app themes, exactly
   like the live-tour SETTINGS panel, so no [data-theme] branch is needed -
   text is near-white / cyan on the dark glass in either theme.
   ════════════════════════════════════════════════════════════════════════ */
.glass-legend{
  /* Dark glass surface (mirrors .lt-sim-panel). The cyan-tinted border +
     deep shadow signal a floating card, not a debug rectangle.
     2026-06-08 (D1): the fill / blur / border / ink now read from the shared
     always-dark glass tokens (--bb-glass-dark-*) so this on-map panel uses
     the SAME navy-glass material as the live-tour gear panel and the dark
     InfoWindow popups - one family. It stays dark glass in BOTH app themes
     by design (it floats over a map that keeps its own theme), which is why
     it uses the theme-INDEPENDENT --bb-glass-dark-* set, not the flipping
     --bb-glass-* set. The 18px radius + the legend's own shadow are kept as
     established here (layout/look unchanged); only the material unifies. */
  background:var(--bb-glass-dark-bg) !important;
  color:var(--bb-glass-dark-ink) !important;
  -webkit-backdrop-filter:var(--bb-glass-blur);
  backdrop-filter:var(--bb-glass-blur);
  border:1px solid var(--bb-glass-dark-border) !important;
  border-radius:18px !important;
  box-shadow:0 14px 36px rgba(0,0,0,0.40),
             inset 0 1px 0 rgba(255,255,255,0.08) !important;
  font-family:var(--bb-font);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .glass-legend{ background:rgba(9,28,53,0.96) !important; }
}

/* Collapse summary + chevron (the vaarverkeer panels use <details>). */
.glass-legend.is-collapsible details summary,
.glass-legend summary{
  color:rgba(243,246,249,0.95) !important;
  font-weight:600;
}
.glass-legend.is-collapsible details summary::before{
  color:var(--bb-cyan) !important;
}
/* The standard-tour Canal-info legend (.vaarregels-legend) rolls its own
   caret span (.vr-caret) instead of the ::before chevron - recolour it cyan
   to match, so the dark-glass skin reads correctly there too. */
.glass-legend .vr-caret{ color:var(--bb-cyan) !important; }
/* Collapsed pill state: keep the dark glass + cyan border (the base
   .gmaps-legend collapsed rule flips it back to white - override it). */
.glass-legend.is-collapsible:not(:has(details[open])){
  background:rgba(9,28,53,0.72) !important;
  border:1px solid rgba(105,254,255,0.40) !important;
  box-shadow:0 6px 18px rgba(0,0,0,0.38) !important;
}

/* Cyan uppercase section label (mirrors .lt-sim-section-label). Both the
   shared .glass-grp class and any <strong> tone-setters read as cyan. */
.glass-legend .glass-grp{
  font-size:0.62rem;font-weight:700;letter-spacing:0.1em;text-transform:uppercase;
  color:rgba(105,254,255,0.88) !important;
  margin:12px 0 5px;
}
.glass-legend .glass-grp:first-child{ margin-top:4px; }

/* Body text inside the panel reads near-white; muted sub-text dims via
   opacity so it never hardcodes a colour that fails on the dark glass. */
.glass-legend a{ color:var(--bb-cyan) !important; }
.glass-legend strong{ color:rgba(243,246,249,0.95); }

/* ── iOS-style switch toggle row (.glass-switch) ──
   A full-width tappable row (>= 40px tall) with the label on the left and
   a sliding pill switch on the right. The real <input type=checkbox> is
   visually hidden but stays in the DOM (same id / change handler), so all
   existing wiring fires unchanged; :checked drives the track + knob. */
.glass-switch{
  display:flex;align-items:center;gap:10px;
  min-height:40px;padding:6px 2px;cursor:pointer;
  font-size:0.8rem;line-height:1.25;
  color:rgba(243,246,249,0.92);
  -webkit-tap-highlight-color:transparent;
}
.glass-switch .glass-switch-lbl{ flex:1 1 auto; }
.glass-switch .glass-switch-lbl small,
.glass-switch .glass-switch-sub{
  display:block;font-size:0.68rem;color:inherit;opacity:0.62;font-weight:400;
}
.glass-switch .glass-switch-cnt{
  font-variant-numeric:tabular-nums;
  color:rgba(243,246,249,0.7);font-size:0.7rem;
  background:rgba(255,255,255,0.10);
  padding:1px 7px;border-radius:8px;min-width:20px;text-align:center;
  flex:0 0 auto;
}
/* Hide the native box but keep it in the layout / tab order. */
.glass-switch input[type="checkbox"]{
  position:absolute;opacity:0;width:0;height:0;margin:0;pointer-events:none;
}
/* The visual track (40 x 24) + sliding knob. Sits at the row's right edge. */
.glass-switch .glass-track{
  position:relative;flex:0 0 auto;
  width:40px;height:24px;border-radius:999px;
  background:rgba(255,255,255,0.16);
  border:1px solid rgba(255,255,255,0.18);
  transition:background 180ms var(--bb-ease), border-color 180ms var(--bb-ease);
}
.glass-switch .glass-track::after{
  content:'';position:absolute;top:2px;left:2px;
  width:18px;height:18px;border-radius:50%;
  background:#fff;box-shadow:0 1px 3px rgba(0,0,0,0.4);
  transition:transform 180ms var(--bb-spring);
}
.glass-switch input:checked + .glass-track{
  background:var(--bb-blue);
  border-color:rgba(105,254,255,0.5);
}
.glass-switch input:checked + .glass-track::after{ transform:translateX(16px); }
.glass-switch input:focus-visible + .glass-track{
  box-shadow:var(--bb-focus-ring-on-navy);
}

/* Colour swatch that sits before a switch label (vaarinfo layer rows). Kept
   visible on the dark glass via a thin light ring. */
.glass-switch .glass-sw{
  flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
}
.glass-switch .glass-sw-line{
  width:20px;height:3px;border-radius:2px;background:var(--bb-red);
}
.glass-switch .glass-sw-dot{
  width:13px;height:13px;border-radius:50%;
  border:1.5px solid rgba(255,255,255,0.85);
  box-shadow:0 0 0 1px rgba(0,0,0,0.25);
}
.glass-switch .glass-sw-pin{
  width:15px;height:15px;border-radius:50%;
  border:1.5px solid rgba(255,255,255,0.85);
  box-shadow:0 0 0 1px rgba(0,0,0,0.25);
  color:#fff;font-size:9px;font-weight:700;line-height:1;
  display:inline-flex;align-items:center;justify-content:center;
}

/* ── Segmented bulk row (Show all / Hide all) ──
   Pill-buttons that read on the dark glass (mirrors .lt-segmented look).
   NOTE: on vaarverkeer these buttons keep their legacy `.vv-bulk-btn` class
   (the JS click handler queries `.vv-bulk-btn`), and tour.css styles
   `.gmaps-legend.vv-types .vv-bulk-btn` with a higher specificity + a later
   source position. The surface-level properties below therefore use
   `!important` so the dark-glass skin wins over tour.css's light pill -
   safely, because these declarations are scoped under `.glass-legend`. */
.glass-legend .glass-bulk-row{
  display:flex;gap:6px;margin:2px 0 8px;
  padding:3px;border-radius:10px;
  background:rgba(255,255,255,0.08);
}
.glass-legend .glass-bulk-btn{
  flex:1;font:inherit;font-size:0.7rem;font-weight:600;letter-spacing:0.02em;
  background:transparent !important;border:0 !important;
  color:rgba(243,246,249,0.78) !important;
  border-radius:8px;padding:6px 8px;cursor:pointer;
  transition:background 160ms var(--bb-ease), color 160ms var(--bb-ease);
}
.glass-legend .glass-bulk-btn:hover,
.glass-legend .glass-bulk-btn:active{
  background:rgba(255,255,255,0.16) !important;color:#fff !important;
}

/* Divider used between blocks (AIS status / scope / rows). */
.glass-legend .glass-div{
  margin:8px 0;border:0;border-top:1px solid rgba(255,255,255,0.12);
}

/* Footer note + dashed top border (vaarinfo). */
.glass-legend .glass-foot{
  margin:10px 0 0;padding-top:9px;
  border-top:1px dashed rgba(255,255,255,0.14);
  font-size:10.5px;line-height:1.4;color:rgba(243,246,249,0.6);
}
.glass-legend .glass-foot strong{ color:rgba(243,246,249,0.78);font-weight:600; }

/* ── Vaarverkeer type-filter rows on the standard tour ──
   The AIS "Filter by type" panel in src/tour/tour.js carries BOTH the legacy
   .vv-type-row class (styled by src/tour/tour.css with a light pill + a
   visible native checkbox) AND the shared .glass-switch class. tour.css loads
   AFTER this file and its .gmaps-legend.vv-types selectors out-specify the
   bare .glass-switch rules, so the light skin would win. These higher-
   specificity selectors (scoped to .glass-legend.vv-types) re-assert the glass
   look there without touching the vaarinfo / vaarverkeer.html panels. */
.glass-legend.vv-types .vv-type-row.glass-switch{
  gap:10px;min-height:40px;padding:6px 2px;
}
/* Hide the native checkbox (tour.css's .vv-type-row input shows it). */
.glass-legend.vv-types .vv-type-row.glass-switch input[type="checkbox"]{
  position:absolute;opacity:0;width:0;height:0;margin:0;pointer-events:none;
}
/* Count chip reads on the dark glass (tour.css gives it a light pill). */
.glass-legend.vv-types .vv-type-row.glass-switch .vv-type-cnt{
  color:rgba(243,246,249,0.7);
  background:rgba(255,255,255,0.10);
}

@media (prefers-reduced-motion: reduce){
  .glass-switch .glass-track,
  .glass-switch .glass-track::after,
  .glass-legend .glass-bulk-btn{ transition:none; }
}
