# ScopePlay — public_html/.htaccess
#
# Upload this as public_html/.htaccess (cPanel File Manager hides dotfiles by
# default: Settings > Show Hidden Files).
#
# The identical file is mounted into the local Docker web container, so every
# rule below is exercised on http://localhost:8080 before it ever reaches the
# host. The one concession to that is the localhost guard in the redirect
# block — nothing else branches on environment.
#
# There are deliberately no SPA rewrite rules. The export is real HTML files
# and Apache should serve them directly.

Options -Indexes +FollowSymLinks

# ===========================================================================
# 1. Protected paths
#
# Credentials, logs, the vendored mailer and every operational file are denied
# over HTTP. PHP includes still reach them; browsers get a 403.
#
# These come first, and deliberately before any host branching. An earlier
# draft gated the whole rewrite section behind a localhost check with [L],
# which quietly skipped these rules in Docker — the deny worked in production
# and not locally, which is the exact divergence this setup exists to prevent.
# ===========================================================================
<IfModule mod_rewrite.c>
  RewriteEngine On

  RewriteRule ^api/config\.php$        - [F,L]
  RewriteRule ^api/(logs|lib)(/|$)     - [F,L]
  RewriteRule \.(sql|log|md|sh)$       - [F,L]
</IfModule>

# ===========================================================================
# 2. Canonical host and HTTPS
#
# Canonical form is the apex: https://scopeplay.co.za
# www.scopeplay.co.za redirects to it.
#
# Only the redirect is host-gated, so local Docker on http://localhost:8080 is
# not bounced to the live domain. Every other rule in this file applies
# identically in both places.
# ===========================================================================
<IfModule mod_rewrite.c>
  # Anything not already HTTPS goes to the canonical apex over TLS.
  RewriteCond %{HTTP_HOST} !^(localhost|127\.0\.0\.1|web)(:[0-9]+)?$ [NC]
  RewriteCond %{HTTPS} !=on
  RewriteCond %{HTTP:X-Forwarded-Proto} !=https
  RewriteRule ^ https://scopeplay.co.za%{REQUEST_URI} [R=301,L]

  # www -> apex, preserving the path.
  RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
  RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
</IfModule>

# Belt and braces, for the case where mod_rewrite is unavailable.
<Files "config.php">
  Require all denied
</Files>

<FilesMatch "\.(sql|log|md|sh)$">
  Require all denied
</FilesMatch>

<FilesMatch "^\.">
  Require all denied
</FilesMatch>

# ===========================================================================
# 3. Directory index
#
# This site is a static export: the home page is index.html and there is no
# index.php anywhere in it.
#
# Naming it explicitly matters because the server's own default prefers
# index.php, and a freshly provisioned Afrihost account ships one — the
# "Domain Registered" parking page. That file is not ours to delete, and a
# release deliberately leaves files it did not create alone, so without this
# line the parking page keeps winning at / and the site looks unreleased even
# after a completely successful upload.
# ===========================================================================
DirectoryIndex index.html

# ===========================================================================
# 4. Error document
# ===========================================================================
ErrorDocument 404 /404.html

# ===========================================================================
# 5. Compression
# ===========================================================================
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/xml
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/json
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE image/svg+xml
</IfModule>

# ===========================================================================
# 6. Caching
#
# Everything under /_next/static/ carries a content hash in its filename, so a
# one-year immutable cache is safe: a changed file gets a changed URL. The same
# goes for the Manrope woff2, which Next emits into /_next/static/media.
#
# HTML is revalidated on every request so a redeploy is picked up immediately.
# /assets holds the favicon and touch icon, whose names are stable — those get
# a week, long enough to matter and short enough to replace.
# ===========================================================================
<IfModule mod_rewrite.c>
  RewriteRule ^_next/static/ - [E=SP_IMMUTABLE:1]
</IfModule>

<IfModule mod_headers.c>
  Header always set Cache-Control "public, max-age=31536000, immutable" env=SP_IMMUTABLE

  <FilesMatch "\.woff2$">
    Header always set Cache-Control "public, max-age=31536000, immutable"
  </FilesMatch>

  <FilesMatch "\.html$">
    Header always set Cache-Control "no-cache"
  </FilesMatch>

  <FilesMatch "\.(txt|xml)$">
    Header always set Cache-Control "public, max-age=3600"
  </FilesMatch>
</IfModule>

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/svg+xml "access plus 7 days"
  ExpiresByType image/png "access plus 7 days"
  ExpiresByType image/x-icon "access plus 7 days"
</IfModule>

# ===========================================================================
# 7. Security headers
#
# The CSP allows inline styles, because the design leans on them throughout.
# It does not allow inline scripts. Next.js in export mode inlines its
# hydration payload as several src-less <script> blocks, so instead of opening
# script-src up with 'unsafe-inline', each block is hashed into the policy.
#
# Those hashes contain the build id, so they change on every build. The block
# between the CSP markers is rewritten by the `postbuild` hook in package.json
# on every `npm run build` — never edit it by hand, and never upload this file
# from a different build than the HTML beside it, or the page will render and
# then sit there dead.
# ===========================================================================
<IfModule mod_headers.c>
  Header always set X-Content-Type-Options "nosniff"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set X-Frame-Options "SAMEORIGIN"

  # Every capability the browser will let us decline. Features Chrome does not
  # recognise are left out on purpose — listing them only produces console
  # warnings on every page load without denying anything.
  Header always set Permissions-Policy "accelerometer=(), autoplay=(), browsing-topics=(), camera=(), display-capture=(), encrypted-media=(), fullscreen=(), gamepad=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), local-fonts=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), serial=(), storage-access=(), usb=(), window-management=(), xr-spatial-tracking=()"

  # CSP-BEGIN (generated by deploy/csp-hashes.mjs on every build — do not edit by hand)
  Header always set Content-Security-Policy "default-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; object-src 'none'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'sha256-/Uh+E6fgx7V7kpmApx8nd8lM/DMKvRWGlod45o1DoJ0=' 'sha256-7KffNXFi1FmhJ5JY7W0Xq/cAgIIrW3NuhR+L9NkikCo=' 'sha256-OBTN3RiyCV4Bq7dFqZ5a2pAXjnCcCYeTJMO2I/LYKeo=' 'sha256-QLvyXHapt1+BLf6y8OtHMkuKpr7VveGnZQpG8xGzNFs=' 'sha256-RxLgu9Ju48XQDmkew08jxm6P1KMtnM0ozZ/0BVazZPA='; font-src 'self'; connect-src 'self' https://crm.scopeplay.co.za; manifest-src 'self'; upgrade-insecure-requests"
  # CSP-END

  # Nothing here should ever be indexed as a directory listing or framed.
  Header always set X-Permitted-Cross-Domain-Policies "none"
</IfModule>

# ===========================================================================
# 8. Charset
# ===========================================================================
AddDefaultCharset UTF-8
AddType application/json .json
AddType image/svg+xml .svg
AddType font/woff2 .woff2
