/* ═══ BluePark — ICON & CONTROL SYSTEM ═════════════════════════════════════════════════════
   SITE-WIDE, not campaign-scoped. This is a quality fix to the standing site, so it must keep
   working after the National Day campaign is archived.

   ── WHAT WAS ACTUALLY WRONG ────────────────────────────────────────────────────────────────
   Measured, not guessed, on the rendered page:

     • 155 inline <svg> in index.html; 91 of them are the 24×24 UI set, the rest are
       illustrations (fish, waves, blobs) and brand marks.
     • ZERO emoji used as interface icons, and ZERO external icon libraries. The site already
       had ONE family — it just wasn't consistent with itself.
     • stroke-width across that one family: 2, 1.9, 1.8, 1.4, 1.3, 1.2, 2.2, 2.4, 2.5, 3, 3.5.
       Ten weights. That is what reads as "inconsistent and generic".
     • header controls: .nutil 40×40 r11, .bp-night-toggle 42×42 r12, .lang-switch 47×40 r999,
       and nav links only 26px tall. Three radii, three sizes, none reaching a 44px touch target.

   ── WHY LUCIDE AND NOT PHOSPHOR ────────────────────────────────────────────────────────────
   Phosphor was evaluated first, as instructed. Its icons are FILLED paths on a 256×256 viewBox
   (fill="currentColor", no stroke). Adopting it would mean converting every icon on the site
   from a light stroke to a solid fill — a whole-site restyle away from BluePark's existing
   personality, which the same brief asks to preserve.

   Lucide is 24×24, fill="none", stroke="currentColor", stroke-width 2, round caps and joins —
   structurally IDENTICAL to what the site already draws by hand. So it standardises the family
   without changing how BluePark looks. ISC licensed. See assets/nd96/ICON-LEDGER.md.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */

/* ── 1. ONE stroke standard for the whole 24×24 family ─────────────────────────────────────
   CSS properties beat SVG presentation attributes, so this normalises all ten inline weights
   at once without editing 91 tags in a 481KB file. Icons that are drawn as FILLS (brand marks,
   social logos, the solid star) set fill and no stroke, so they are untouched by these rules. */
.bp-ico,
svg.bp-ico {
  width: 1em;
  height: 1em;
  stroke-width: 2px;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: -0.125em;
  flex: 0 0 auto;
}
/* the fill variants opt out explicitly, by their own class, rather than by accident */
.bp-ico.fill { stroke-width: 0; }

/* ── 2. ONE control-button standard (§23) ──────────────────────────────────────────────────
   Same touch target, same radius, same optical centre, same hover and pressed states, same
   backdrop. 44px is the floor everywhere; 46 on coarse pointers. */
.nutil,
.bp-night-toggle,
.lang-switch,
.bp-ctl {
  --bp-ctl-size: 44px;
  min-width: var(--bp-ctl-size);
  height: var(--bp-ctl-size);
  border-radius: 13px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 10px;
  font-size: 20px;                /* the icon inherits this via width:1em */
  line-height: 1;
  transition: background-color .18s ease, transform .12s ease, box-shadow .18s ease;
}
.nutil, .bp-night-toggle { padding: 0; width: var(--bp-ctl-size); }

/* The night toggle already carried width/height/radius with !important — a pre-existing hack
   that pinned it to 42×42 r12 while its neighbours were 40×40 r11 and 47×40 r999. Matching the
   !important is the only way to bring it into the same system without unpicking that hack, which
   also controls the toggle's position and is not this change's business. */
.bp-night-toggle {
  width: var(--bp-ctl-size) !important;
  height: var(--bp-ctl-size) !important;
  border-radius: 13px !important;
}
@media (max-width: 600px) {
  .bp-night-toggle { width: var(--bp-ctl-size) !important; height: var(--bp-ctl-size) !important; }
}

.nutil:hover,
.bp-night-toggle:hover,
.lang-switch:hover,
.bp-ctl:hover { box-shadow: 0 4px 14px rgba(19, 52, 74, .16); }

.nutil:active,
.bp-night-toggle:active,
.lang-switch:active,
.bp-ctl:active { transform: translateY(1px); }

/* one focus ring for all of them — visible, and not the browser's default outline offset zero */
.nutil:focus-visible,
.bp-night-toggle:focus-visible,
.lang-switch:focus-visible,
.bp-ctl:focus-visible {
  outline: 2px solid var(--blue, #2A8FC4);
  outline-offset: 2px;
}

/* the language control carries text, so it may be wider — but never shorter */
.lang-switch { border-radius: 13px; font-size: 14px; font-weight: 800; }

@media (pointer: coarse) {
  .nutil, .bp-night-toggle, .lang-switch, .bp-ctl { --bp-ctl-size: 46px; }
}

/* ── 3. nav links reach a real target height without changing the layout ────────────────── */
.nav a, .nav-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* ── 4. NO campaign-mode control treatment ─────────────────────────────────────────────────
   A "glass" variant was tried here: white text on a 13%-white fill while the campaign is active,
   on the assumption that the header floats over the dark campaign hero. It does not. The header
   carries its own light surface at scroll-top — the BluePark wordmark and the menu icon are dark
   on it — so the variant rendered the language control as WHITE "EN" ON WHITE, measured at a
   contrast ratio of 1:1. An invisible control is a worse outcome than an unstyled one.

   The standing header styling already has contrast in both themes and both scroll states. The
   campaign changes the ICONS' geometry and the buttons' size, and leaves their colour alone.
   bp-icons.test.mjs asserts that no campaign-scoped rule reappears here. */

@media (prefers-reduced-motion: reduce) {
  .nutil, .bp-night-toggle, .lang-switch, .bp-ctl { transition: none; }
  .nutil:active, .bp-night-toggle:active, .lang-switch:active, .bp-ctl:active { transform: none; }
}
