# Cloudflare Pages headers. Each rule is a path line followed by indented
# "Name: value" headers. Multiple matching rules merge (so /* security headers
# apply on top of the per-path cache rules below).

# ── Security headers (all responses) ──────────────────────────────────────────
#
# Why this policy is not tighter than it is — each of these was checked against
# the source before being left wide, so don't "fix" them without re-checking:
#
#   script-src 'unsafe-inline'  index.html carries ~300 inline event-handler
#       attributes (onclick=/onchange=/oninput=) plus 3 inline <script> blocks.
#       Handler attributes cannot be authorised by a hash or a nonce at all, so
#       dropping 'unsafe-inline' means porting every one to addEventListener
#       first. Real hardening, but a code change, not a header change.
#   style-src 'unsafe-inline'   MapLibre sets element styles inline, and Pages
#       serves a static file so there is no per-request nonce to hand out.
#   connect-src / img-src https:   users add their OWN raster sources (custom
#       WMTS/XYZ/WMS templates, see customSources in app.js), so the set of
#       reachable tile hosts is open-ended by design. An allowlist would break
#       the feature the moment someone points at an agency server we never
#       enumerated.
#   connect-src ws:             the LAN bridge connects to ws://localhost:4243
#       and to user-entered LAN addresses; wss: alone is not enough.
#
# 'unsafe-eval' was removed after confirming no eval()/new Function() survives
# in dist/assets/*.js. If a future dependency reintroduces eval the map will
# break loudly in console — re-check rather than pasting it back in.
#
# COEP is deliberately absent: it would require every cross-origin tile server
# to send CORP, which none of them do, and would blank the map.
#
# upgrade-insecure-requests is deliberately absent for the same reason ws: is
# allowed — it rewrites ws:// to wss://, which kills the LAN bridge the moment
# someone enters a plain LAN address like ws://192.168.1.100:8080.
#
# Permissions-Policy grants, all verified against real call sites — do not
# demote these to () without checking the source first:
#   geolocation      the whole point of the app
#   microphone       voice messages (MediaRecorder, app.js)
#   serial           MAVLink drone telemetry over USB serial
#                    (navigator.serial.requestPort, team-sync.js)
#   accelerometer/gyroscope/magnetometer   the compass (deviceorientation)
#   screen-wake-lock keeps the screen up while navigating
# Everything else is denied outright; none of those APIs appear in src/.
/*
  X-Content-Type-Options: nosniff
  X-Frame-Options: DENY
  Referrer-Policy: strict-origin-when-cross-origin
  Cross-Origin-Opener-Policy: same-origin
  Cross-Origin-Resource-Policy: same-site
  X-Permitted-Cross-Domain-Policies: none
  Strict-Transport-Security: max-age=31536000; includeSubDomains
  Permissions-Policy: geolocation=(self), microphone=(self), screen-wake-lock=(self), accelerometer=(self), gyroscope=(self), magnetometer=(self), serial=(self), fullscreen=(self), camera=(), usb=(), payment=(), bluetooth=(), hid=(), midi=(), idle-detection=(), local-fonts=(), display-capture=(), xr-spatial-tracking=(), browsing-topics=(), interest-cohort=()
  Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data: https:; connect-src 'self' https: wss: ws: blob: data:; worker-src 'self' blob:; child-src 'self' blob:; media-src 'self' blob: data:; frame-src 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; manifest-src 'self'

# ── Caching ───────────────────────────────────────────────────────────────────
# index.html + SW + manifest must always revalidate so deploys go live instantly.
/index.html
  Cache-Control: no-cache, no-store, must-revalidate
/service-worker.js
  Cache-Control: no-cache
/manifest.json
  Cache-Control: no-cache
# Content-hashed build output is safe to cache forever.
/assets/*
  Cache-Control: public, max-age=31536000, immutable
/icons/*
  Cache-Control: public, max-age=86400
