# ============================================================================
# AVRI Cakes
# Site rules first, then the SEO framework's blocks.
# ============================================================================

DirectoryIndex index.php index.html

# Never serve the site data or the SEO framework's data
RedirectMatch 404 ^/data/

<IfModule mod_rewrite.c>
  RewriteEngine On

  # ---- Repair links that arrive with the "#" turned into %23 ----
  # In app browsers, Instagram above all, hand us "index.php%23booking" as a
  # literal file name. Nothing by that name exists, so the server answered 404.
  # Send the visitor to the real anchor instead. NE stops Apache re encoding
  # the hash on the way back out.
  RewriteCond %{THE_REQUEST} "\s([^\s?]*)%(?:25)*23([^\s?]*)" [NC]
  RewriteRule ^ %1#%2 [NE,R=302,L]

  # ---- One clean address per place, no file names, no hashes ----
  # avricakes.ca/order, /gallery and so on.
  # Old addresses are sent to the clean one so nothing already shared breaks.
  RewriteCond %{THE_REQUEST} "\s(/+)index\.php[\s?]" [NC]
  RewriteRule ^index\.php$ %1 [R=301,L]

  RewriteCond %{THE_REQUEST} "\s(/+)(gallery|order|menu|reviews)\.php[\s?]" [NC]
  RewriteRule ^(gallery|order|menu|reviews)\.php$ %1%2 [R=301,L]

  # Same for a page built in the admin panel: page.php?p=about becomes /about.
  # Only a request typed or linked that way is redirected — the catch-all rule
  # further down rewrites internally, which never appears in THE_REQUEST, so
  # this cannot loop.
  RewriteCond %{THE_REQUEST} "\s(/+)page\.php\?p=([a-z0-9][a-z0-9-]*)[\s&]" [NC]
  RewriteRule ^page\.php$ %1%2? [R=301,L,NE]

  # A stray trailing slash still lands in the right place.
  RewriteRule ^(gallery|order|menu|reviews|home|favourites|faq)/+$ $1 [R=301,L]

  # --- this client's real pages -------------------------------------------
  RewriteRule ^gallery$  gallery.php [L]
  RewriteRule ^order$    order.php   [L]
  RewriteRule ^menu$     menu.php    [L]
  RewriteRule ^reviews$  reviews.php [L]

  # The home page sections answer on their own address and scroll into view.
  # NOTE: "about" is deliberately NOT here. AVRI's About is a real page the
  # baker writes herself in the Pages screen, so it must fall through to the
  # catch-all below and be served by page.php.
  RewriteRule ^(home|favourites|faq)$ index.php?s=$1 [L,QSA]

  # ---- Pages built in the admin panel ----
  # Anything that is not a real file or folder, and not one of the named
  # addresses above, is handed to page.php. If no page owns that address
  # page.php answers with the normal 404, so this cannot swallow mistakes.
  # This rule must stay LAST of the page rules, or it would shadow them.
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^([a-z0-9][a-z0-9-]{0,59})/?$ page.php?p=$1 [L,QSA]

  # ---- SEO framework: dynamic sitemap, robots and llms.txt ----
  RewriteRule ^sitemap\.xml$ seo/sitemap.php [L]
  RewriteRule ^robots\.txt$  seo/robots.php  [L]
  RewriteRule ^llms\.txt$    seo/llms.php    [L]

  # ---- SEO framework: block its stored config ----
  RewriteRule ^seo/data/ - [F,L]

  # ---- Serve WebP where the browser supports it and a .webp twin exists ----
  RewriteCond %{HTTP_ACCEPT} image/webp
  RewriteCond %{REQUEST_FILENAME} (?i)(.*)(\.jpe?g|\.png)$
  RewriteCond %1\.webp -f
  RewriteRule (?i)(.*)(\.jpe?g|\.png)$ $1.webp [T=image/webp,E=webp:1,L]
</IfModule>

# ---- SEO framework: smart 404 applies the panel's redirect map first ----
# ⚠ THIS PATH IS ABSOLUTE FROM THE DOMAIN ROOT, NOT FROM THIS FOLDER.
# Apache and LiteSpeed both resolve ErrorDocument against the document root,
# and there is no way to write it relative to the .htaccess. On a site that
# lives in a SUBFOLDER — this one is served from /avri-cakes/ — the line below
# has to carry that folder, or every 404 inside the site falls through to the
# host's own bare "Not Found" page: no redirect map, no link back to the
# website, and no clue which address failed. That is how a routing problem here
# once looked like a dead server.
#
#   site at the domain root   ->  ErrorDocument 404 /seo/404.php
#   site in a subfolder       ->  ErrorDocument 404 /folder/seo/404.php
#
# Change this one line when the site moves to its own domain.
ErrorDocument 404 /avri-cakes/seo/404.php

<IfModule mod_headers.c>
  Header append Vary Accept env=webp
  Header always set X-Content-Type-Options "nosniff"
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/plain text/css text/xml
  AddOutputFilterByType DEFLATE application/javascript application/json
  AddOutputFilterByType DEFLATE application/xml image/svg+xml
</IfModule>

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/webp        "access plus 1 year"
  ExpiresByType image/jpeg        "access plus 1 year"
  ExpiresByType image/png         "access plus 1 year"
  ExpiresByType image/svg+xml     "access plus 1 year"
  ExpiresByType image/x-icon      "access plus 1 year"
  ExpiresByType font/woff2        "access plus 1 year"
  ExpiresByType video/mp4         "access plus 1 year"
  ExpiresByType text/css          "access plus 1 month"
  ExpiresByType application/javascript "access plus 1 month"
  ExpiresByType text/html         "access plus 0 seconds"
</IfModule>

# ---------------------------------------------------------------------------
# Config files are not web pages.
#
# .user.ini was being served at https://the-site/.user.ini — it is only PHP
# limits, but a config file readable by anyone is a config file, and the same
# rule covers .env, composer files and editor leftovers if they ever land here.
# ---------------------------------------------------------------------------
<FilesMatch "^\.(user\.ini|htaccess|htpasswd|env|git.*)$|^(composer\.(json|lock)|package(-lock)?\.json|\.ai-manifest\.json)$">
  <IfModule mod_authz_core.c>
    Require all denied
  </IfModule>
  <IfModule !mod_authz_core.c>
    Order allow,deny
    Deny from all
  </IfModule>
</FilesMatch>

# ---------------------------------------------------------------------------
# Upload limits, for servers running PHP as an Apache module.
#
# The real settings live in /.user.ini, which is what Hostinger (LiteSpeed) and
# any PHP-FPM host read. This block is the equivalent for plain Apache mod_php,
# which ignores .user.ini entirely.
#
# ⚠ The <IfModule> guard is not optional. php_value outside it is a fatal
#   configuration error — a 500 on every page — on the CGI, FastCGI and
#   LiteSpeed setups most shared hosts actually use.
# ---------------------------------------------------------------------------
<IfModule mod_php.c>
  php_value upload_max_filesize 3M
  php_value post_max_size 8M
  php_value memory_limit 256M
  php_value max_execution_time 120
</IfModule>
<IfModule mod_php7.c>
  php_value upload_max_filesize 3M
  php_value post_max_size 8M
  php_value memory_limit 256M
  php_value max_execution_time 120
</IfModule>
