/* public/css/app-shell.css
   STAP 2B -- publieke app-ervaring en look & feel.

   Deliberately a SEPARATE stylesheet, loaded only by public/index.html
   (never by public/admin.html). public/css/styles.css is not touched by
   this file or by this correction round at all -- so the admin
   environment, which loads only styles.css, is visually and functionally
   guaranteed untouched. This file freely reuses existing component classes
   from styles.css where they already fit (.card, .tag, .chip, .qstatus,
   .overlay/.sheet, form styles) and only adds NEW rules on top for the
   public app shell: the SANAUNDA/NA-accent wordmark, the idle/results
   start-screen behaviour, the mobile bottom sheet, and the list/map
   toggle. Nothing here redefines a selector that also exists in
   styles.css -- new, app-shell-prefixed class names only, so cascade order
   between the two files never matters.
*/

:root {
  /* A warmer, slightly more Caribbean-leaning extension of the existing
     brand tokens in styles.css (--pink/--ink/--bg etc, which stay exactly
     as they are for the admin environment). These are additive, new
     tokens -- nothing here overrides an existing --variable name. */
  --sa-fuchsia: #E6007E;
  --sa-anthracite: #171417;
  --sa-ink-soft: #3a3439;
  --sa-off-white: #fbf6f1;
  --sa-aqua: #dff2ef;
  --sa-aqua-deep: #2f8f86;
  --sa-sand: #f6ece0;
  --sa-line: #ece3da;
  --sa-shadow: 0 18px 50px rgba(49, 21, 34, 0.12);
  --sa-shadow-soft: 0 6px 20px rgba(49, 21, 34, 0.08);
  --sa-radius-lg: 26px;
  --sa-radius-md: 18px;
  --sa-radius-sm: 12px;
  --sa-safe-top: env(safe-area-inset-top, 0px);
  --sa-safe-bottom: env(safe-area-inset-bottom, 0px);
}

/* ==========================================================================
   App shell base
   ========================================================================== */
#appShell { background: linear-gradient(180deg, var(--sa-off-white), #fff 340px); min-height: 100dvh; }

/* ==========================================================================
   Sticky chrome -- header + search bar + suggestions travel together as
   one sticky block, always visible in both idle and results state (only
   the big hero mark and the idle-only extras below toggle). "Beheer" is
   deliberately NOT in here (section 21): the admin route still exists and
   works, it is just not a prominent link in the public interface any
   more -- a small, muted link remains in the footer only, so it stays
   reachable without competing with the search experience.

   app.js measures this block's real rendered height (it changes with
   language, viewport width and idle-vs-results state) and writes it into
   --sa-chrome-h, which .saMapStage's full-bleed results-mode layer (below)
   uses as its top offset -- more robust than a guessed fixed pixel value.
   ========================================================================== */
.saStickyChrome { position: sticky; top: 0; z-index: 40; background: rgba(251, 246, 241, 0.92); backdrop-filter: blur(14px); padding-top: var(--sa-safe-top); border-bottom: 1px solid var(--sa-line); }
.saHeaderRow { max-width: 1180px; margin: auto; padding: 14px 16px 4px; display: flex; align-items: flex-start; gap: 10px; }
.saHeaderRow .spacer { flex: 1; }

/* ==========================================================================
   Wordmark -- ONE single element (#brandMark), reused as-is in both idle
   and results state -- not two separate logo instances -- so there is
   never a risk of two marks rendering at once. Only its SIZE and layout
   change with #appShell[data-state], via CSS custom properties, not new
   markup: idle = big and centred with "by ECHT.BON" visible underneath
   (section 10's start-screen order); results = small and left-aligned,
   sub-line hidden, sitting inline with the language switch (matches a
   normal compact app header once actively searching).

   "Harde merkregel": the fuchsia accent sits under the FIRST "NA"
   (letters 3-4 of SANAUNDA), never under any other pair. Built by
   splitting config.brand.product_name into one <span> per letter
   (renderBrandmark() in app.js) so this stays correct even though the
   name itself stays config-driven, not hardcoded.

   Sizing is done entirely in em/relative units off the element's own
   font-size (set via --sa-mark-size below), so the accent tracks the
   3rd/4th letters at any element size -- no fixed-pixel offsets that could
   land under the wrong letters on a different screen width. Verified at
   4 breakpoints, see STAP2B_REPORT.md.
   ========================================================================== */
.saMark {
  display: inline-flex; flex-direction: column; align-items: flex-start; line-height: 1;
  font-size: 22px; /* results-state / default size */
  transition: font-size .18s ease;
  text-decoration: none; color: inherit; /* #brandMark is an <a>; undo the browser's default link underline/color */
}
.saMarkWord { display: inline-flex; font-weight: 900; letter-spacing: -0.01em; color: var(--sa-anthracite); }
.saMarkWord .saLetter { display: inline-block; }
/* STAP 2B.1 section 1: the accent under the first "NA" (letters 3-4 of the
   product name) must be a soft half-arc ("smile"), never a straight line,
   never under the wrong letter pair, and never at a fixed pixel position
   that could drift on a different screen. Built as an inline SVG (see
   renderBrandmark() in app.js) sized with width:100%/height:auto against
   its own viewBox -- exactly like a responsive image -- so it always
   scales together with the two letters it sits under, at any viewport
   width or idle/results .saMark font-size. Verified at 320/390/820/1440px,
   see STAP2B1_REPORT.md section I. */
.saMarkWord .saAccentPair { position: relative; display: inline-flex; padding-bottom: 0.3em; }
.saAccentArc { display: block; position: absolute; left: 0; bottom: -0.08em; width: 100%; height: 0.34em; overflow: visible; }
.saAccentArc path { fill: none; stroke: var(--sa-fuchsia); stroke-width: 9; stroke-linecap: round; }
/* STAP 2B correction round: text-transform: uppercase used to run here,
   which visually turned the required "by ECHT.BON" into "BY ECHT.BON" --
   the brief requires the literal lowercase "by" to be what's shown, not
   just what's in the markup. Removed. The modest letter-spacing (0.06em)
   is kept only as a subtle secondary-label touch; on lowercase text it no
   longer causes the "by" -> "B Y" splitting that the earlier uppercase
   version had. */
.saMarkSub { margin-top: 10px; font-size: 0.28em; font-weight: 800; letter-spacing: 0.06em; color: var(--sa-ink-soft); opacity: 0.82; display: none; }

/* Idle state: big, centred, with the "by ECHT.BON" sub-line visible --
   this is the section-10 start screen presentation. */
#appShell[data-state="idle"] .saHeaderRow { flex-direction: column; align-items: center; padding-top: 22px; }
#appShell[data-state="idle"] .saHeaderRow .spacer { display: none; }
#appShell[data-state="idle"] .saHeaderRow .saLangSwitch { margin-top: 14px; }
#appShell[data-state="idle"] .saMark { font-size: clamp(40px, 11vw, 72px); align-items: center; }
#appShell[data-state="idle"] .saMarkSub { display: block; }

/* .saMarkSub carries its own letter-spacing (0.06em, for a subtle secondary-
   label feel) -- but that would visually pull the "." away from the "T" in
   ECHT.BON, which the brief explicitly forbids. So the owner-brand text
   itself ("ECHT.BON") is wrapped in its own span with letter-spacing reset
   to 0, overriding the parent -- the "by " prefix keeps the (small) spaced
   feel, the "T." junction never gets pulled apart. */
.saMarkSub .saOwnerBrand { letter-spacing: 0; }

/* MINI-CORRECTIE STARTVRAAG ZICHTBAAR MAKEN: #pageH1 already held the
   correct config/i18n tagline text ("Wat zoek je op Bonaire?" / PAP / EN --
   see applyTagline() in app.js), it just carried the sr-only class, which
   hid it from sighted visitors. That class is removed from the element in
   index.html; this rule is the only styling it needs to read as a quiet,
   secondary line under the wordmark -- not a heavy page title -- directly
   above the search bar. #qLabel (the <input>'s real <label>) keeps its
   OWN sr-only class untouched, so the input still has exactly one visible
   question, not two. Sits between .saHeaderRow (mark + "by ECHT.BON") and
   .saSearchWrap, whose own top padding (18px) already gives room before
   the search bar -- margin-top here gives matching room above. Same rule
   in idle and results state -- section 3 asks only for visible + neatly
   styled, not a new state-conditional show/hide behaviour.

   letter-spacing is explicitly reset to normal here: styles.css (loaded
   on every page, admin included) has a generic `h1 { letter-spacing:
   -2.5px; ... }` rule sized for a much bigger heading elsewhere. This
   #pageH1 rule already overrides font-size/line-height/margin/max-width
   by being a higher-specificity ID selector, but never declared
   letter-spacing -- so that -2.5px leaked through, and at this small
   font-size it shrank the space character enough to visually run whole
   words together ("Watzoekjeop Bonaire?"). Resetting it here fixes that
   without touching styles.css itself (admin, which only loads
   styles.css, never sees #pageH1 at all). */
#pageH1 {
  max-width: 620px;
  margin: 12px auto 0;
  padding: 0 16px;
  text-align: center;
  font-size: clamp(21px, 5vw, 28px);
  font-weight: 800;
  letter-spacing: normal;
  color: var(--sa-anthracite);
  line-height: 1.2;
}

.saHomeSubline {
  max-width: 620px;
  margin: 7px auto 0;
  padding: 0 20px;
  text-align: center;
  font-size: clamp(13px, 3.4vw, 15px);
  font-weight: 500;
  color: var(--sa-ink-soft);
  line-height: 1.45;
}

.saSearchWrap { max-width: 640px; margin: 0 auto; padding: 14px 16px 10px; }

/* LIVEGANG 2026-10-06: behoud de eerder goedgekeurde mobiele kaartgeometrie.
   De grotere startvraag + subregel horen alleen bij de idle/homepage. Zodra er
   resultaten zijn, gebruikt de sticky chrome exact de oude compacte H1-maten
   en verdwijnt de subregel. Zo blijft --sa-chrome-h (en dus kaartfocus/zoom)
   gelijk aan de goedgekeurde basisversie. */
#appShell[data-state="results"] #pageH1 {
  max-width: 520px;
  margin: 10px auto 0;
  font-size: clamp(14px, 3.6vw, 16px);
  font-weight: 600;
  color: var(--sa-ink-soft);
  line-height: 1.35;
}
#appShell[data-state="results"] .saHomeSubline { display: none; }
#appShell[data-state="results"] .saSearchWrap { padding-top: 18px; }
.saSearchBar { display: flex; align-items: center; gap: 8px; background: #fff; border: 2px solid var(--sa-anthracite); border-radius: 999px; padding: 6px 6px 6px 20px; box-shadow: var(--sa-shadow); }
.saSearchBar input { flex: 1; min-width: 0; border: 0; outline: 0; background: transparent; font-size: 16px; padding: 12px 4px; }
.saSearchBar input::placeholder { color: #a89ea6; }
.saSearchBar button { border: 0; background: var(--sa-fuchsia); color: #fff; font-weight: 900; border-radius: 999px; padding: 13px 20px; font-size: 14px; min-height: 44px; }
.saSearchBar .saClear { display: none; border: 0; background: #f1ecef; color: var(--sa-ink-soft); width: 38px; height: 38px; border-radius: 50%; font-size: 16px; font-weight: 900; align-items: center; justify-content: center; min-height: 38px; }
.saSearchBar.hasQuery .saClear { display: inline-flex; }
/* Livegang 2026-10-06: het gestructureerde leeftijdsveld bestaat nog als
   technisch reserveveld buiten het formulier, maar is niet onderdeel van de
   zichtbare zoekbalk. Geen tweede kolom, scheidingslijn of lege ruimte. */
.saSearchWrap { position: relative; }
.saAgeField[hidden] { display: none !important; }
.saAgeError { position: absolute; left: 16px; right: 16px; top: calc(100% - 6px); z-index: 5; margin: 0; padding: 6px 12px; border-radius: 12px; background: #fff; box-shadow: var(--sa-shadow); text-align: center; font-size: 13px; font-weight: 700; color: #b3261e; }

.saQuickSearchLabel { text-align: center; margin-top: 10px; font-size: 12px; font-weight: 700; color: var(--sa-ink-soft); }
.saSuggestions { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 4px; padding: 12px 10px 4px; font-size: 13px; color: var(--sa-ink-soft); }
.saSuggestions button { border: 0; background: transparent; color: inherit; font: inherit; padding: 4px 2px; text-decoration: underline; text-decoration-color: transparent; text-underline-offset: 3px; transition: text-decoration-color .15s ease; min-height: 32px; }
.saSuggestions button:hover, .saSuggestions button:focus-visible { text-decoration-color: var(--sa-fuchsia); }
.saSuggestions .saDivider { opacity: 0.5; }

/* ==========================================================================
   Idle vs. results state (section 9, 13, 15). #appShell carries
   data-state="idle" | "results", toggled from app.js.

   .saResultsArea (containing BOTH the map and the sheet) is always
   present in the DOM once init() has run -- it is never display:none --
   because the map inside it is a SINGLE, persistent Leaflet instance (one
   #map div, created once in init()), reused whenever Kaart view becomes
   available rather than a fresh instance per search, per "gebruik waar
   mogelijk de bestaande werkende kaarttechniek" and to avoid the
   complexity/risk of juggling two Leaflet instances or re-mounting one.
   app.js calls map.invalidateSize() after each state/view change so
   Leaflet redraws correctly whenever it becomes visible again.

   STAP 2B.1 "UI-correctie kaartlogica": the SHEET (results list/count/
   toggle) is hidden in idle state exactly as before -- and the map (see
   ".saMapStage" below) is now ALSO hidden in idle state, and in every
   other state except "results + Kaart view + map-eligible". There is no
   more idle-only "calm background map".
   ========================================================================== */
#appShell[data-state="idle"] .saSheet { display: none; }
#appShell[data-state="results"] .saIdleExtras { display: none; }

.saMapPanel { position: relative; border-radius: var(--sa-radius-lg); overflow: hidden; box-shadow: var(--sa-shadow-soft); background: var(--sa-aqua); height: 100%; }
/* BLOK 1 ronde 7: eigen stacking context voor de kaart. Leaflet zet zijn
   lagen op z-index 400-1000 (pins 600, popup 700, knoppen 1000) en de
   sluitknop staat op 1100. Zonder isolatie kwamen die op desktop BOVEN het
   profiel (.overlay, z-index 60) en de sticky kop (40) uit: pins, popup en
   het kaart-kruisje bleven klikbaar door een open profiel heen ("nieuwe
   kaartlaag bovenop"). Nu blijft alles van Leaflet binnen het kaartpaneel. */
.saMapPanel { isolation: isolate; }
.saMapPanel #map { height: 100%; width: 100%; }

/* STAP 2B.1 "definitieve laatste correctieronde" Deel B: a subtle drop
   shadow so the fuchsia pin (see pinIcon() in app.js) stays clearly
   readable over any map tile color underneath it -- purely a visual
   legibility aid, not a second marker state/color. */
.saLocationPin svg { display: block; filter: drop-shadow(0 2px 3px rgba(23, 20, 23, 0.35)); }

.saResultsArea { position: relative; }

/* ==========================================================================
   STAP 2B.1 "UI-correctie kaartlogica": the map is hidden by default, in
   EVERY state and at EVERY viewport -- there is no more "calm idle
   background map" (section 1: "TOON NIET: kaart") and no more mobile
   pattern where the map sat full-bleed behind the results list at all
   times. It is shown for exactly one combination: results state, Kaart
   view actively chosen, AND app.js has determined the query is
   map-eligible (>=2 results, >=2 with a usable location -- see
   updateMapEligibility() in app.js, mirrored onto #appShell as
   data-map-eligible). The [data-map-eligible="true"] condition below is
   defense in depth -- app.js already forces the view back to "list"
   whenever a query stops being eligible -- so the map never becomes
   visible through a stale view-mode value alone.
   ========================================================================== */
.saMapStage { display: none; }
#appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saMapStage { display: block; }

/* STAP 2B.1 "UI-correctie kaartlogica": the Lijst/Kaart toggle itself is
   part of the sheet head, but must only ever appear when the map is
   actually eligible (section 3/4) -- otherwise there is only ever Lijst,
   with no toggle to choose from at all. */
#appShell:not([data-map-eligible="true"]) .saViewToggle { display: none; }

/* Default result panel (Lijst -- the only view whenever the map is not
   eligible, and the default view even when it is): a plain, in-flow,
   full-page panel. No fixed "bottom sheet floating over a full-bleed map"
   positioning here any more -- there is no map to float over. This is the
   same static/in-flow treatment the >=900px breakpoint already gave the
   sheet before this step; it now applies at every viewport for the same
   reason (no map behind it to reserve fixed screen space for). */
.saSheet {
  position: static; height: auto; max-height: none; width: auto;
  background: #fff; border-radius: 22px 22px 0 0; box-shadow: 0 -12px 40px rgba(49,21,34,.18);
  padding-bottom: calc(14px + var(--sa-safe-bottom));
  display: flex; flex-direction: column;
  touch-action: auto;
}
.saSheetHandleRow { display: none; } /* only meaningful for the floating map-view sheet, see the map-view block below */
.saSheetHandle { width: 42px; height: 5px; border-radius: 999px; background: #ddd3d8; }
.saSheetHead { flex: 0 0 auto; display: flex; align-items: center; gap: 10px; padding: 12px 16px 10px; }
.saSheetTitle { font-weight: 900; font-size: 15px; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.saViewToggle { display: inline-flex; background: #f1ecef; border-radius: 999px; padding: 3px; gap: 2px; flex: 0 0 auto; }
.saViewToggle button { border: 0; background: transparent; padding: 7px 12px; border-radius: 999px; font-size: 12px; font-weight: 850; color: var(--sa-ink-soft); min-height: 32px; }
.saViewToggle button.active { background: var(--sa-anthracite); color: #fff; }
.saSheetBody { flex: 1 1 auto; overflow: visible; padding: 0 12px 4px; -webkit-overflow-scrolling: touch; }

/* ==========================================================================
   Kaart view (mobile/tablet only, <900px -- see the desktop breakpoint
   further down for its own, already-static, non-overlay Kaart layout).
   Only reachable when data-map-eligible="true" (app.js never sets
   data-view="map" otherwise), so this block is exactly the previous,
   already-approved "map full-bleed behind a floating bottom sheet" pattern
   from STAP 2B/2B.1 -- unchanged in its own mechanics, just now scoped to
   the one state it is actually allowed to occur in.
   ========================================================================== */
@media (max-width: 899.98px) {
  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saMapStage {
    position: fixed; left: 0; right: 0; top: var(--sa-chrome-h, 132px); bottom: 0; height: auto; margin: 0; z-index: 5;
  }
  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saMapStage .saMapPanel { border-radius: 0; box-shadow: none; }

  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saSheet {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 35;
    border: 0; margin: 0;
    height: 128px;
    /* The sheet is bottom-anchored with a height, not a top+bottom box, so a
       tall height can push its top edge above the sticky chrome (header +
       search + suggestions) on short viewports -- which would hide the drag
       handle behind the header and leave it unclickable. --sa-chrome-h (see
       updateChromeHeight() in app.js) is the chrome's real measured height,
       so capping max-height against it guarantees the handle always stays
       below the chrome and reachable, on any viewport or language (string
       length changes the chrome's height too). */
    max-height: min(82vh, calc(100vh - var(--sa-chrome-h, 132px) - 8px));
    transition: height .22s ease;
    /* pan-y keeps native vertical scroll working inside the sheet on a
       touchscreen; there is no custom drag/swipe gesture engine here (the
       handle is a plain click/tap target, see wireAppShell() in app.js). */
    touch-action: pan-y;
  }
  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saSheet[data-sheet="full"] {
    height: min(82vh, calc(100vh - var(--sa-chrome-h, 132px) - 8px));
  }
  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saSheetHandleRow {
    display: flex; justify-content: center; padding: 9px 0 3px; cursor: pointer;
  }
  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saSheetBody { overflow: auto; }
  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saSheet[data-sheet="peek"] .saSheetBody { overflow: hidden; }
  /* Entering Kaart view always starts collapsed to this 128px peek strip
     (handle + toggle + count only) unless the person has explicitly
     expanded it to "full" via the handle -- same behaviour as before this
     step, just scoped to the one state it can occur in now. */
  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saSheet:not([data-sheet="full"]) { height: 128px; }
}

.saEmptyState { padding: 30px 16px 10px; text-align: center; }
.saEmptyState .saEmptyIcon { font-size: 34px; }
.saEmptyState h3 { margin: 10px 0 4px; font-size: 17px; }
.saEmptyState p { margin: 0 0 16px; color: var(--sa-ink-soft); font-size: 13px; line-height: 1.5; }
.saEmptyState button { border: 0; background: var(--sa-fuchsia); color: #fff; font-weight: 900; border-radius: 999px; padding: 12px 18px; font-size: 13px; min-height: 44px; }

/* ==========================================================================
   Result cards -- reuse .card/.ico/.tags/.tag/.qstatus/.actions from
   styles.css (already compact and warm); only the surrounding grid here
   is new.
   ========================================================================== */
.saCardList { display: grid; gap: 9px; padding: 6px 4px 18px; }

/* ==========================================================================
   Idle-state extras: quiet stat line + the "organisatie aanmelden"
   invitation, both de-emphasised per sections 22-23 (not a dashboard, not
   a big technical block).
   ========================================================================== */
#statsLine { text-align: center; font-size: 12px; color: var(--sa-ink-soft); padding: 2px 16px 0; }
#statsLine strong { color: var(--sa-fuchsia); }

.saIdleExtras { max-width: 640px; margin: 10px auto 0; padding: 0 16px 28px; }
.saInviteCard { display: flex; align-items: center; gap: 12px; background: var(--sa-sand); border: 1px solid var(--sa-line); border-radius: var(--sa-radius-md); padding: 14px 16px; }
.saInviteCard p { margin: 0; font-size: 12.5px; color: var(--sa-ink-soft); flex: 1; }
.saInviteCard strong { display: block; font-size: 13.5px; color: var(--sa-anthracite); margin-bottom: 2px; }
.saInviteCard button { flex: 0 0 auto; border: 0; background: var(--sa-anthracite); color: #fff; font-weight: 900; border-radius: 999px; padding: 10px 14px; font-size: 12px; min-height: 40px; }

/* ==========================================================================
   Footer -- quiet, small admin link lives here only (section 21).
   ========================================================================== */
.saFooter { max-width: 1180px; margin: auto; padding: 18px 16px calc(28px + var(--sa-safe-bottom)); color: #8b8189; font-size: 11.5px; line-height: 1.6; display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: center; justify-content: space-between; }
.saFooterLinks { display: flex; gap: 14px; flex-wrap: wrap; }
.saFooterLinks a { color: #8b8189; text-decoration: none; font-weight: 700; }
.saFooterLinks a:hover, .saFooterLinks a:focus-visible { text-decoration: underline; }

/* ==========================================================================
   Language switch -- kept, restyled slightly quieter to match the app shell.
   ========================================================================== */
.saLangSwitch { display: flex; gap: 4px; }
.saLangSwitch button { border: 1px solid var(--sa-line); background: #fff; padding: 7px 10px; border-radius: 999px; font-weight: 850; font-size: 11px; min-height: 32px; color: var(--sa-ink-soft); }
.saLangSwitch button.active { background: var(--sa-anthracite); color: #fff; border-color: var(--sa-anthracite); }

/* ==========================================================================
   Accessibility (section 27): visible focus states everywhere in the app
   shell, real touch targets, no color-only meaning.
   ========================================================================== */
#appShell button:focus-visible, #appShell a:focus-visible, #appShell input:focus-visible {
  outline: 3px solid var(--sa-aqua-deep); outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .saSheet, .saSuggestions button { transition: none; }
}

/* ==========================================================================
   Tablet / desktop.

   STAP 2B.1 sections 11/16: SANAUNDA is primarily zoeken -> vinden, not a
   map-viewing tool, on ANY screen size -- so the STAP 2B desktop layout
   below (a permanent, always-visible 1.05fr/0.95fr map+results split, with
   the Lijst/Kaart toggle hidden entirely because "both are visible side by
   side anyway") is exactly what this step changes. Lijst is now the
   default on desktop too, shown full-width and roomy with no map alongside
   it; the toggle stays visible so a person can still actively choose
   Kaart, which then becomes the roomy primary view instead of a permanent
   second column. This is a layout/CSS change only -- the same
   #appShell[data-view="list"|"map"] state machine STAP 2B already built
   for mobile now also drives desktop, instead of desktop ignoring it.
   ========================================================================== */
@media (min-width: 900px) {
  #appShell[data-state="idle"] .saHeaderRow { padding-top: 46px; }
  #appShell[data-state="idle"] .saMark { font-size: clamp(56px, 6vw, 78px); }

  .saResultsArea {
    max-width: 1180px; margin: 0 auto; padding: 0 16px 30px;
    display: grid; grid-template-columns: 1fr; gap: 16px; align-items: start;
  }
  /* STAP 2B.1 "UI-correctie kaartlogica": idle no longer shows a map at all
     (section 1) -- the old "calm, compact, pin-free centred map" idle
     treatment that used to live here has been removed; .saMapStage's base
     rule (display: none) already covers idle on every viewport, so no
     idle-specific override is needed here any more. */

  /* Kaart (map) view: the map becomes the primary, roomy view (section H of
     the STAP 2B.1 report this builds on) instead of a fixed-height side
     column. The results list stays reachable underneath rather than
     disappearing outright, but is intentionally secondary/compact here.
     [data-map-eligible="true"] is defense in depth -- app.js never sets
     data-view="map" for an ineligible query -- see the mobile breakpoint
     above for the equivalent comment. */
  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saMapStage {
    position: static; height: min(70vh, 640px); margin: 0; z-index: auto;
  }
  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saMapStage .saMapPanel { border-radius: var(--sa-radius-lg); box-shadow: var(--sa-shadow-soft); }
  #appShell[data-state="results"][data-view="map"][data-map-eligible="true"] .saSheetBody { max-height: 220px; }

  .saSheet {
    border-radius: var(--sa-radius-lg);
    box-shadow: var(--sa-shadow-soft); border: 1px solid var(--sa-line);
    padding-bottom: 0; min-width: 0;
  }
  /* Without min-width: 0, a CSS grid item's automatic minimum width is its
     content's min-content size -- and the (horizontally-scrollable, by
     design) .chips category row is much wider than either grid column once
     all ~23 categories are in it. min-width: 0 makes the grid item respect
     the track sizing instead of forcing extra columns open; kept for
     .saMapStage too, for the same reason, now that it participates in the
     grid only in Kaart view. */
  .saMapStage { min-width: 0; }
  .saSheetBody { height: 560px; display: block; overflow: auto; }
  /* STAP 2B.1 section 16 (carried over from the report this builds on): the
     toggle must stay visible and functional on desktop too, whenever it is
     map-eligible -- see the shared, viewport-independent
     "#appShell:not([data-map-eligible='true']) .saViewToggle" rule above. */
}

/* ==========================================================================
   BLOK 1 (2e ronde): kaart-sluitknop en keuzelijst bij overlappende pins.
   z-index boven Leaflet (panes 400-700, controls 1000), binnen de eigen
   stacking context van .saMapPanel (ronde 7: isolation: isolate).
   ========================================================================== */
.saMapClose {
  position: absolute; top: 10px; right: 10px; z-index: 1100;
  width: 44px; height: 44px; border-radius: 999px; border: 0;
  background: var(--sa-anthracite, #2b2b2b); color: #fff; font-size: 24px; line-height: 44px; font-weight: 700;
  box-shadow: 0 2px 10px rgba(0,0,0,.25); cursor: pointer;
}
/* ==========================================================================
   Kaartcontrols -- één SANAUNDA-familie (acceptatiefix).
   primary   = fuchsia gevuld   -> Bekijk profiel
   outline   = fuchsia rand     -> Locatie (focus binnen SANAUNDA)
   secondary = zachte fuchsia   -> Google Maps ↗ (extern)
   nav       = fuchsia gevuld   -> ← Resultaten (kaartnavigatie)
   Het kruisje (.saMapClose) blijft bewust neutraal/zwart: sluitactie.
   ========================================================================== */
.saMapBtn {
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  min-height: 40px; padding: 0 14px; border: 2px solid var(--sa-fuchsia, #E6007E); border-radius: 999px; box-sizing: border-box;
  font: 700 13px/1 system-ui, sans-serif; white-space: nowrap; text-decoration: none; cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.saMapBtn:focus-visible { outline: 3px solid var(--sa-anthracite, #2b2b2b); outline-offset: 2px; }
.saMapBtn--primary, .saMapBtn--nav { background: var(--sa-fuchsia, #E6007E); color: #fff; }
.saMapBtn--primary:hover, .saMapBtn--nav:hover { background: #c4006b; border-color: #c4006b; }
.saMapBtn--primary:active, .saMapBtn--nav:active { background: #a3005a; border-color: #a3005a; }
.saMapBtn--outline { background: #fff; color: var(--sa-fuchsia, #E6007E); }
.saMapBtn--outline:hover { background: #fdeef6; }
.saMapBtn--outline:active { background: #f9d6e9; }
.saMapBtn--secondary { background: #fdeef6; border-color: #fdeef6; color: #8a0049; }
.saMapBtn--secondary:hover { background: #f9d6e9; border-color: #f9d6e9; }
.saMapBtn--secondary:active { background: #f3bcd9; border-color: #f3bcd9; }

/* "← Resultaten" alleen in locatie-focus, linksboven naast de zoomknoppen,
   binnen de eigen stacking context van de kaart. */
.saMapBackOverview {
  position: absolute; top: 10px; left: 56px; z-index: 1100;
  min-height: 44px; padding: 0 16px; font-size: 14px;
  box-shadow: 0 2px 10px rgba(23, 20, 23, .25);
}
.saMapBackOverview[hidden] { display: none; }
.saMapClose:focus-visible { outline: 3px solid var(--sa-fuchsia, #E6007E); outline-offset: 2px; }

/* Marker-hiërarchie: geselecteerde pin groot (pinIcon in app.js) en
   bovenop (zIndexOffset); overige resultaten klein en iets rustiger. */
.saPinWrap { position: relative; display: block; width: 28px; height: 38px; }
.saPinWrap.isSelected svg { filter: drop-shadow(0 2px 4px rgba(0,0,0,.45)); }
.saPinWrap.isRest svg { opacity: .82; filter: drop-shadow(0 1px 2px rgba(23, 20, 23, .3)); }

/* Locatie-focus: alleen de geselecteerde pin; overige markers en hun
   naamlabels tijdelijk niet getoond (puur presentatie, niet uit de laag). */
#map.saMapFocus .leaflet-marker-icon:not(.saPinSelected) { display: none; }
#map.saMapFocus .leaflet-tooltip { display: none; }
/* In focus staat de popup bovenin het kaartvlak, los van de pin (zie
   focusLayout): zonder pijltje, zodat hij de straat rond de pin niet afdekt. */
#map.saMapFocus .leaflet-popup-tip-container { display: none; }

/* Leaflet-popup van de geselecteerde pin. Bij exact dezelfde coördinaten
   staan alleen de organisaties van die pin erin. */
.saMapPopupWrap .leaflet-popup-content { margin: 10px 12px; }
.saMapPopup { list-style: none; margin: 0; padding: 0; min-width: 180px; }
.saMapPopupItem { display: flex; flex-direction: column; align-items: stretch; gap: 6px; padding: 6px 0; }
.saMapPopupActions { display: flex; gap: 6px; flex-wrap: wrap; }
.saMapPopupItem + .saMapPopupItem { border-top: 1px solid #f1ecef; }
.saMapPopupName { flex: 1; font-size: 13px; font-weight: 600; color: var(--sa-ink-soft, #555); }
.saMapPopupItem.isSelected .saMapPopupName { font-size: 14px; font-weight: 800; color: var(--sa-anthracite, #2b2b2b); }
/* Ronde 7: "← Kaart" in het profiel, alleen zichtbaar boven de open kaart. */
.saBackToMap {
  display: inline-flex; align-items: center; min-height: 40px; margin: 0 0 10px; padding: 8px 14px; border: 0; border-radius: 999px;
  background: var(--sa-fuchsia, #E6007E); color: #fff; font: 700 14px/1 system-ui, sans-serif; cursor: pointer;
}
.saBackToMap[hidden] { display: none; }

/* Huisstijl organisatieprofiel: de actieknoppen (← Kaart, Website, Bekijk
   locatie op kaart) in de officiële accentkleur, met dezelfde hover/active-
   waarden als de kaartknoppen. Lokaal in het profiel (#detail); de gedeelde
   .linkBtn in styles.css (ook door admin geladen) blijft ongewijzigd. Het
   kruisje (.close) blijft neutraal. */
#detail .linkBtn { background: var(--sa-fuchsia, #E6007E); color: #fff; transition: background-color .15s ease; }
.saBackToMap:hover, #detail .linkBtn:hover { background: #c4006b; }
.saBackToMap:active, #detail .linkBtn:active { background: #a3005a; }
.saBackToMap:focus-visible, #detail .linkBtn:focus-visible { outline: 3px solid var(--sa-anthracite, #171417); outline-offset: 2px; }

/* Standaard fallbackpunt (geen categorie-emoji) in de accentkleur, in het
   profiel en op de resultaatkaartjes. Emoji's blijven ongewijzigd. */
.saIconFallback { color: var(--sa-fuchsia, #E6007E); }
