/*
Theme Name: Aqua Studio
Theme URI: https://egfishstore.com
Description: Aqua Studio — English-only WooCommerce child theme for egfishstore.com (Aqua Studio brand, Egypt-based aquarium e-commerce; Arabic planned as a later phase). Built on Storefront (see README.md for parent-theme justification). Implements the G2-approved design-token system (build/tokens.json) and the UX-spec structural requirements (lead-time-honesty at 5 checkpoints, single header/footer system, CPL 181/2018 disclosure blocks).
Author: Aqua Studio / Ali (Claude Code build lane)
Author URI: https://egfishstore.com
Template: storefront
Version: 2.9.6
Requires at least: 6.0
Tested up to: 6.6
Requires PHP: 7.4
Requires Plugins: woocommerce
Text Domain: aqua-studio
Domain Path: /languages
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/

/* ==========================================================================
   1. Tokens
   All color/type/spacing/radii/elevation/surface/badge values come from
   assets/css/tokens.css (compiled from build/tokens.json). Nothing in this
   file or any other theme CSS file should hardcode a hex/px value that
   already exists as a token — reference var(--token-name) instead.

   v2.9.0 — THE `@import url("assets/css/tokens.css")` THAT USED TO SIT HERE
   IS REMOVED, and this is the most consequential change in this release.

   ROOT CAUSE (confirmed by reading the LIVE computed styles on
   aquastudio.me while it served v2.8.0, not inferred): a CSS @import
   carries no `?ver=` query string. `style.css?ver=2.8.0` was cache-busted
   on every release; the token file it imported never was. Behind LiteSpeed
   Cache, production was therefore still serving the PRE-REBRAND "Living
   Water" token set — every value on build/tokens.json's own "refuses"
   blacklist:
       --color-ink-text-primary    #0D2A44 navy   (locked: #3A2A40 ink)
       --color-base-clear-mid      #2E8FB8 blue   (locked: #78417D violet)
       --color-base-luminous-deep  #123E63 navy   (locked: #673272)
       --color-base-lagoon-light   #DCEEF4 blue   (locked: #EFD8AC sand)
       --color-ink-text-inverse    #EAF6FB        (locked: #F9FDEC paper)
       --color-semantic-success-eco #2FA36B       (locked: #438F49)
       --cta-signal-primary        #C6402E rust   (locked: #673272)
       --type-display-en           Fraunces serif (locked: Baloo 2)
       --surfaces-lifted-tint      #F4FAFC        (locked: #F9FDEC)
       --radii-card                14px           (current: 18px)
       --spacing-nav-height        92px           (current: 148px)
   That single stale file is the true origin of the rust buttons (D4), the
   "display serif" product titles (D1 — the live face was Fraunces, never
   Baloo 2), the blue category-tile link (D7) and the pale blue-grey body
   copy (D9: navy ink at reduced opacity over bluish paper). Every palette
   correction shipped since v2.5.0 has been invisible on production.

   THE FIX: tokens.css is now enqueued as a real, VERSIONED stylesheet
   (functions.php, handle `aqua-studio-tokens`, a dependency of
   `aqua-studio-style`), so it is cache-busted by every release and heals
   itself. The block below then re-declares the LOCKED brand values here,
   in the file that is guaranteed cache-busted — so even if a stale
   tokens.css survives in a cache layer we do not control, the brand can no
   longer come out wrong. tokens.css / build/tokens.json remain the
   generated single source of truth; this block is a deliberate,
   documented mirror of the locked subset and must be updated with them.
   ========================================================================== */
:root {
	/* Locked palette — BRAND.md / master-plan §1. Never change these six. */
	--color-base-lagoon-light: #EFD8AC;      /* sand         */
	--color-base-clear-mid: #78417D;         /* violet       */
	--color-base-luminous-deep: #673272;     /* deep purple  */
	--color-ink-text-primary: #3A2A40;       /* ink          */
	--color-ink-text-inverse: #F9FDEC;       /* paper        */
	--color-semantic-success-eco: #438F49;   /* emerald      */
	--color-semantic-reef-coral-magenta: #78417D;

	/* Six distinct category hues (v2.5.0 palette-collapse fix). */
	--color-category-keys-main-brand: #673272;
	--color-category-keys-freshwater: #1C5F4F;
	--color-category-keys-freshwater-tint: #DDEEEA;
	--color-category-keys-planted-accent: #57772C;
	--color-category-keys-planted-pip: #374F17;
	--color-category-keys-marine: #673272;
	--color-category-keys-coral-accent: #BF4A6D;
	--color-category-keys-coral-pip: #7E2540;
	--color-category-keys-coral-tag: #E6BCC9;
	--color-category-keys-automation: #656383;
	--color-category-keys-livestock: #EFD8AC;

	/* v2.9.0 D4 — primary action. Deep Purple (8.9:1 on paper). The old
	   #941E75 was off-palette; production was serving the banned #C6402E. */
	--cta-signal-primary: #673272;
	--cta-pip-livestock: #EFD8AC;

	/* Locked type — Baloo 2 (display) + Inter (text). No other faces.
	   v2.9.0 BUG FIX: these MUST be quoted. A CSS <family-name> is a
	   sequence of identifiers and an identifier cannot begin with a digit,
	   so the previous unquoted `Baloo 2` expanded to
	   `font-family: Baloo 2, Georgia, serif` — invalid, and browsers drop
	   the entire declaration. Verified in a live browser: the unquoted form
	   computed to the INHERITED family, meaning the locked display face
	   never actually applied to any heading; the quoted form resolves
	   correctly. Both generators (build/tokens-to-css.php and its Python
	   stand-in) now emit these quoted too, so a regeneration cannot
	   reintroduce it. */
	--type-display-en: "Baloo 2";
	--type-text-en: "Inter";
	--type-hero-h1-en-px: 52px;
	--type-section-title-en-px: 28px;
	--type-body-en-px: 16.5px;
	--type-price-px: 23px;
	--type-badge-label-px: 12px;

	--spacing-board-padding-x: 48px;
	--spacing-nav-height: 96px; /* v2.9.4 TASK A — was 120px (v2.9.2 C5); 148px v2.9.0 D8; 124px v2.5.0; 92px orig. The tight-crop logo derivative is 2.16:1 instead of 1:1, so a 69px-tall box now carries a 69px-tall MARK (it was a 34px mark inside a 138px box). The band no longer has to be tall enough to hold three-quarters of empty canvas. */
	--spacing-card-gap: 22px;
	--spacing-card-body-padding: 18px 20px 22px 20px;
	--spacing-card-img-height: 168px;

	--radii-card: 18px;
	--radii-card-small: 12px;
	--radii-cta-button: 999px;
	--radii-badge-pill: 20px;
	--radii-nav-cat-chip: 20px;

	--elevation-card-shadow: 0 10px 28px rgba(103, 50, 114, .12);
	--elevation-hairline: rgba(103, 50, 114, .18);

	--surfaces-lifted-opaque: #FFFFFF;
	--surfaces-lifted-tint: #F9FDEC;
	--surfaces-lifted-deep-opaque: #673272;
	--surfaces-reef-darkest-gutter: #3A2A40;
}
/* v2.2.0: assets/css/rtl.css deleted (English-only conversion, task #50) —
   RTL-only CSS + its conditional enqueue no longer exist. */

/* ==========================================================================
   2. Reset / base box model
   ========================================================================== */
*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	-webkit-text-size-adjust: 100%;
}

body {
	margin: 0;
	background-color: var(--surfaces-lifted-tint);
	color: var(--color-ink-text-primary);
	font-family: var(--type-text-en), -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	font-size: var(--type-body-en-px);
	line-height: 1.55;
}

img,
svg {
	max-width: 100%;
	height: auto;
	display: block;
}

a {
	color: var(--color-base-clear-mid);
	text-decoration: none;
}

a:hover,
a:focus {
	text-decoration: underline;
}

/* ==========================================================================
   3. Typography scale
   Display face (Baloo 2) is reserved for hero H1 and section titles only
   — never body copy, never buttons, per token set + brand rule.
   ========================================================================== */
h1,
h2,
h3,
.aqua-display {
	/* v2.9.1 — D1 P0 (audit row 1.1). This stack used to fall back to
	   `Georgia, serif`. Baloo 2 is a rounded SANS — so every time Google
	   Fonts was slow, blocked, offline, or simply beaten by the render, the
	   whole site's headings and card titles fell through to a SERIF. That
	   is the actual mechanism behind the reported "giant serif titles"
	   defect: not a wrong token, a wrong fallback. Corrected to a sans
	   stack. NEVER use a serif fallback anywhere in this theme — if you are
	   adding a font-family declaration and the fallback chain does not end
	   in `sans-serif`, it is wrong. */
	font-family: var(--type-display-en), 'Trebuchet MS', system-ui, sans-serif;
	color: var(--color-ink-text-primary);
	font-weight: 600;
	line-height: 1.15;
	margin: 0 0 0.5em;
}

.aqua-hero-h1 {
	/* v2.4.0 — premium-finish pass: the flat 52px token read small/timid
	   against the rebuilt hero's generous board width on large desktops
	   ("big confident headline" instruction). Responsive clamp keeps the
	   52px token as the informed floor-ish baseline at typical widths but
	   lets it grow with confidence on wide viewports; never edits the
	   token itself (build/tokens.json stays the source of truth for the
	   base value — this is a presentation-layer override, same pattern as
	   the logo/page-title clamps elsewhere in this file). */
	font-size: clamp(var(--type-hero-h1-en-px), 4.6vw, 68px);
	letter-spacing: -0.01em;
}

.aqua-section-title {
	font-size: var(--type-section-title-en-px);
}

/* v2.9.1 — D1 P2 (audit row 6.5). Checkout carried bare `<h3>`/`<h4>` with
   no class, so they rendered at the raw browser heading scale in the
   display face while every other template used `.aqua-section-title` —
   checkout, of all pages, was the one that looked untouched. Those
   headings now carry the class; this modifier gives the genuinely
   subordinate one ("Estimated ship times", an h4 inside the order-review
   block) a smaller step so adding the class does not flatten the
   hierarchy by making every checkout heading the same size. */
.aqua-section-title--sub {
	font-size: 18px;
	font-weight: 600;
}

.aqua-price {
	font-size: var(--type-price-px);
	font-variant-numeric: tabular-nums;
	font-weight: 600;
	color: var(--color-ink-text-primary);
}

.aqua-badge-label {
	font-size: var(--type-badge-label-px);
	font-weight: 500;
	letter-spacing: 0.01em;
}

/* ==========================================================================
   4. Layout primitives
   ========================================================================== */
.aqua-board {
	max-width: 1320px;
	margin-left: auto;
	margin-right: auto;
	padding-left: var(--spacing-board-padding-x);
	padding-right: var(--spacing-board-padding-x);
}

/* v2.9.0 (Ali) — D8 ROOT CAUSE: this was a FIXED `height`, but
   `.aqua-site-header__inner` (§17) sets `flex-wrap: wrap`. Whenever the
   branding + nav + utilities row wrapped (any viewport narrow enough, and
   at the logo's own clamp maximum), the wrapped content grew taller than
   the 124px band while the band itself stayed 124px — so the branding
   block, whose logo SVG carries an opaque white 1024x1024 backing plate as
   its first <path> (the asset is LOCKED, we must not edit it), spilled out
   past the header's bottom hairline and painted a white box over the hero.
   `min-height` lets the band grow with its own content instead, so nothing
   can ever escape it; the fixed value stays the FLOOR so the header keeps
   its designed presence on a normal single-row layout. Vertical padding
   added for the same reason — the logo now has real breathing room inside
   the band rather than sitting flush against its edges. */
.aqua-nav {
	position: relative;
	min-height: var(--spacing-nav-height);
	/* v2.9.2 (Ali) — C5. Band padding cut 10px -> 4px and the
	   --spacing-nav-height FLOOR cut 148px -> 120px, so the band is sized
	   by the logo box it contains instead of by a fixed value that exceeded
	   it. Measured live before: band 160.07px around a 132px logo box.
	   After: 146px around a 138px box. See the .aqua-site-branding__logo
	   rule below for the honest limit on how far this can go. */
	/* v2.9.4 (Ali) — TASK A. Padding restored 4px -> 12px. v2.9.2 had to
	   squeeze it to 4px because the logo box was 138px tall inside a band
	   that could not grow much further; with the tight-crop derivative the
	   box is 69px, so the band can be BOTH shorter overall and more
	   generously padded around the mark at the same time.
	   Measured, all three checked widths: tallest flex child is the 69px
	   logo (desktop) / the 46px logo and 40px hamburger (mobile), and the
	   tallest utility is the 38px search toggle — so content + 24px padding
	   = 93px desktop, 70px mobile, both under the 96px floor. Band resolves
	   to a flat 96px at 390 / 768 / 1440, down from 120 / 120 / 146px.
	   `min-height` (NOT height) is retained deliberately: it is the v2.9.0
	   D8 fix that stops a wrapped row from spilling the branding block past
	   the header's bottom hairline and painting over the hero. */
	padding-top: 12px;
	padding-bottom: 12px;
	display: flex;
	align-items: center;
	border-bottom: 1px solid var(--elevation-hairline);
	background: var(--surfaces-lifted-opaque);
}

.aqua-card-grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
	gap: var(--spacing-card-gap);
}

/* v2.9.2 (Ali) — C3. The v2.5.0 bento above (node 1 spanning 2x2, node 6 a
   full-width banner) is REPLACED by an even 3-column grid. Reason, measured
   live on https://aquastudio.me/ at a 1512px viewport rather than inferred:
   the featured tile rendered 601x795px while its own content — a 601px
   square photo plus a 107px caption body — totalled 708px, leaving 87px of
   empty white card below the caption; every other tile measured a gap of
   exactly 0. Nothing in the theme can legitimately fill that 87px: a tile
   is a photo plus a one-line label, and inventing an ornament, motif or
   filler graphic to occupy it is barred outright by the no-authored-
   graphics rule. So the span is dropped rather than padded. Six equal
   tiles resolve to two clean rows of three, every card flush and the same
   height, which is the deliberate-plain option the brief asks for over a
   ragged asymmetric one. Markup and source order are untouched — this
   stays CSS-only, and removing the grid-template-areas also retires the
   nth-child(1)/nth-child(6) special cases (the 16/5 banner ratio and the
   featured-caption size bump) that only existed to service the bento. */
.aqua-home__category-grid {
	grid-template-columns: repeat(3, 1fr);
}

/* v2.9.2 — the homepage tiles are an editorial showcase, so their caption
   may run a little larger than the 15px commerce-grid title, but it must
   scale with the tile. The shared `.aqua-card__title` rule (§4) already
   guarantees wrapping, a 2-line reservation and left alignment. NOTE: this
   caption is now the ONLY name on the tile — see the v2.9.2 note in
   functions.php aqua_studio_render_category_tile() for why the second,
   clipped copy the owner reported was never DOM text at all. */
.aqua-home__category-grid .aqua-card__title {
	font-size: clamp(15px, 1.15vw, 18px);
}

@media (max-width: 900px) {
	.aqua-home__category-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 540px) {
	.aqua-home__category-grid {
		grid-template-columns: 1fr;
	}
}


.aqua-card {
	background: var(--surfaces-lifted-opaque);
	border-radius: var(--radii-card);
	box-shadow: var(--elevation-card-shadow);
	overflow: hidden;
}

.aqua-card-small {
	border-radius: var(--radii-card-small);
}

.aqua-card__img {
	/* v2.7.0 (Ali) — owner-reported defect: product-grid thumbnails were an
	   inset circular "specimen" avatar with a framing drop-shadow — reported
	   as "a circle with a photo inside, a strange texture behind/beneath
	   it." Reverted to a plain edge-to-edge rounded-top rectangle: no
	   invented shape, no separate frame shadow (the card itself already
	   carries its own shadow). Used by the category grid, homepage category
	   tiles, and PDP "Pairs well with" cross-sell cards — all three already
	   share this one class via aqua_studio_product_image_or_placeholder() /
	   front-page.php's direct wp_get_attachment_image() call, so one rule
	   reaches all three consistently. object-fit:cover means any real photo
	   aspect ratio still crops safely.

	   v2.8.0 §9 render-QA fix: when this class is merged onto the new
	   ".aqua-photo" wrapper (front-page.php's category tiles / the archive
	   header thumb call site — aqua_studio_render_category_tile()'s
	   $extra_class param), ":where(.aqua-photo)"'s own `height: 100%`
	   (zero specificity, by design — see that rule's own comment) was
	   resolving against the stretched CSS-grid-item height of the PARENT
	   `.aqua-card`, forcing the photo to consume the card's ENTIRE height
	   and pushing `.aqua-card__body` (title) entirely out of the
	   overflow:hidden card — captions rendered completely invisible, a
	   more severe version of the "clipped caption" defect this same wave
	   fixes. Explicit `height: auto` here — higher specificity than
	   `:where()` — wins that conflict and lets `aspect-ratio` alone govern
	   this element's own height, exactly the ":where() ... callers that
	   merge an existing sizing class must always win" contract this file
	   already documents. Contexts where .aqua-photo has NO extra class and
	   sits inside an already-sized parent (.aqua-world-card__media,
	   .aqua-archive__thumb, .aqua-world__gallery-item — all set their own
	   explicit width/height or aspect-ratio) are unaffected and still rely
	   on .aqua-photo's height:100% to fill that parent, unchanged. */
	width: 100%;
	height: auto;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	/* v2.9.2 (Ali) — C8, "two different systems". VERIFIED LIVE on
	   https://aquastudio.me/shop/: a card WITH a photo painted this box in
	   the flat paper tint (computed rgb(249,253,236), no border), while a
	   card WITHOUT one painted .aqua-img-placeholder in the sand->paper
	   wash PLUS a hairline border — so the same grid read as two unrelated
	   components, and any product photo with a transparent background sat
	   on bare white next to a sand neighbour. Both slots now carry the
	   IDENTICAL wash + hairline, so the frame behind every image in the
	   grid is one system. Same tokens, no new colour. */
	background: linear-gradient(155deg, var(--color-base-lagoon-light) 0%, var(--surfaces-lifted-tint) 72%);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card) var(--radii-card) 0 0;
	display: block;
	margin: 0;
}

/* v2.9.2 (Ali) — C8, the real cause of the reported ~23px title
   misalignment. MEASURED LIVE, not inferred: Storefront ships
   `ul.products li.product img { margin: 0 auto 1.618em }` (specificity
   0,2,3) which OUTRANKS `.aqua-card__img { margin: 0 }` (0,1,0) above, so
   every card with a real photo carried a computed margin-bottom of
   23.36px under its image while placeholder cards (a <div>, not an <img>,
   so the rule never matched) carried none. Both image boxes were already
   exactly 227.2px tall — the boxes were never the problem, this margin
   was, and it pushed the title of every photo card 23.4px below its
   placeholder neighbours in the same row. Re-stated here at 0,3,3 so it
   beats the parent rule instead of losing to it. */
ul.products li.product img.aqua-card__img,
ul.products li.product .aqua-card__img {
	margin: 0;
}

.aqua-card__body {
	padding: var(--spacing-card-body-padding);
}

/* v2.9.0 (Ali) — D1 + D5 + D7, the single biggest "amateur" signal on the
   shop grid. ROOT CAUSE: archive-product.php renders the loop title as
   `<h2 class="aqua-card__title">`, and v2.8.0's rule below set no family,
   size, weight or alignment — so every product title inherited §3's
   `h1,h2,h3` DISPLAY face (Baloo 2) at the browser's default h2 size
   (~1.5em ≈ 25px). A 60-character product name ("Blue Leg Hermit Crab x5 —
   Marine Cleanup Crew") therefore rendered as display type over 5 wrapped
   lines, blowing the card's height out and dropping the viewport to ~4
   cards. Benchmark (BulkReefSupply and every serious commerce grid): a
   compact SANS title, ~15px, max 2 lines, left-aligned.
   Fix, at the one class every caller already shares:
     - Inter (text face) explicitly — the display face is reserved for real
       page headings only, which is what §3's comment already claims but
       could not enforce through the h2 inheritance above.
     - 15px / 600 / 1.35, letter-spacing reset (Baloo 2's tracking is wrong
       for dense UI type), margin reset (h2 carries `margin: 0 0 .5em`).
     - Hard 2-line clamp PLUS a reserved min-height of exactly 2 lines, so
       every card's title block is the SAME height whether the title is one
       word or sixty characters — that reserved box is what makes a row of
       cards line up instead of going ragged.
     - text-align: left (D5 — the whole card stack was centred, which is
       what reads as an unconfigured template demo).
   The clamp box is exactly its own min-height, so unlike the v2.8.0
   situation it cannot be cropped by `.aqua-card`'s overflow:hidden — the
   element never exceeds the room reserved for it. Reaches category tiles,
   archive header thumb, Worlds cards and product/cross-sell cards alike.
   Previously v2.8.0 — fixed clipped category-tile labels (no explicit
   wrap/height rule); that fix is folded into the min-height below. */
.aqua-card__title {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	font-family: var(--type-text-en), -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	font-size: 15px;
	font-weight: 600;
	letter-spacing: 0;
	color: var(--color-ink-text-primary);
	text-align: left;
	white-space: normal;
	overflow-wrap: break-word;
	word-break: normal;
	line-height: 1.35;
	min-height: calc(1.35em * 2);
	margin: 0 0 6px;
}

/* v2.9.0 — D5: left-align the ENTIRE card content stack (title, brand,
   price, badge, button). Applied at the card/body/actions level rather
   than per-element so nothing centred can survive anywhere this component
   is used, and applied to WooCommerce's own default loop item too (which
   Storefront centres) so non-theme loops — related products, upsells, any
   plugin-rendered [products] shortcode — match. */
.aqua-card,
.aqua-card__body,
.aqua-card__actions,
.woocommerce ul.products li.product,
.woocommerce-page ul.products li.product {
	text-align: left;
}

/* v2.9.0 — D2, second half: uniform card heights. The card is a flex
   column, the image slot is a fixed 1:1 box, the title block reserves a
   fixed 2 lines (above), and the actions row is pinned to the bottom with
   `margin-top: auto`. Result: every card in a row is the same height and
   every Add to Cart button sits on the same baseline, regardless of how
   long the title is or whether the product has a photo yet. */
ul.products li.aqua-card,
.aqua-card-grid > .aqua-card {
	display: flex;
	flex-direction: column;
}

.aqua-card__link {
	flex: 1 1 auto;
	display: flex;
	flex-direction: column;
}

.aqua-card__actions {
	margin-top: auto;
}

/* v2.8.0 — VISUAL EMERGENCY FIX: plain photo wrapper, replaces the deleted
   assets/css/aqua-mask.css duotone+grain+vignette treatment (functions.php
   aqua_studio_photo_wrap() / aqua_studio_photo_placeholder() emit this
   markup — see those docblocks). Full, crisp colour by default, always —
   category tiles, Worlds cards, product images, hero. The only interaction
   kept is a gentle hover/focus zoom (transform only, opt-in via
   --hover-zoom) — never a colour/saturation change. Same layout-agnostic
   contract the old mask had: border-radius is inherited from whatever
   sizing class the caller merges on (e.g. .aqua-card__img), so this file's
   own card/thumb shapes are unaffected. */
:where(.aqua-photo) {
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
	overflow: hidden;
	border-radius: inherit;
}

.aqua-photo__media {
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
	overflow: hidden;
	border-radius: inherit;
}

.aqua-photo__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.aqua-photo__media--empty {
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--color-base-luminous-deep);
}

.aqua-photo--hover-zoom .aqua-photo__media img {
	transition: transform 0.35s ease;
}

.aqua-photo--hover-zoom:hover .aqua-photo__media img,
.aqua-photo--hover-zoom:focus-within .aqua-photo__media img,
a:hover .aqua-photo--hover-zoom .aqua-photo__media img,
a:focus-visible .aqua-photo--hover-zoom .aqua-photo__media img {
	transform: scale(1.045);
}

@media (prefers-reduced-motion: reduce) {
	.aqua-photo--hover-zoom .aqua-photo__media img {
		transition: none;
	}
}

/* ==========================================================================
   5. CTA buttons — fill is ALWAYS the signal-primary token. Never the
   livestock pip color, never yellow/amber (refused zone, see tokens.json).
   ========================================================================== */
.aqua-cta,
.woocommerce a.button,
.woocommerce button.button,
.woocommerce #respond input#submit,
.woocommerce input.button,
.woocommerce-page a.button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5em;
	background-color: var(--cta-signal-primary);
	color: var(--color-ink-text-inverse);
	border: none;
	border-radius: var(--radii-cta-button);
	/* v2.9.0 (Ali) — D4: buttons were oversized (0.85em/1.4em on inherited
	   16.5px body type gave a ~48px tall pill for an in-card action).
	   Brought down to a normal control height and pinned to the text face
	   at an explicit 14.5px so a button never inherits the display face or
	   the body size. --cta-signal-primary itself moved #941E75 -> #673272
	   at the token source this version (see build/tokens.json): the old
	   value was a wine/rust magenta that is NOT one of the six locked
	   brand colours, and it was the "rust-red block" the owner flagged on
	   both Add to cart and the hero CTA. Deep Purple is the pick for
	   primary actions sitewide — Emerald (#438F49) was the alternative but
	   only reaches 3.89:1 against the paper text token, failing WCAG AA
	   for control-sized text; Deep Purple reaches 8.9:1 and stays the
	   brand's dominant hue. Emerald keeps its existing, distinct jobs
	   (success/eco semantics, the WhatsApp pill). */
	padding: 0.62em 1.15em;
	font-family: var(--type-text-en), -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	font-size: 14.5px;
	line-height: 1.3;
	font-weight: 600;
	cursor: pointer;
	transition: filter 0.15s ease;
}

.aqua-cta:hover,
.woocommerce a.button:hover,
.woocommerce button.button:hover,
.woocommerce #respond input#submit:hover,
.woocommerce input.button:hover {
	filter: brightness(0.92);
	color: var(--color-ink-text-inverse);
}

.aqua-hero__cta-row {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
	align-items: center;
}

.aqua-cta--secondary {
	background: transparent;
	color: var(--cta-signal-primary);
	border: 2px solid var(--color-base-lagoon-light);
	box-shadow: inset 0 0 0 1px var(--elevation-hairline);
}

.aqua-cta--secondary:hover {
	filter: none;
	background: var(--color-base-lagoon-light);
	color: var(--cta-signal-primary);
}

/* v2.8.0 — VISUAL EMERGENCY FIX: commerce signals. The shop/category
   product-grid card (templates/woocommerce/archive-product.php) already
   showed price; it was missing an Add to Cart control. This wraps a real
   woocommerce_template_loop_add_to_cart() call in its own row, a sibling to
   the card's <a> (not nested inside it — nesting an interactive WooCommerce
   button inside the card's own link would be invalid HTML). No new colour:
   the button itself already inherits the solid, high-contrast
   ".woocommerce a.button" fill above. Full-width so it reads as a clear,
   prominent action, same treatment applied to the PDP cross-sell card's
   existing button (.aqua-pairs-card__cta, §10) for consistency. */
.aqua-card__actions {
	padding: 0 20px 20px;
}

/* v2.9.0 (Ali) — D4 + D5: v2.8.0 made these buttons full-width blocks,
   which — once they were also rust-coloured — turned the loudest thing on
   every card into a solid bar. A normal-width control aligned to the
   card's LEFT edge (matching the title, price and badge above it) reads
   as a considered commerce card instead of a template demo. */
.aqua-card__actions,
.aqua-pairs-card__cta {
	display: flex;
	justify-content: flex-start;
}

.aqua-card__actions .button,
.aqua-pairs-card__cta .button {
	display: inline-flex;
	width: auto;
	max-width: 100%;
}

/* v2.1.0 — Advisory Commerce homepage */
.aqua-home__intent-dek,
.aqua-home__guides-dek {
	margin: 0 0 24px;
	font-size: var(--type-body-en-px);
	color: var(--color-base-clear-mid);
}

.aqua-intent-grid {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--spacing-card-gap);
}

.aqua-intent-card {
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card);
	padding: 22px 20px;
	box-shadow: var(--elevation-card-shadow);
	display: flex;
	flex-direction: column;
	gap: 8px;
	min-height: 148px;
	transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.aqua-intent-card:hover,
.aqua-intent-card:focus-within {
	transform: translateY(-3px);
	box-shadow: 0 14px 32px rgba(103, 50, 114, 0.14);
}

/* v2.9.1 — D9 P0 (audit rows 2.1-2.4 / 8.2). The circular badge that used
   to hold four hand-authored inline SVG icons (equalizer / DRAWN FISH /
   open book / chat bubble) is gone along with the artwork itself — see
   template-parts/home-intent-cards.php. What replaces it is TYPOGRAPHY on
   a flat tinted panel: the card's step number, set in the theme's own text
   face, on a rounded rectangle washed with a locked-palette tint. A digit
   is not a drawing and a rectangle is not a motif, so this carries no
   representational meaning and cannot regress the standing rule.
   The numeral is deep-purple on every variant (6.63:1 on sand, the
   tightest of the four) rather than per-variant colour, so no tint can
   push it under AA. Squared off, not circular, so it reads as a panel/
   label rather than as an icon slot waiting for an icon. */
.aqua-intent-card__step {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border-radius: var(--radii-card-small);
	flex: none;
	font-family: var(--type-text-en), Inter, system-ui, sans-serif;
	font-size: 15px;
	font-weight: 700;
	letter-spacing: .04em;
	font-variant-numeric: tabular-nums;
	color: var(--color-base-luminous-deep);
	user-select: none;
}

.aqua-intent-card__step--violet {
	background: rgba(120, 65, 125, .14);
}

.aqua-intent-card__step--emerald {
	background: rgba(67, 143, 73, .14);
}

.aqua-intent-card__step--sand {
	background: var(--color-base-lagoon-light);
}

.aqua-intent-card__step--purple {
	background: rgba(103, 50, 114, .12);
}

.aqua-intent-card__title {
	margin: 0;
	font-size: 16px;
	font-weight: 700;
}

.aqua-intent-card__desc {
	margin: 0;
	flex: 1;
	font-size: 13px;
	line-height: 1.45;
	color: var(--color-base-clear-mid);
}

/* v2.9.1 — D7 (audit row 8.1). Emerald --color-semantic-success-eco
   (#438F49) on the card's white surface measures 3.99:1, and 13px/700 does
   not qualify as large text (that needs >=18.66px bold), so this
   declaration was below AA as written. Repointed to --cta-signal-primary
   (deep-purple #673272, 9.23:1 on white). Emerald itself is NOT darkened —
   it is a locked primary, used correctly elsewhere at larger sizes and on
   darker grounds, so the fix belongs at the call site, not in the palette.
   NOTE: this rule does not actually win the cascade — `.aqua-board a` (§
   near the end of this file, 0,2,0) outranks it and always has. The rule
   that genuinely paints this link lives there, declaring the same value.
   Both are kept deliberately so the component still states its own intent
   at the point of definition; see that block's comment for the full
   writeup, including why the register's "3.99:1 live" reading was a
   cascade artefact. */
.aqua-intent-card__link {
	font-size: 13px;
	font-weight: 700;
	color: var(--cta-signal-primary);
	text-decoration: none;
}

.aqua-intent-card__link--chat {
	color: var(--cta-signal-primary);
}

.aqua-intent-card__link::after,
.aqua-guide-card__read-text::after,
.aqua-home__guides-more .aqua-guide-card__read-text::after {
	content: " →";
}

.aqua-guides-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--spacing-card-gap);
}

.aqua-guide-card {
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card);
	box-shadow: var(--elevation-card-shadow);
	padding: 0 0 4px;
}

.aqua-guide-card__tag {
	display: inline-block;
	margin: 18px 18px 0;
	font-size: 11px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--cta-signal-primary);
	background: var(--color-base-lagoon-light);
	padding: 4px 10px;
	border-radius: 12px;
}

.aqua-guide-card__title {
	font-size: 17px;
	margin: 12px 18px 8px;
	line-height: 1.3;
}

.aqua-guide-card__title a {
	color: var(--color-ink-text-primary);
	text-decoration: none;
}

.aqua-guide-card__excerpt {
	font-size: 13px;
	margin: 0 18px 12px;
	color: var(--color-base-clear-mid);
	line-height: 1.45;
}

.aqua-guide-card__read,
.aqua-home__guides-more a {
	font-size: 13px;
	font-weight: 700;
	color: var(--cta-signal-primary);
	text-decoration: none;
}

.aqua-home__guides-more {
	margin-top: 18px;
	font-size: 14px;
	font-weight: 600;
}

.aqua-tool-back-bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 12px 24px;
	background: var(--surfaces-lifted-opaque);
	border-bottom: 1px solid var(--elevation-hairline);
}

.aqua-tool-back-bar__home img {
	display: block;
	height: 44px;
	width: auto;
}

.aqua-tool-back-bar__shop {
	font-size: 14px;
	font-weight: 600;
	color: var(--cta-signal-primary);
	text-decoration: none;
}

.aqua-tool-app__content {
	min-height: 60vh;
}

@media (max-width: 900px) {
	.aqua-intent-grid {
		grid-template-columns: repeat(2, 1fr);
	}
	.aqua-guides-grid {
		grid-template-columns: 1fr;
	}
}

@media (max-width: 540px) {
	.aqua-intent-grid {
		grid-template-columns: 1fr;
	}
}

/* ==========================================================================
   6. Badge pills (lead-time / trust) — see template-parts/leadtime-badge-partial.php
   Colors below are consumed as var() only; the plugin decides copy/state,
   the theme decides presentation.
   ========================================================================== */
.aqua-badge {
	display: inline-flex;
	align-items: center;
	gap: 0.4em;
	border-radius: var(--radii-badge-pill);
	padding: 0.3em 0.85em;
}

.aqua-badge__dot {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	flex: none;
}

.aqua-badge--in-region {
	background: var(--badge-in-region-lagoon-bg);
	color: var(--badge-in-region-lagoon-text);
}
.aqua-badge--in-region .aqua-badge__dot {
	background: var(--badge-in-region-lagoon-dot);
}

.aqua-badge--sourced {
	background: var(--badge-sourced-to-order-lagoon-bg);
	color: var(--badge-sourced-to-order-lagoon-text);
}
.aqua-badge--sourced .aqua-badge__dot {
	background: var(--badge-sourced-to-order-lagoon-dot);
}

.aqua-badge--import {
	background: var(--badge-import-sourced-to-order-lagoon-bg);
	color: var(--badge-import-sourced-to-order-lagoon-text);
	border: 1px solid var(--badge-import-sourced-to-order-lagoon-border);
}
.aqua-badge--import .aqua-badge__dot {
	background: var(--badge-import-sourced-to-order-lagoon-dot);
}

/* ==========================================================================
   7. Category-key theming
   Body classes added by aqua_studio_body_class_category_key() in
   functions.php. Each node gets a distinct accent used for header rules,
   nav-chip active state, and category-page hero tint. Green
   (--color-semantic-success-eco) must NEVER appear as a category accent —
   it is reserved solely for success/eco semantic states.

   v2.5.0 P0 FIX (F01, Ali): TWO separate defects, both invisible to a
   code-only read because tokens.json's hex values were also collapsed
   (see build/tokens.json header history) — only a real render surfaced it.
   (1) VALUE bug: 4 of 6 category-key tokens + --cta-signal-primary had all
   collapsed to the same #673272 in build/tokens.json — tokens.css inherited
   the collapse. Fixed at the source (tokens.json), all 6 category hues +
   CTA are now independently distinct AA-safe hexes; vestigial
   coral-reef/planted "_blue/_orange/_darkblue/_red/_magenta" names (leftover
   from an earlier, since-superseded blue "Reef"/"Lagoon" palette register —
   see this file's v2.3.0 changelog note) are renamed to true semantic names
   (accent/pip/tag); the unused, never-referenced coral_reef_darkblue token
   is dropped.
   (2) WIRING bug, independent of (1) and NOT mentioned in the original
   defect report — would have silently survived a naive value-only fix:
   automation's selector below pointed at --color-category-keys-marine
   instead of its own --color-category-keys-automation token (so automation
   pages would have kept rendering marine's color even after (1) was fixed);
   freshwater's selector pointed at --color-category-keys-main-brand instead
   of --color-category-keys-freshwater (so freshwater pages would have kept
   rendering plain brand-purple, not green, even after (1) was fixed). Both
   now point at their own correctly-named, correctly-valued tokens.
   `.cat-key-accessories` is dead code (no live product_cat slug maps to
   'accessories' in aqua_studio_category_key_map()) — left as a harmless
   explicit fallback to --color-category-keys-main-brand rather than
   deleted, in case a future taxonomy term needs a neutral default.
   ========================================================================== */
/* v2.9.1 — D4 P1 (audit row 1.4). The `.cat-key-*` rules below supply only
   a `background-color`. `.aqua-category-accent` had NO base rule anywhere —
   no display, no width, no height — and the markup that carries it
   (front-page.php's homepage tiles, archive-product.php's category header)
   is an EMPTY `<span>`. An empty inline element with a background and no
   box is zero-by-zero: it paints nothing. So the six distinct category
   hues introduced by the v2.5.0 P0 palette fix have never actually been
   visible on those two surfaces — the token fix was real, the wiring was
   real, and the result was still invisible for want of a box.
   `.aqua-archive__accent-bar` likewise had no rule at all (grep: zero
   hits), so the archive header's bar was equally absent. Both get a real
   box here. This is a plain rule, not artwork — a coloured bar carrying no
   representational form (compare the CSS-drawn magnifying glass removed in
   §"utilities" above, which depicted an object).
   The `:not(.aqua-badge__dot)` guard matters: single-product.php:130 puts
   BOTH classes on one span, and `.aqua-badge__dot` (§6, 7x7 round) is the
   one call site where this component was already sized correctly and has
   always rendered. Without the guard this rule sits later in the file at
   equal specificity and would silently restyle that working PDP dot into a
   38x4 bar — fixing two invisible accents by breaking the one visible one. */
.aqua-category-accent:not(.aqua-badge__dot) {
	display: block;
	width: 38px;
	height: 4px;
	border-radius: 2px;
	background-color: var(--color-category-keys-main-brand);
}

/* The archive header's variant is the same primitive, sized for a page
   header rather than a card. */
.aqua-archive__accent-bar:not(.aqua-badge__dot) {
	width: 56px;
	height: 4px;
	margin: 0 0 10px;
}

/* Pips are small round dots (badge/legend use), not bars. */
.aqua-category-accent--pip:not(.aqua-badge__dot) {
	width: 7px;
	height: 7px;
	border-radius: 50%;
}

.cat-key-marine .aqua-category-accent {
	background-color: var(--color-category-keys-marine);
}
.cat-key-automation .aqua-category-accent {
	background-color: var(--color-category-keys-automation);
}

.cat-key-coral-reef .aqua-category-accent {
	background-color: var(--color-category-keys-coral-accent);
}
.cat-key-coral-reef .aqua-category-accent--pip {
	background-color: var(--color-category-keys-coral-pip);
}
.cat-key-coral-reef .aqua-category-accent--tag {
	background-color: var(--color-category-keys-coral-tag);
}

.cat-key-planted .aqua-category-accent {
	background-color: var(--color-category-keys-planted-accent);
}
.cat-key-planted .aqua-category-accent--pip {
	background-color: var(--color-category-keys-planted-pip);
}

.cat-key-freshwater .aqua-category-accent {
	background-color: var(--color-category-keys-freshwater);
}

/* Dead-code fallback only — see v2.5.0 note above; no live term maps here. */
.cat-key-accessories .aqua-category-accent {
	background-color: var(--color-category-keys-main-brand);
}

/* v1.1.0: livestock gets its own cat-key (not folded into coral-reef) —
   token already existed (--color-category-keys-livestock, #EFD8AC) but had
   (v2.9.1, audit row 1.6 — the comment said #F1663B rust-orange; the live
   token has always been sand #EFD8AC. Stale COMMENT only, never a live
   rust value, but a comment naming an off-palette hex is how off-palette
   hexes get reintroduced, so it is corrected rather than left.)
   no .cat-key-livestock rule wired up; this closes that gap. */
.cat-key-livestock .aqua-category-accent {
	background-color: var(--color-category-keys-livestock);
}

/* Livestock-only pip (never a button fill, never the CTA color). */
.aqua-livestock-pip {
	background-color: var(--cta-pip-livestock);
}

/* Success/eco semantic state — the ONLY place --color-semantic-success-eco may appear. */
.aqua-state-success {
	color: var(--color-semantic-success-eco);
}

/* ==========================================================================
   8. Reef (dark) register surfaces
   ========================================================================== */
.aqua-surface-reef {
	background-color: var(--surfaces-reef-darkest-gutter);
	color: var(--color-ink-text-inverse);
}

.aqua-surface-reef a {
	color: var(--color-ink-text-inverse);
}

/* v2.4.0 — P0 CONTRAST FIX: §3's global `h1, h2, h3 { color:
   var(--color-ink-text-primary) }` rule directly targets any heading
   element, which beats inheritance from an ancestor's `color` no matter
   that ancestor's specificity — so every `<h3 class="aqua-widget-title">`
   inside this dark surface (footer.php's "Contact" / "Policies" / "Payment
   Methods" headings, template-parts/trust-register.php) was rendering in
   --color-ink-text-primary (#3A2A40) on a --surfaces-reef-darkest-gutter
   background that is the EXACT SAME HEX (#3A2A40) — i.e. fully invisible
   text, sitewide, in the footer, on every single page. This is almost
   certainly the root cause of the client's "black-on-purple text" report:
   a code-only/text-fetch review cannot detect an invisible-contrast bug
   (the text is present in the DOM, just unreadable), which is why this
   was not already on the panel's defects register. Fixes it at the
   surface level so ANY current or future heading dropped into a dark
   surface is safe by default, not just today's known instances. */
.aqua-surface-reef h1,
.aqua-surface-reef h2,
.aqua-surface-reef h3,
.aqua-surface-reef .aqua-display {
	color: var(--color-ink-text-inverse);
}

/* v2.4.2 — CONFIRMED-LIVE P0 CONTRAST FIX: `.aqua-surface-reef a` above
   (specificity 0,1,1) does not reliably win on the live page. Storefront
   core's own `.site-footer a{color:#2c2d33;text-decoration:underline}`
   ties it on specificity, and the Customizer-generated inline rule
   `.site-footer a:not(.button):not(.components-button){color:#333}`
   (0,3,1 — each :not(.class) counts as a class) beats it outright, on
   every page, regardless of load order. See this file's header comment
   for the full root-cause writeup. `#colophon` is footer.php's own real,
   unique wrapper ID (`<footer id="colophon" class="site-footer
   aqua-surface-reef">`) — confirmed live (2026-07-11) that no Storefront/
   WooCommerce/Customizer CSS anywhere targets `#colophon`, so an ID-anchored
   rule permanently outranks any class/:not() combination without
   `!important`, including any future Customizer color-scheme change. */
#colophon a {
	color: var(--color-ink-text-inverse);
	text-decoration: underline;
}

#colophon a:hover,
#colophon a:focus-visible {
	color: var(--surfaces-lifted-opaque);
}

/* CTA-style footer links (currently only the "Chat on WhatsApp" pill,
   template-parts/trust-register.php) are buttons, not inline text — they
   must stay solid-filled with no underline, never inherit the plain-link
   treatment above. Listed by class, not by excluding `.aqua-cta` from the
   `#colophon a` rule, so any future footer CTA stays correct automatically
   as long as it also carries `.aqua-cta` and/or `.aqua-header-whatsapp`. */
#colophon .aqua-cta,
#colophon .aqua-header-whatsapp {
	color: var(--color-ink-text-inverse);
	text-decoration: none;
}

#colophon .aqua-cta:hover,
#colophon .aqua-cta:focus-visible,
#colophon .aqua-header-whatsapp:hover,
#colophon .aqua-header-whatsapp:focus-visible {
	color: var(--color-ink-text-inverse);
	text-decoration: none;
}

/* ==========================================================================
   9. v2.0.0 brand re-skin additions — site-branding logo, footer branding,
   reef corner accents. New in this version; sections 1-8 above are
   token-driven and needed no edits for the re-skin itself.
   ========================================================================== */
.aqua-site-branding__link {
	display: inline-flex;
	align-items: center;
}

/* v2.9.0 (Ali) — D8, second half: "the logo still reads small against the
   nav". Raised clamp(72px,8.5vw,116px) -> clamp(88px,9.5vw,132px), with
   --spacing-nav-height raised 124px -> 148px in the SAME pass so the band
   keeps proportional headroom around the mark (the v2.5.0 note below
   records what happens when only one of the two moves).
   ASSET INTEGRITY: height-only sizing + `width: auto` is retained and
   `aspect-ratio: 1/1` is stated explicitly — the SVG's true intrinsic
   ratio (1024x1024 viewBox). The file itself is untouched, and no width is
   ever forced (a hardcoded width="220" is what distorted this mark once
   before — see header.php v2.7.1). Enlarging is purely a rendered-size
   change.
   Previously v2.5.0 (Ali, owner: "logo tiny") — was clamp(56px,7vw,92px)
   inside a 92px row, already maxed with zero headroom. */
.aqua-site-branding__logo {
	/* v2.9.2 (Ali) — C5. Raised from clamp(88px,9.5vw,132px) while the band
	   around it was tightened (see .aqua-nav above), so the mark gains size
	   in absolute terms AND in proportion to the header.

	   MEASURED, not asserted — the ink bounding box of the locked
	   assets/img/logo/aqua-studio-logo-primary.svg was computed from the
	   file's own path data: the artwork occupies y 378.1..638.8 of a
	   1024x1024 viewBox, i.e. 260.7px = 25.5% of the canvas height (and
	   54.3% of its width). Confirms the 25.4% figure recorded earlier.
	   ~74.5% of this file is transparent padding baked into the asset.

	   Consequence, stated plainly: at the 138px cap the visible wordmark is
	   only ~35px tall inside a 146px band. The band cannot be tightened
	   further without shrinking the mark with it, because the empty space
	   is INSIDE the logo file, not around it. A wordmark-cropped logo
	   variant would let this band drop to ~72px at the same optical size —
	   that is an owner decision on a locked brand asset, so it is flagged,
	   not taken here. The file is untouched; this is a rendered-size
	   change only, and no width is ever forced (a hardcoded width="220" is
	   what distorted this mark once before — see header.php v2.7.1). */
	height: clamp(92px, 9.8vw, 138px);
	width: auto;
	aspect-ratio: 1 / 1;
	position: relative;
	z-index: 1;
}

/* v2.9.4 (Ali) — TASK A. Applied ONLY when header.php resolved the
   tight-crop derivative (assets/img/logo/aqua-studio-logo-primary-tight.svg);
   the rule above stays the fallback for the uncropped master, which is
   still 1:1 and must not be stretched to this ratio.

   THE MEASUREMENT THE v2.9.2 NOTE ABOVE ASKED FOR, now acted on. Ink
   bounding box of the master, recomputed this pass from its own path
   geometry using true cubic-Bezier extrema (not control-point hulls):
       x 232.864607 .. 784.015592   -> 551.151px, 53.82% of canvas width
       y 378.108000 .. 633.126072   -> 255.018px, 24.90% of canvas height
   Cross-checked by rasterising the file and taking the non-white pixel
   bbox: x 231..785, y 377..634 — a 1-2px antialias margin around the exact
   geometry, which confirms it. This CORRECTS the y-max recorded in the
   v2.9.2 note above (638.8, and thus "25.5%"): that figure came from a
   control-point bound, which overestimates a Bezier. The true extremum is
   633.126 and the true height fraction is 24.90%.

   The derivative's viewBox IS that bounding box, so its rendered height IS
   its optical height — 1:1, no dead canvas. Resulting optical mark height:
       390px  22.9px -> 46px   (2.01x)
       768px  22.9px -> 46px   (2.01x)
       1440px 34.4px -> 69px   (2.01x)
   i.e. the owner-requested ~2x at every checked width, while the band
   around it drops 120/120/146px -> a flat 96px.

   aspect-ratio is stated explicitly as the crop's true intrinsic ratio
   (551.151 / 255.0181 = 2.161223) for the same reason the 1:1 above states
   it: height-only sizing plus `width: auto` must never be able to distort
   this mark. The SVG files themselves are untouched by this rule. */
.aqua-site-branding__logo--tight {
	height: clamp(46px, 4.8vw, 69px);
	width: auto;
	aspect-ratio: 551.151 / 255.0181;
}

.aqua-site-branding__link--text {
	font-family: var(--type-display-en), sans-serif;
	font-weight: 700;
	font-size: 22px;
	color: var(--cta-signal-primary);
}

.aqua-footer__inner {
	padding-top: 40px;
	padding-bottom: 32px;
	display: flex;
	flex-direction: column;
	gap: 28px;
}

.aqua-footer__brand {
	display: flex;
	align-items: center;
}

/* v2.7.0 (Ali) — owner: "logo on white background with strange dimensions."
   Root cause (confirmed via render): aqua-studio-logo-mono.svg bakes in its
   OWN opaque near-white full-canvas background rect — it is not a
   transparent "white ink" reversed mark, so it always paints a white plate
   behind itself on any surface (visually confirmed, not usable transparently
   anywhere). aqua-studio-logo-primary.svg (still one of the 3 agreed,
   unmodified logo files) has a genuinely transparent background and reads
   cleanly on this dark footer surface — footer.php now uses that file
   instead. Both files share the same 1024x1024 (1:1) intrinsic canvas, so a
   single height + width:auto keeps the true aspect ratio (footer.php's
   width/height attributes were also corrected to a matching 1:1 ratio —
   previously 160x52, which mismatched the SVG's real 1:1 shape). */
.aqua-footer__logo {
	height: 56px;
	width: auto;
	max-width: 200px;
}

.aqua-footer__logo--text {
	font-family: var(--type-display-en), sans-serif;
	font-weight: 700;
	font-size: 20px;
	color: var(--color-ink-text-inverse);
}

.aqua-footer__credit {
	font-size: 13px;
	opacity: 0.75;
}

/* v2.5.1 (Chen) — homepage hero emergency fix: optional Pexels courtesy
   credit line (footer.php, .aqua-footer__photo-credit). Same treatment
   family as .aqua-footer__credit just above, slightly smaller/quieter
   since it is a courtesy line, not a legally required one (Pexels License
   does not require attribution — rights-ledger.md row 35). */
.aqua-footer__photo-credit {
	font-size: 12px;
	opacity: 0.6;
	margin-top: -8px;
}

/* v2.4.0 — premium-finish pass: .aqua-trust-register (footer.php AND
   page-contact.php's checkout-variant embed) had ZERO layout CSS anywhere
   in this file — its 3-4 child blocks (NAP/Policies/Payment/Supplier-
   identity) were plain stacked full-width <div>s, reading as a raw
   unstyled list rather than a designed footer. Responsive column grid,
   consistent widget-title treatment (also reused by the archive Filters
   heading + checkout supplier-identity heading — same class, one rule). */
.aqua-widget-title {
	font-size: 13px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	margin: 0 0 14px;
}

.aqua-trust-register {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
	gap: 32px 28px;
	width: 100%;
	padding-top: 8px;
}

.aqua-trust-register__nap,
.aqua-trust-register__policies,
.aqua-trust-register__payments,
.aqua-trust-register__supplier-identity {
	min-width: 0;
}

.aqua-trust-register__supplier-identity {
	grid-column: 1 / -1;
}

.aqua-trust-register__name {
	font-weight: 600;
	margin: 0 0 4px;
}

.aqua-trust-register__address {
	margin: 0 0 12px;
	opacity: 0.85;
	font-size: 14px;
}

.aqua-trust-register__policies ul,
.aqua-trust-register__payment-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 9px;
	font-size: 14px;
}

.aqua-trust-register__policies a {
	opacity: 0.9;
}

.aqua-trust-register__policies a:hover,
.aqua-trust-register__policies a:focus-visible {
	opacity: 1;
}

.aqua-trust-register__payment-list li {
	opacity: 0.85;
}

.aqua-trust-register--checkout {
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card);
	box-shadow: var(--elevation-card-shadow);
	padding: 24px 26px;
}

.aqua-trust-register__legal-fields {
	grid-column: 1 / -1;
	margin: 4px 0 0;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: 10px 24px;
}

.aqua-trust-register__legal-fields dt {
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	color: var(--cta-signal-primary);
	margin: 0;
}

.aqua-trust-register__legal-fields dd {
	margin: 2px 0 0;
	font-size: 14px;
}

/* Subtle brand ribbon along the top edge of every dark reef surface —
   cheap, tasteful "premium finish" signature instead of a hard flat
   color-block edge. Gradient reuses only locked brand tokens. */
.aqua-surface-reef {
	position: relative;
}

.aqua-surface-reef::before {
	content: "";
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 3px;
	background: linear-gradient(
		90deg,
		var(--color-semantic-success-eco) 0%,
		var(--color-base-lagoon-light) 50%,
		var(--color-base-clear-mid) 100%
	);
}

/* ==========================================================================
   10. v2.0.0 — category archive layout (facet rail now visible, see
   templates/woocommerce/archive-product.php v2.0.0 comment). No grid CSS
   existed for this in v1.1.0 because the whole rail was HTML-commented out;
   this is new structural CSS, not a re-skin of an existing rule.
   ========================================================================== */
/* v2.9.0 (Ali) — D6 RESOLVED. The reported "stray tooltip stuck to the
   top-left of the shop page, overlapping content: a white panel reading
   'Sourced to order / Imported — see each product card for its exact lead
   time'" was never a tooltip: it was THIS 220px facet rail
   (`.aqua-archive__facets`, a white sticky card) and the sentence was its
   lead-time facet hint. The rail was removed from
   templates/woocommerce/archive-product.php this version — see that file
   for the full rationale; in short it rendered ZERO working controls (two
   deliberately inert headings and one hint paragraph, no inputs at all),
   so it cost a fifth of the archive width, duplicated D3's per-card
   lead-time signal, and read as a stray floating panel. The layout is now
   a single full-width column, which also lets the product grid run four
   across instead of three. The `.aqua-archive__facets` / `.aqua-facet`
   rules below are intentionally KEPT (dead but harmless) so a future wave
   can reinstate a real, wired filter rail without rebuilding its styling
   from scratch. */
.aqua-archive__layout {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--spacing-card-gap);
	align-items: start;
}

.aqua-archive__facets {
	background: var(--surfaces-lifted-opaque);
	border-radius: var(--radii-card);
	padding: 20px;
	box-shadow: var(--elevation-card-shadow);
	position: sticky;
	top: 24px;
}

.aqua-facet {
	padding: 14px 0;
	border-bottom: 1px solid var(--elevation-hairline);
}

.aqua-facet:last-child {
	border-bottom: none;
}

.aqua-facet h3 {
	margin: 0;
	font-family: var(--type-text-en), sans-serif;
	font-weight: 600;
	font-size: 15px;
	color: var(--color-ink-text-primary);
}

/* Visually-present-but-inert facets (Brand/Price in v2.0.0) — dimmed +
   non-interactive, so the rail is honest about what actually filters. */
.aqua-facet--inert {
	opacity: 0.55;
}

.aqua-facet__hint {
	margin: 6px 0 0;
	font-size: 13px;
	color: var(--color-ink-text-primary);
	opacity: 0.85;
}

.aqua-facet__hint--inert {
	font-style: italic;
}

.aqua-archive__products {
	min-width: 0;
}

/* Product-card grid — rounded image top, name/price/badge body, per
   mockups/category.png. .aqua-card / .aqua-card__img / .aqua-card__body
   already token-driven from section 4; this adds the woocommerce ul.products
   grid wrapper + brand-slot styling the archive template needs. */
ul.products {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
	gap: var(--spacing-card-gap);
	list-style: none;
	margin: 0;
	padding: 0;
}

/* v2.9.2 (Ali) — C7, the "phantom empty cell" on /shop/. ROOT CAUSE found
   in the LIVE cascade, not guessed: Storefront ships a float clearfix,
   `ul.products::before, ul.products::after { content: ""; display: table }`.
   That is harmless on a float layout, but the rule above makes this same
   element `display: grid` — and per CSS Grid, every pseudo-element child of
   a grid container is BLOCKIFIED into a real grid ITEM. `::before` was
   therefore silently occupying grid slot 1: row 1 rendered only 4 cards
   starting at x=393px while every later row rendered 5 flush at x=144px
   (measured live at a 1512px viewport, 5 tracks of 227.2px — a 249px
   phantom indent, exactly the owner's report). `::after` consumed a
   trailing slot the same way. This is NOT a leftover facets-rail element;
   nothing in our own markup was ever there. `content: none` stops the
   pseudo-elements being generated at all, so no slot is consumed. Declared
   at the same specificity but later in the cascade (child theme loads after
   the parent), with display:none as belt-and-braces. */
ul.products::before,
ul.products::after,
.woocommerce ul.products::before,
.woocommerce ul.products::after {
	content: none;
	display: none;
}

ul.products li.aqua-card {
	list-style: none;
}

.aqua-card__link {
	display: block;
	color: inherit;
}

.aqua-card__link:hover,
.aqua-card__link:focus {
	text-decoration: none;
}

.aqua-card__brand--text {
	display: block;
	font-size: 13px;
	color: var(--color-ink-text-primary);
	opacity: 0.7;
	margin-bottom: 4px;
}

.aqua-card__brand--logo-slot {
	display: block;
	min-height: 18px;
	margin-bottom: 4px;
}

/* ==========================================================================
   11. v2.0.0 — PDP layout (rounded gallery frame, two-column summary,
   sand-pill DOA note). No structural PHP change (see single-product.php +
   doa-strip.php v2.0.0 header comments) — this is the missing layout CSS
   the re-skin needed, none of it existed before.
   ========================================================================== */
.aqua-pdp__layout {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: 40px;
	align-items: start;
}

@media (max-width: 782px) {
	.aqua-pdp__layout {
		grid-template-columns: 1fr;
	}
}

.aqua-pdp__gallery {
	border-radius: var(--radii-card);
	overflow: hidden;
	background: var(--surfaces-lifted-tint);
}

.aqua-pdp__gallery img {
	border-radius: var(--radii-card);
}

.aqua-pdp__gallery-placeholder {
	aspect-ratio: 1 / 1;
	display: flex;
	align-items: center;
	justify-content: center;
	background: var(--surfaces-lifted-tint);
	border-radius: var(--radii-card);
	padding: 24px;
	text-align: center;
}

.aqua-pdp__summary {
	display: flex;
	flex-direction: column;
	gap: 14px;
}

.aqua-pdp__pip {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	font-size: 13px;
	font-weight: 600;
	/* v2.5.0 fix (render QA caught it): this hardcoded --cta-signal-primary,
	   invisibly "correct" only because that token and the category-accent
	   tokens all used to be the same collapsed #673272 (see F01). Now that
	   CTA is its own distinct color, a CTA-colored label next to a
	   category-colored dot (.aqua-badge__dot.aqua-category-accent, sibling
	   span, unchanged) read as a mismatch. Label goes neutral ink; the dot
	   alone carries the category-color signal -- standard
	   indicator-dot-plus-neutral-label pattern, no per-category label-color
	   logic needed. */
	color: var(--color-ink-text-primary);
}

/* v2.3.3 — Brand/attribute meta line (live-panel Specifications-dedup fix,
   see templates/woocommerce/single-product.php). Muted like
   .aqua-footer__credit (opacity, no new color token) — a factual aside,
   not a heading-level element, so it never competes with the real
   "Specifications" heading in the rich table.aq-spec below (§12). */
.aqua-pdp__meta-line {
	margin: 0;
	font-size: 13px;
	font-weight: 500;
	color: var(--color-ink-text-primary);
	opacity: 0.7;
}

.aqua-pdp__leadtime {
	margin: 4px 0;
}

.aqua-pdp__add-to-cart {
	margin: 6px 0;
}

/* DOA sand-pill note (v2.0.0 — replaces the v1.1.0 dark .aqua-surface-reef
   treatment; see template-parts/doa-strip.php v2.0.0 header comment). */
.aqua-doa-strip {
	background: var(--color-base-lagoon-light); /* sand token */
	border: 1px solid rgba(103,50,114,.2);
	border-radius: var(--radii-badge-pill);
	padding: 0.85em 1.4em;
	color: var(--color-ink-text-primary);
	font-size: 14px;
}

.aqua-doa-strip a {
	color: var(--cta-signal-primary);
	font-weight: 600;
}

/* v2.3.3 — live-panel Specifications-dedup fix: templates/woocommerce/
   single-product.php no longer renders a <section class="aqua-pdp__spec-table">
   (that was the duplicate WooCommerce-attributes-only "Specifications" box —
   see .aqua-pdp__meta-line above, §9). Rules below (.aqua-pdp__spec-table,
   .aqua-spec-table) are now unused by any live template; left in place
   (harmless, zero render cost) rather than risk collateral CSS breakage on
   a live-site polish pass — candidate for removal in a future cleanup pass. */
.aqua-pdp__spec-table {
	margin-top: 32px;
}

.aqua-spec-table {
	width: 100%;
	border-collapse: separate;
	border-spacing: 0;
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card-small);
	overflow: hidden;
}

.aqua-spec-table th,
.aqua-spec-table td {
	text-align: left;
	padding: 12px 16px;
	border-bottom: 1px solid var(--elevation-hairline);
	font-size: 15px;
}

.aqua-spec-table tbody tr:last-child th,
.aqua-spec-table tbody tr:last-child td {
	border-bottom: none;
}

.aqua-spec-table tbody tr:nth-child(even) {
	background: var(--surfaces-lifted-tint);
}

.aqua-spec-table th {
	font-weight: 600;
	color: var(--cta-signal-primary);
	width: 40%;
}

/* ==========================================================================
   12. v2.1.3 — PDP long-description content (imported copy + embedded spec
   table, see templates/woocommerce/single-product.php "DESCRIPTION"
   section). v2.2.0: English-only — the catalogue-import pipeline authors
   each product's long description as a single EN HTML fragment:
     <div class="aq-desc" lang="en">…<table class="aq-spec">…</table></div>
   (the Arabic sibling block + its RTL presentational rules below are
   removed; Arabic may return in a later phase per owner directive.)
   Distinct from .aqua-spec-table (§11 above, the attributes-only
   Specifications box) — table.aq-spec is the richer spec table authored
   INSIDE the description copy itself. Brand tokens only (Deep Purple
   --cta-signal-primary, off-white --surfaces-lifted-tint/--color-ink-text-inverse);
   --color-semantic-success-eco (Emerald) is deliberately NOT used here —
   §7 above already documents it as reserved solely for .aqua-state-success,
   and no other emerald-valued token has a semantic fit in a generic
   description block. No amber/yellow, per the refused-palette rule.
   ========================================================================== */
.aqua-pdp__description {
	margin-top: 32px;
}

.aq-desc {
	color: var(--color-ink-text-primary);
	font-size: var(--type-body-en-px);
	line-height: 1.65;
}

.aq-desc p {
	margin: 0 0 1em;
}

.aq-desc h4 {
	margin: 1.4em 0 0.6em;
	font-family: var(--type-text-en), sans-serif;
	font-size: 16px;
	font-weight: 700;
	color: var(--cta-signal-primary);
}

.aqua-pdp__description hr {
	border: none;
	border-top: 1px solid var(--elevation-hairline);
	margin: 28px 0;
}

table.aq-spec {
	width: 100%;
	border-collapse: collapse;
	margin: 0.6em 0 1.2em;
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card-small);
	overflow: hidden;
}

table.aq-spec th,
table.aq-spec td {
	text-align: left;
	padding: 10px 14px;
	font-size: 14px;
	border-bottom: 1px solid var(--elevation-hairline);
}

table.aq-spec tbody tr:last-child th,
table.aq-spec tbody tr:last-child td {
	border-bottom: none;
}

table.aq-spec thead th {
	background: var(--cta-signal-primary);
	color: var(--color-ink-text-inverse);
	font-weight: 600;
}

table.aq-spec tbody tr:nth-child(even) {
	background: var(--surfaces-lifted-tint);
}

/* ==========================================================================
   13. v2.3.0 — template-rebuild wave — pixel-match to web/mockups/pdp.png,
   category.png, home-hero.png + the layout richness of creative/comps-v3
   and comps-v4 (their blue "Lagoon Light"/"Reef" register is superseded —
   only structure/spacing is reused here, always in the locked purple/cream
   palette). Brand tokens only, no hardcoded hexes beyond what already
   exists as a token; --color-semantic-success-eco stays reserved for
   .aqua-state-success per §7/§12. v2.7.0: the placeholder atom below no
   longer uses a decorative gradient (owner's no-invented-graphics rule) —
   flat brand-tint fill only.
   ========================================================================== */

/* -- Designed placeholder atom — never WooCommerce's gray placeholder.png
   or a broken image box. v2.7.0 (Ali): the previous gradient-bloom
   background + rotated-square "petal" mark were exactly the kind of
   invented/drawn ornament the owner's absolute no-authored-graphics rule
   forbids — flattened to a single flat brand-tint fill, no shape drawn on
   top (the parent's role="img"/aria-label already communicates the "image
   pending" state to assistive tech). Used by the PDP gallery (no-image
   state), category/PDP cross-sell cards
   (aqua_studio_product_image_or_placeholder(), see functions.php), reused
   wherever a product has no rights-cleared photo yet. -- */
/* v2.9.0 (Ali) — D2: ~61 of 120 products still have no featured image, and
   this slot painted them as a large blank rectangle in exactly the page's
   own background colour (--surfaces-lifted-tint IS the paper), so half the
   shop grid read as broken/empty boxes. Replaced with a soft sand->paper
   wash on the two LOCKED palette colours (#EFD8AC sand -> #F9FDEC paper).
   NO-INVENTED-GRAPHICS COMPLIANCE: this is a two-stop colour gradient — a
   flat tint treatment, nothing representational. Zero shapes, icons,
   motifs or illustrations are drawn here; `.aqua-img-placeholder__mark`
   stays `display: none` (v2.7.0, unchanged) and the only glyph added is
   the product's own first initial as plain typography (see
   `.aqua-img-placeholder__initial` below and
   aqua_studio_product_image_or_placeholder() in functions.php). The
   aspect-ratio + fixed box means a card with no photo occupies EXACTLY the
   same slot as a card with one, so rows stay level. */
.aqua-img-placeholder {
	position: relative;
	width: 100%;
	aspect-ratio: 1 / 1;
	border-radius: var(--radii-card) var(--radii-card) 0 0;
	overflow: hidden;
	display: flex;
	align-items: center;
	justify-content: center;
	background: linear-gradient(155deg, var(--color-base-lagoon-light) 0%, var(--surfaces-lifted-tint) 72%);
	/* v2.7.0 §9 render QA fix: --surfaces-lifted-tint IS the page's own
	   "paper" background colour, so a flat fill alone was reading as an
	   invisible/blank box wherever this placeholder sits directly on the
	   page body (PDP main gallery) rather than inside a white .aqua-card —
	   exactly the "broken/blank box" this component exists to avoid. A
	   hairline border (existing token, already used the same way on
	   .aqua-nav/.aqua-soon__notify elsewhere in this file) keeps the slot
	   legible as a defined box in every context without drawing anything. */
	border: 1px solid var(--elevation-hairline);
}

.aqua-img-placeholder__mark {
	display: none;
}

/* v2.9.0 — the product's own first initial, set in the display face at low
   opacity. This is TYPOGRAPHY (a character from the product's real name),
   not an authored graphic/icon/monogram-mark — it gives the empty slot a
   quiet focal point and makes adjacent placeholder cards distinguishable
   from one another instead of reading as one repeated blank panel.
   aria-hidden on the element (functions.php) — the wrapper's own
   role="img" + aria-label already carries the accessible name. */
.aqua-img-placeholder__initial {
	/* v2.9.1 — D1 P0 (audit row 1.1): serif fallback corrected to sans. */
	font-family: var(--type-display-en), 'Trebuchet MS', system-ui, sans-serif;
	font-size: clamp(38px, 5vw, 64px);
	font-weight: 700;
	line-height: 1;
	color: var(--color-base-luminous-deep);
	opacity: 0.16;
	user-select: none;
	pointer-events: none;
}

/* v2.9.0 — same D2 treatment for the photo-wrapper's empty state (the
   category-tile / Worlds-card slot with no sourced photo yet, e.g.
   Automation). Was a solid deep-purple block, which read as a deliberate
   dark tile rather than a pending photo; now matches the product-card
   placeholder exactly, so every empty image slot sitewide is one
   consistent, on-brand treatment. */
.aqua-photo__media--empty {
	background: linear-gradient(155deg, var(--color-base-lagoon-light) 0%, var(--surfaces-lifted-tint) 72%);
}

/* PDP main frame — full card radius on all corners (no card body below it). */
.aqua-img-placeholder--pdp {
	border-radius: var(--radii-card);
}

.aqua-img-placeholder--thumb {
	aspect-ratio: 1 / 1;
	border-radius: var(--radii-card-small);
}

.aqua-img-placeholder--thumb .aqua-img-placeholder__mark {
	width: 40%;
	height: 40%;
}

/* -- PDP gallery — framed main image + 4-up thumbnail row -- */
.aqua-pdp__gallery-main {
	border-radius: var(--radii-card);
	overflow: hidden;
}

.aqua-pdp__gallery-thumbs {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 10px;
	margin-top: 10px;
}

.aqua-pdp__gallery-note {
	margin: 10px 0 0;
	font-size: 13px;
	color: var(--color-ink-text-primary);
	opacity: .7;
}

/* -- PDP price, bigger per mockups/pdp.png -- */
.aqua-price--pdp {
	font-size: calc(var(--type-price-px) * 1.55);
}

/* -- "Sourced to order" MODULE — styled card wrapping the real plugin
   badge (theme owns zero lead-time business logic; see
   templates/woocommerce/single-product.php header comment) plus a static,
   honest, generic explanation. -- */
.aqua-pdp__leadtime-module {
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card);
	box-shadow: var(--elevation-card-shadow);
	padding: 18px 20px;
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.aqua-pdp__leadtime-badge-slot .aqua-leadtime-badge {
	font-size: 15px;
	padding: 8px 14px;
	font-weight: 600;
	gap: 10px;
}

.aqua-pdp__leadtime-badge-slot .aqua-leadtime-badge__doa-link {
	margin-inline-start: 4px;
	padding-inline-start: 10px;
	border-left: 1px solid currentColor;
	opacity: .85;
	font-weight: 500;
}

.aqua-pdp__leadtime-explain {
	margin: 0;
	font-size: 14px;
	line-height: 1.5;
	color: var(--color-ink-text-primary);
}

.aqua-pdp__leadtime-caption {
	margin: 0;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px 14px;
	font-size: 12.5px;
	padding-top: 8px;
	border-top: 1px solid var(--elevation-hairline);
}

.aqua-pdp__leadtime-caption a {
	font-weight: 600;
	color: var(--cta-signal-primary);
}

.aqua-pdp__leadtime-honest {
	text-transform: uppercase;
	letter-spacing: .04em;
	font-weight: 700;
	color: var(--color-base-clear-mid);
	opacity: .85;
	font-size: 11px;
}

/* -- Availability — 3-card row -- */
.aqua-pdp__availability {
	margin-top: 32px;
}

.aqua-availability-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--spacing-card-gap);
}

.aqua-availability-card {
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card-small);
	padding: 18px;
	box-shadow: var(--elevation-card-shadow);
}

.aqua-availability-card--accent {
	border-color: var(--cta-signal-primary);
	background: var(--surfaces-lifted-tint);
}

.aqua-availability-card h3 {
	margin: 0 0 8px;
	font-size: 13px;
	text-transform: uppercase;
	letter-spacing: .03em;
	font-family: var(--type-text-en), sans-serif;
	font-weight: 700;
	color: var(--cta-signal-primary);
	/* v2.9.1 — D9 P0 (audit row 2.5). The `::before` that stood here painted
	   a data-URI SVG CHECK-MARK-IN-A-CIRCLE as a CSS mask — a drawn glyph,
	   authored in this file, rendering three times on every PDP
	   (single-product.php availability cards). Deleted: it is exactly the
	   kind of authored artwork the standing rule forbids, and the heading
	   text beside it already carried the entire message, so removing it
	   costs no meaning. `display:flex` is kept (the headings still align
	   their own content); the 8px gap is dropped with the glyph it spaced. */
	display: flex;
	align-items: center;
}

/* v2.4.0 — hover-lift consistency pass: .aqua-card/.aqua-intent-card
   already had a hover lift (motion.css §2.1); these 4 card types did not,
   reading inert/flat next to everything else on the page. Same
   transform+shadow language, reused verbatim. */
.aqua-guide-card,
.aqua-contact-card,
.aqua-availability-card,
.aqua-policy-card {
	transition: transform .2s ease, box-shadow .2s ease;
}

.aqua-guide-card:hover,
.aqua-guide-card:focus-within,
.aqua-contact-card:hover,
.aqua-contact-card:focus-within,
.aqua-availability-card:hover,
.aqua-availability-card:focus-within,
.aqua-policy-card:hover,
.aqua-policy-card:focus-visible {
	transform: translateY(-3px);
	box-shadow: 0 14px 30px rgba(103, 50, 114, .14);
}

.aqua-availability-card p {
	margin: 0;
	font-size: 14px;
	line-height: 1.5;
	color: var(--color-ink-text-primary);
}

/* -- About this product — reuses .aq-desc typography (§12) via the same
   markup shape; section-level spacing only. -- */
.aqua-pdp__description {
	margin-top: 32px;
}

/* -- Pairs well with — 4-card cross-sell row, reuses .aqua-card-grid/
   .aqua-card (§4) at a fixed 4-across count on desktop. -- */
.aqua-pdp__pairs {
	margin-top: 40px;
}

.aqua-card-grid.aqua-pairs-grid {
	grid-template-columns: repeat(4, 1fr);
}

.aqua-pairs-card__cta {
	padding: 0 20px 20px;
}

.aqua-pairs-card .aqua-card__body {
	padding-bottom: 10px;
}

@media (max-width: 900px) {
	.aqua-card-grid.aqua-pairs-grid {
		grid-template-columns: repeat(2, 1fr);
	}
}

@media (max-width: 540px) {
	.aqua-card-grid.aqua-pairs-grid {
		grid-template-columns: 1fr;
	}
	.aqua-availability-grid {
		grid-template-columns: 1fr;
	}
	.aqua-pdp__gallery-thumbs {
		grid-template-columns: repeat(4, 1fr);
	}
}

@media (max-width: 782px) {
	.aqua-availability-grid {
		grid-template-columns: 1fr;
	}
}

/* -- Category archive — corner accents, subtitle, facet dots, richer card
   imagery (mockups/category.png). -- */
.aqua-archive {
	position: relative;
}

.aqua-archive__layout {
	position: relative;
	z-index: 1;
}

.aqua-archive__header {
	position: relative;
	z-index: 1;
}

/* v2.7.0 (Ali) — owner-reported category-page defect: thumb was a framed
   CIRCULAR avatar with the (now-removed) .aqua-reef-corner texture behind/
   beneath it — "a circle with a photo inside, a strange texture behind it,
   and another texture at the bottom." Fixed: plain rectangle, tasteful
   radius, no corner ornament anywhere on this template. Header degrades to
   text-only (no layout shift/empty box) when no thumbnail exists yet —
   .aqua-archive__header--has-thumb is the only flex-row trigger. */
.aqua-archive__header--has-thumb {
	display: flex;
	align-items: center;
	gap: 26px;
	flex-wrap: wrap;
}

.aqua-archive__header-text {
	flex: 1 1 320px;
	min-width: 0;
}

.aqua-archive__thumb {
	flex: none;
	width: 132px;
	height: 132px;
	border-radius: var(--radii-card-small);
	overflow: hidden;
	box-shadow: var(--elevation-card-shadow);
	border: 3px solid var(--surfaces-lifted-opaque);
}

.aqua-archive__thumb-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	margin: 0;
}

@media (max-width: 540px) {
	.aqua-archive__header--has-thumb {
		flex-direction: column;
		align-items: flex-start;
	}
}

.aqua-archive__subtitle {
	margin-top: 6px;
	max-width: 60ch;
	font-size: var(--type-body-en-px);
	color: var(--color-ink-text-primary);
	opacity: .8;
}

.aqua-archive__subtitle p {
	margin: 0;
}

.aqua-facet__dot {
	display: inline-block;
	width: 8px;
	height: 8px;
	border-radius: 50%;
	margin-inline-end: 8px;
	vertical-align: middle;
}

.aqua-facet__dot--brand {
	background: var(--color-base-clear-mid);
}

.aqua-facet__dot--price {
	background: var(--color-base-lagoon-light);
	border: 1px solid var(--cta-signal-primary);
}

.aqua-facet__dot--leadtime {
	background: var(--color-semantic-success-eco);
}

/* -- Home — section rhythm polish (mockups/home-hero.png's premium
   spacing). Every top-level home section is a direct <section> child of
   <main class="aqua-home"> (hero, home-intent-cards.php, featured-guides.php,
   the category grid, trust, FAQ) — one rule reaches all of them without
   editing every partial. -- */
.aqua-home > section {
	margin-top: 72px;
}

.aqua-home > section:first-child {
	margin-top: 0;
}

.aqua-home .aqua-section-title {
	margin-bottom: 10px;
}

/* ==========================================================================
   14. v2.3.0 — cart + checkout visual elevation (as3-checkout.png layout,
   in the locked purple palette). No PHP logic touched — cart.php and
   form-checkout.php were already 100% token-driven (README v2.0.0 note);
   this styles the theme's own wrapper classes plus WooCommerce's own
   stable, long-documented core classnames (table.shop_table, #order_review,
   ul.wc_payment_methods, .woocommerce-shipping-methods, .place-order) —
   the same low-risk "style the real markup, don't reinvent it" approach
   already used for the loop add-to-cart button.
   ========================================================================== */
.aqua-cart__table,
.shop_table {
	background: var(--surfaces-lifted-opaque);
	border-radius: var(--radii-card-small);
	overflow: hidden;
	box-shadow: var(--elevation-card-shadow);
	border-collapse: separate;
	border-spacing: 0;
	width: 100%;
}

.aqua-cart__table th,
.shop_table th {
	text-align: left;
	padding: 14px 16px;
	background: var(--surfaces-lifted-tint);
	font-size: 13px;
	text-transform: uppercase;
	letter-spacing: .03em;
	color: var(--cta-signal-primary);
}

.aqua-cart__table td,
.shop_table td {
	padding: 14px 16px;
	border-top: 1px solid var(--elevation-hairline);
	vertical-align: middle;
}

.aqua-cart__table img,
.shop_table img {
	border-radius: var(--radii-card-small);
	width: 64px;
	height: 64px;
	object-fit: cover;
}

.aqua-cart__collaterals {
	margin-top: 28px;
	display: flex;
	justify-content: flex-end;
}

.aqua-cart__collaterals .cart_totals {
	background: var(--surfaces-lifted-opaque);
	border-radius: var(--radii-card);
	box-shadow: var(--elevation-card-shadow);
	padding: 22px 24px;
	min-width: 320px;
}

/* -- Checkout — 2-col layout, order-review as a sticky card, shipping/
   payment options as bordered rows (mirrors as3-checkout.png's radio
   cards without assuming markup this theme doesn't control). -- */
.aqua-checkout__customer-details {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 32px;
	align-items: start;
}

@media (max-width: 900px) {
	.aqua-checkout__customer-details {
		grid-template-columns: 1fr;
	}
}

.aqua-checkout__shipping-tier {
	margin-top: 20px;
	padding: 18px 20px;
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card-small);
}

.aqua-checkout__shipping-tier select,
#aqua_governorate {
	width: 100%;
	padding: 10px 12px;
	border: 1px solid var(--elevation-hairline);
	border-radius: 8px;
	background: var(--surfaces-lifted-opaque);
	font-size: 15px;
	margin-top: 6px;
}

#order_review,
.woocommerce-checkout-review-order {
	background: var(--surfaces-lifted-opaque);
	border-radius: var(--radii-card);
	box-shadow: var(--elevation-card-shadow);
	padding: 22px 24px;
}

.woocommerce-checkout-review-order-table {
	width: 100%;
	border-collapse: collapse;
}

.woocommerce-checkout-review-order-table th,
.woocommerce-checkout-review-order-table td {
	padding: 10px 0;
	border-bottom: 1px solid var(--elevation-hairline);
	text-align: left;
}

.woocommerce-checkout-review-order-table .order-total th,
.woocommerce-checkout-review-order-table .order-total td {
	font-size: 18px;
	font-weight: 700;
	color: var(--cta-signal-primary);
	border-bottom: none;
}

/* Shipping-method + payment-method radio rows — WooCommerce's own stable
   core markup (ul.wc_payment_methods / #shipping_method), styled as
   bordered selectable cards rather than left as bare browser radios. */
.woocommerce-shipping-methods,
ul.wc_payment_methods {
	list-style: none;
	margin: 10px 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.woocommerce-shipping-methods li,
ul.wc_payment_methods li.wc_payment_method {
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card-small);
	padding: 12px 16px;
	background: var(--surfaces-lifted-opaque);
}

.woocommerce-shipping-methods li label,
ul.wc_payment_methods li.wc_payment_method > label {
	font-weight: 600;
	display: flex;
	align-items: center;
	gap: 10px;
}

.payment_box {
	margin-top: 10px;
	padding: 12px 14px;
	background: var(--surfaces-lifted-tint);
	border-radius: 8px;
	font-size: 14px;
}

.aqua-checkout__leadtime-echo {
	margin-top: 18px;
	padding-top: 14px;
	border-top: 1px solid var(--elevation-hairline);
}

.aqua-checkout__leadtime-list {
	list-style: none;
	margin: 8px 0 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 8px;
}

.aqua-checkout__leadtime-line {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	flex-wrap: wrap;
	font-size: 14px;
}

/* v2.7.4 — deposit notice (owner directive 2026-07-20). Reuses only
   already-locked tokens: --color-base-lagoon-light (sand) as background
   for genuine prominence, --color-ink-text-primary (ink) for text —
   zero new hex, zero new graphic/icon/ornament, per the standing "plain
   type/colour only" rule. Box treatment mirrors .aqua-checkout__returns-
   summary's existing card pattern (padding/border-radius) below. */
.aqua-checkout__deposit-notice {
	margin-top: 18px;
	padding: 16px 18px;
	background: var(--color-base-lagoon-light);
	border-radius: var(--radii-card-small);
}

.aqua-checkout__deposit-notice-title {
	margin: 0 0 6px;
	font-size: 15px;
	color: var(--color-ink-text-primary);
}

.aqua-checkout__deposit-notice-text {
	margin: 0 0 6px;
	font-size: 14px;
	font-weight: 600;
	color: var(--color-ink-text-primary);
}

.aqua-checkout__deposit-notice-contact {
	margin: 0;
	font-size: 13px;
	line-height: 1.5;
	color: var(--color-ink-text-primary);
}

/* Deposit note (plugin-rendered .aqua-leadtime-deposit-note — layout
   lives in the plugin's own inline stylesheet per its "single source of
   truth for color" rule; this theme-side rule only nudges spacing where
   it sits inside PDP/cart layout containers this theme owns). */
.aqua-pdp__deposit-note-slot {
	margin-top: -4px;
}

.aqua-checkout__legal-disclosure {
	margin-top: 32px;
}

.aqua-checkout__returns-summary {
	margin-top: 18px;
	padding: 16px 18px;
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card-small);
}

#place_order {
	width: 100%;
	font-size: 16px;
	padding: 1em 1.4em;
}

/* ==========================================================================
   15. v2.3.0 — contact page (as3-contact.png layout, WhatsApp-forward,
   purple/cream palette). WhatsApp-only decision (v2.1.2) and the M-P0-09
   dead-form removal are unchanged — no phone/email card, no form re-added.
   ========================================================================== */
.aqua-contact {
	position: relative;
}

.aqua-contact__header,
.aqua-contact-cards,
.aqua-contact__legal,
.aqua-contact__policies {
	position: relative;
	z-index: 1;
}

.aqua-contact__subtitle {
	max-width: 62ch;
	font-size: 16px;
	color: var(--color-ink-text-primary);
	opacity: .8;
	margin: 0 0 32px;
}

.aqua-contact-cards {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
	gap: var(--spacing-card-gap);
	margin-bottom: 40px;
}

.aqua-contact-card {
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card);
	box-shadow: var(--elevation-card-shadow);
	padding: 22px 22px 24px;
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.aqua-contact-card--accent {
	border-color: var(--cta-signal-primary);
}

.aqua-contact-card__label {
	font-size: 12px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .04em;
	color: var(--cta-signal-primary);
}

.aqua-contact-card__body {
	margin: 0;
	font-size: 15px;
	line-height: 1.5;
	color: var(--color-ink-text-primary);
	flex: 1;
}

.aqua-contact__legal {
	margin-bottom: 40px;
}

.aqua-policy-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: 16px;
}

.aqua-policy-card {
	display: flex;
	flex-direction: column;
	gap: 6px;
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card-small);
	padding: 16px 18px;
	color: var(--color-ink-text-primary);
}

.aqua-policy-card:hover,
.aqua-policy-card:focus {
	text-decoration: none;
	border-color: var(--cta-signal-primary);
}

.aqua-policy-card__title {
	font-weight: 700;
}

.aqua-policy-card__link {
	font-size: 13px;
	font-weight: 600;
	color: var(--cta-signal-primary);
}

.aqua-policy-card__link::after {
	content: " →";
}

@media (max-width: 540px) {
	.aqua-contact-cards {
		grid-template-columns: 1fr;
	}
}

/* v2.7.0 — no more per-context size override: .aqua-img-placeholder's base
   rule (§13, width:100%/aspect-ratio:1/1/rounded-top) already matches
   .aqua-card__img's real-photo treatment exactly, so a product-card
   placeholder sits in the identical slot a real photo would with zero
   extra rules needed. */

/* ==========================================================================
   16. v2.3.1 — content pages (page.php, new — About/FAQ/Shipping & Lead
   Times/policies), 404 (404.php, new), and search results + search form
   (search.php/searchform.php, new). Before this pass none of these 4 files
   existed in the child theme, so WordPress fell back to the parent
   Storefront theme's own default templates for all of them — off-brand,
   zero token usage. Everything below is additive; nothing in §1-15 was
   edited. Brand tokens only — the raw rgba(103,50,114,…) focus-ring/shadow
   tints below reuse the exact convention §9's .aqua-intent-card:hover
   shadow already established (a CSS var() cannot be decomposed into rgba()
   channels), not a new hardcoded-hex exception.
   ========================================================================== */

/* -- Shared "inner page" padding rhythm for page.php/404.php/search.php. -- */
.aqua-page,
.aqua-error-404,
.aqua-search {
	position: relative;
	padding: 48px 0 72px;
}

.aqua-page__article,
.aqua-error-404__content,
.aqua-search__header,
.aqua-search__results,
.aqua-search__count,
.aqua-quick-categories {
	position: relative;
	z-index: 1;
}

/* --------------------------------------------------------------------
   16a. Content pages (page.php) — About / FAQ / Shipping & Lead Times /
   the 4 policy pages, and any future plain content Page.
   -------------------------------------------------------------------- */
.aqua-page__article {
	max-width: 800px;
	margin: 0 auto;
}

.aqua-page__title {
	margin-bottom: 0.4em;
	font-size: clamp(30px, 4.5vw, 40px);
}

.aqua-page__thumb {
	margin: 0 0 32px;
	border-radius: var(--radii-card);
	overflow: hidden;
	box-shadow: var(--elevation-card-shadow);
}

.aqua-page__thumb-img {
	margin: 0;
}

.aqua-page__pagination {
	margin-top: 32px;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px;
}

.aqua-page__pagination span {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
}

/* Typography scale for raw the_content() output — headings, paragraphs,
   lists, links, tables, blockquote-as-callout, hr, and an optional
   .aqua-callout utility card any content author can apply. h1/h2/h3
   already inherit Baloo 2 + weight/color from §3's global rule; only
   size/rhythm is added here since plain admin-authored content carries no
   utility class. */
.aqua-content {
	font-size: var(--type-body-en-px);
	line-height: 1.7;
	color: var(--color-ink-text-primary);
}

.aqua-content > *:first-child {
	margin-top: 0;
}

.aqua-content p {
	margin: 0 0 1.1em;
}

.aqua-content h2 {
	margin-top: 1.7em;
	font-size: var(--type-section-title-en-px);
}

.aqua-content h3 {
	margin-top: 1.4em;
	font-size: 20px;
}

.aqua-content h4 {
	margin-top: 1.2em;
	font-size: 17px;
}

.aqua-content ul,
.aqua-content ol {
	margin: 0 0 1.2em;
	padding-left: 1.4em;
}

.aqua-content li {
	margin-bottom: 0.45em;
}

.aqua-content li:last-child {
	margin-bottom: 0;
}

.aqua-content a {
	color: var(--cta-signal-primary);
	text-decoration: underline;
	text-decoration-color: rgba(103, 50, 114, .35);
	text-underline-offset: 3px;
}

.aqua-content a:hover,
.aqua-content a:focus-visible {
	text-decoration-color: currentColor;
}

.aqua-content strong {
	color: var(--color-ink-text-primary);
}

.aqua-content hr {
	border: none;
	border-top: 1px solid var(--elevation-hairline);
	margin: 28px 0;
}

.aqua-content img {
	border-radius: var(--radii-card-small);
	margin: 0.4em 0 1.2em;
}

.aqua-content figure {
	margin: 0 0 1.2em;
}

/* Blockquote — the one native WP block that reads naturally as a callout;
   left accent bar + tint background, same visual language as the
   .aqua-callout utility card below without duplicating its rules. */
.aqua-content blockquote {
	margin: 0 0 1.2em;
	padding: 14px 20px;
	background: var(--surfaces-lifted-opaque);
	border-left: 4px solid var(--cta-signal-primary);
	border-radius: 0 var(--radii-card-small) var(--radii-card-small) 0;
	box-shadow: var(--elevation-card-shadow);
	font-style: italic;
}

.aqua-content blockquote p:last-child {
	margin-bottom: 0;
}

/* Generic callout/note card — any content author can wrap a block in
   `<div class="aqua-callout">…</div>` (Gutenberg Group block "Additional
   CSS class", or a Custom HTML block) to get a designed note/aside instead
   of a plain paragraph. Also reused verbatim by search.php's no-results
   state — not a page.php-only class despite living in this sub-section. */
.aqua-callout {
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-left: 4px solid var(--cta-signal-primary);
	border-radius: var(--radii-card-small);
	padding: 18px 20px;
	margin: 0 0 1.2em;
}

.aqua-callout:last-child {
	margin-bottom: 0;
}

.aqua-callout p:last-child {
	margin-bottom: 0;
}

/* Tables — same bordered/radius/striped-row visual language as
   .aqua-spec-table (§11) and table.aq-spec (§12), scoped to plain
   the_content() tables (e.g. the Shipping & Lead Times delivery-tier
   table) via .aqua-content instead of a 3rd near-identical ruleset under
   yet another class name. */
.aqua-content table {
	width: 100%;
	border-collapse: separate;
	border-spacing: 0;
	margin: 0 0 1.2em;
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card-small);
	overflow: hidden;
}

.aqua-content th,
.aqua-content td {
	text-align: left;
	padding: 12px 16px;
	border-bottom: 1px solid var(--elevation-hairline);
	font-size: 15px;
	vertical-align: top;
}

.aqua-content tbody tr:last-child th,
.aqua-content tbody tr:last-child td {
	border-bottom: none;
}

.aqua-content thead th {
	background: var(--cta-signal-primary);
	color: var(--color-ink-text-inverse);
	font-weight: 600;
	border-bottom: none;
}

.aqua-content tbody tr:nth-child(even) {
	background: var(--surfaces-lifted-tint);
}

/* FAQ accordion — <details>/<summary> support for the_content() AND the
   pre-existing .aqua-faq-list/.aqua-faq-item markup front-page.php's
   homepage FAQ section already ships (style.css previously had ZERO rules
   for either — a real pre-existing gap, not a duplicate; both surfaces now
   share one ruleset instead of two near-identical ones). */
.aqua-content details,
.aqua-faq-item {
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-card-small);
	padding: 4px 20px;
	margin: 0 0 10px;
}

.aqua-content details:last-child,
.aqua-faq-item:last-child {
	margin-bottom: 0;
}

.aqua-content summary,
.aqua-faq-item summary {
	list-style: none;
	cursor: pointer;
	padding: 14px 28px 14px 0;
	position: relative;
	font-weight: 600;
	color: var(--color-ink-text-primary);
}

.aqua-content summary::-webkit-details-marker,
.aqua-faq-item summary::-webkit-details-marker {
	display: none;
}

.aqua-content summary::after,
.aqua-faq-item summary::after {
	content: "+";
	position: absolute;
	right: 2px;
	top: 10px;
	font-size: 20px;
	font-weight: 600;
	color: var(--cta-signal-primary);
	transition: transform .2s ease;
}

.aqua-content details[open] summary::after,
.aqua-faq-item[open] summary::after {
	transform: rotate(45deg);
}

.aqua-content summary:focus-visible,
.aqua-faq-item summary:focus-visible {
	outline: 2px solid var(--cta-signal-primary);
	outline-offset: 2px;
	border-radius: 6px;
}

.aqua-content details > :not(summary),
.aqua-faq-item > :not(summary) {
	padding-bottom: 16px;
}

/* --------------------------------------------------------------------
   16b. 404 (Not Found)
   -------------------------------------------------------------------- */
.aqua-error-404__content {
	max-width: 640px;
	margin: 0 auto;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 14px;
	text-align: center;
}

.aqua-error-404__eyebrow {
	margin: 0;
	font-size: 15px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .08em;
	color: var(--cta-signal-primary);
	opacity: .6;
}

.aqua-error-404__title {
	margin: 0;
	font-size: clamp(30px, 5vw, 44px);
}

.aqua-error-404__subtitle {
	margin: 0;
	max-width: 52ch;
	font-size: 16px;
	color: var(--color-ink-text-primary);
	opacity: .8;
}

.aqua-error-404__search {
	width: 100%;
	max-width: 440px;
	margin-top: 6px;
	display: flex;
	justify-content: center;
}

.aqua-error-404__search .aqua-search-form {
	width: 100%;
	max-width: none;
}

.aqua-error-404__links {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 14px;
	margin-top: 4px;
}

.aqua-error-404 .aqua-quick-categories {
	margin-top: 56px;
	text-align: center;
}

.aqua-error-404 .aqua-quick-categories .aqua-policy-grid {
	max-width: 760px;
	margin: 0 auto;
}

/* --------------------------------------------------------------------
   16c. Search results
   -------------------------------------------------------------------- */
.aqua-search__header {
	margin-bottom: 32px;
}

.aqua-search__query {
	color: var(--cta-signal-primary);
}

.aqua-search__form-wrap {
	margin-top: 16px;
	max-width: 480px;
}

.aqua-search__count {
	margin: 0 0 24px;
	font-size: 14px;
	opacity: .7;
}

.aqua-search__result-type {
	display: block;
	font-size: 11px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: .05em;
	color: var(--cta-signal-primary);
	opacity: .8;
	margin-bottom: 4px;
}

.aqua-search__result-title {
	font-size: 17px;
	margin: 0 0 8px;
}

.aqua-search__result-excerpt {
	margin: 0;
	font-size: 14px;
	line-height: 1.5;
	color: var(--color-ink-text-primary);
	opacity: .8;
}

.aqua-search__empty {
	max-width: 640px;
}

.aqua-search .nav-links {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	justify-content: center;
	margin-top: 44px;
}

.aqua-search .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 40px;
	height: 40px;
	padding: 0 12px;
	border-radius: var(--radii-card-small);
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	color: var(--color-ink-text-primary);
	font-weight: 600;
	font-size: 14px;
	text-decoration: none;
}

.aqua-search .page-numbers:hover {
	border-color: var(--cta-signal-primary);
	color: var(--cta-signal-primary);
}

.aqua-search .page-numbers:focus-visible {
	outline: 2px solid var(--cta-signal-primary);
	outline-offset: 2px;
}

.aqua-search .page-numbers.current {
	background: var(--cta-signal-primary);
	border-color: var(--cta-signal-primary);
	color: var(--color-ink-text-inverse);
}

/* --------------------------------------------------------------------
   16d. Search form (searchform.php) — reused by 404 + search + anywhere
   else get_search_form() is called. Same pill visual language as
   .aqua-soon__notify (coming-soon) but its own namespaced classes — and,
   unlike that pre-existing field, ships a visible :focus-visible
   indicator from day one (see assets/css/motion.css for the coming-soon
   field's matching retrofit this same pass).
   -------------------------------------------------------------------- */
.aqua-search-form {
	display: flex;
	align-items: center;
	gap: 8px;
	background: var(--surfaces-lifted-opaque);
	border: 1px solid var(--elevation-hairline);
	border-radius: var(--radii-cta-button);
	padding: 6px 6px 6px 20px;
	max-width: 480px;
}

.aqua-search-form:focus-within {
	border-color: var(--cta-signal-primary);
	box-shadow: 0 0 0 3px rgba(103, 50, 114, .16);
}

.aqua-search-form__input {
	flex: 1;
	min-width: 0;
	border: none;
	outline: none;
	background: transparent;
	font-family: var(--type-text-en), sans-serif;
	font-size: 15px;
	color: var(--color-ink-text-primary);
}

.aqua-search-form__input::placeholder {
	color: var(--color-ink-text-primary);
	opacity: .5;
}

.aqua-search-form__input:focus-visible {
	outline: 2px solid var(--cta-signal-primary);
	outline-offset: 3px;
	border-radius: 8px;
}

.aqua-search-form__submit {
	flex: none;
	white-space: nowrap;
}

/* --------------------------------------------------------------------
   16e. Quick-categories (template-parts/quick-categories-partial.php) —
   reuses .aqua-policy-grid/.aqua-policy-card verbatim (§15); only the
   title needs new spacing.
   -------------------------------------------------------------------- */
.aqua-quick-categories__title {
	margin-bottom: 16px;
}

/* ==========================================================================
   16b. v2.8.0 — VISUAL EMERGENCY FIX: trust bar (header.php). A compact
   strip at the very top of every page — honest lead times, Cash on
   Delivery, the 50%+ deposit term (v2.7.4, unchanged), and a real WhatsApp
   link. Same Deep-Purple-surface / paper-inverse-text pairing
   ".aqua-world__cost-callout" (§ Worlds) already uses — zero new hex.
   Plain type only, no icons/graphics/ornaments. Sits above the sticky
   ".aqua-site-header" below, so it scrolls away and the nav takes over the
   sticky top slot once the visitor scrolls past it (standard utility-bar-
   above-sticky-nav pattern).
   ========================================================================== */
.aqua-trust-bar {
	background: var(--surfaces-lifted-deep-opaque);
}

.aqua-trust-bar__inner {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 6px 28px;
	padding-top: 9px;
	padding-bottom: 9px;
	text-align: center;
}

.aqua-trust-bar__item {
	color: var(--color-ink-text-inverse);
	font-size: 13px;
	font-weight: 600;
	white-space: nowrap;
}

/* v2.9.2 (Ali) — C6, a genuine WCAG AA failure, root-caused in the LIVE
   cascade. `.aqua-trust-bar__item` (specificity 0,1,0) set the correct
   inverse/paper colour, but the trust bar's inner element also carries the
   `.aqua-board` class, and §8 ships
   `.site-content a, .entry-content a, .aqua-board a { color: var(--color-base-clear-mid) }`
   at 0,1,1 — which OUTRANKS it for the one item that is an <a>. Measured on
   the live homepage: the WhatsApp link computed to rgb(120,65,125) =
   #78417D sitting on the bar's #673272 violet. That is 1.25:1 — violet on
   violet, not the "dark grey" it reads as, and far below the 4.5:1 AA
   floor. Re-asserted at 0,2,0 (two classes) so it beats `.aqua-board a`:
   #F9FDEC on #673272 = 8.92:1, comfortably AA (and AAA). Hover/focus now
   shifts the UNDERLINE rather than dropping opacity, because opacity 0.82
   on the old colour was compounding the failure instead of signalling. */
.aqua-trust-bar .aqua-trust-bar__item,
.aqua-trust-bar a.aqua-trust-bar__item,
.aqua-trust-bar__inner a.aqua-trust-bar__item {
	color: var(--color-ink-text-inverse);
}

a.aqua-trust-bar__item {
	text-decoration: underline;
	text-underline-offset: 2px;
}

.aqua-trust-bar a.aqua-trust-bar__item:hover,
.aqua-trust-bar a.aqua-trust-bar__item:focus-visible {
	color: var(--color-ink-text-inverse);
	text-decoration-thickness: 2px;
	text-underline-offset: 3px;
}

@media (max-width: 640px) {
	.aqua-trust-bar__inner {
		gap: 4px 16px;
		padding-top: 7px;
		padding-bottom: 7px;
	}
	.aqua-trust-bar__item {
		font-size: 11.5px;
		white-space: normal;
	}
}

/* ==========================================================================
   17. v2.3.2 — header redesign (BUG FIX)
   Site-wide single-row header. Root cause + fix rationale: see header.php's
   own file-header comment. Reuses §4's .aqua-nav (height/flex/border/
   background) as the row's base — this section only adds the 3-zone
   layout, the dropdown/mobile-panel components, sticky positioning, and the
   new utilities (search toggle / cart wrapper / WhatsApp link). Deep Purple
   (--cta-signal-primary) / Emerald (--color-semantic-success-eco) / off-white
   tokens only — no new hex values, no amber.
   ========================================================================== */
.aqua-site-header {
	position: sticky;
	top: 0;
	z-index: 200;
}

.aqua-site-header__inner {
	justify-content: space-between;
	gap: 24px;
	flex-wrap: wrap;
	position: relative;
}

/* ---- branding: unchanged from v2.0.0 (logo only, never printed alongside
   site-title text — that text/tagline row was never in this block, it came
   from the now-removed duplicate do_action( 'storefront_header' ) call). */

/* ---- mobile nav toggle (hamburger) ----------------------------------- */
.aqua-nav-toggle {
	display: none;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	gap: 5px;
	width: 40px;
	height: 40px;
	padding: 0;
	background: none;
	border: none;
	cursor: pointer;
	flex: none;
	order: 2;
}

.aqua-nav-toggle__bar {
	display: block;
	width: 22px;
	height: 2px;
	background-color: var(--cta-signal-primary);
	border-radius: 2px;
	transition: transform .15s ease, opacity .15s ease;
}

#masthead.is-nav-open .aqua-nav-toggle__bar:nth-child(1) {
	transform: translateY(7px) rotate(45deg);
}

#masthead.is-nav-open .aqua-nav-toggle__bar:nth-child(2) {
	opacity: 0;
}

#masthead.is-nav-open .aqua-nav-toggle__bar:nth-child(3) {
	transform: translateY(-7px) rotate(-45deg);
}

/* ---- primary nav ------------------------------------------------------ */
.aqua-primary-nav {
	flex: 1 1 auto;
	min-width: 0;
	order: 3;
}

.aqua-primary-nav__list {
	display: flex;
	align-items: center;
	gap: 28px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.aqua-primary-nav__item {
	position: relative;
	display: flex;
	align-items: center;
}

.aqua-primary-nav__link {
	font-family: var(--type-text-en), sans-serif;
	font-size: 15px;
	font-weight: 600;
	color: var(--color-ink-text-primary);
	text-decoration: none;
	white-space: nowrap;
}

.aqua-primary-nav__link:hover,
.aqua-primary-nav__link:focus-visible {
	color: var(--cta-signal-primary);
}

.aqua-primary-nav__link.aqua-nav-cat-chip::after {
	background-color: var(--cta-signal-primary);
}

.aqua-primary-nav__link:focus-visible {
	outline: 2px solid var(--cta-signal-primary);
	outline-offset: 3px;
	border-radius: 4px;
}

/* Shop caret + dropdown */
.aqua-primary-nav__caret {
	background: none;
	border: none;
	padding: 4px;
	margin-left: -4px;
	cursor: pointer;
	color: var(--cta-signal-primary);
	font-size: 10px;
	line-height: 1;
	display: inline-flex;
	align-items: center;
}

.aqua-primary-nav__submenu {
	list-style: none;
	margin: 0;
	padding: 10px;
	position: absolute;
	top: calc(100% + 14px);
	left: 0;
	min-width: 220px;
	background: var(--surfaces-lifted-opaque);
	border-radius: var(--radii-card-small);
	box-shadow: var(--elevation-card-shadow);
	opacity: 0;
	visibility: hidden;
	transform: translateY(6px);
	transition: opacity .15s ease, transform .15s ease, visibility .15s;
	z-index: 210;
}

.aqua-primary-nav__item--shop:hover .aqua-primary-nav__submenu,
.aqua-primary-nav__item--shop:focus-within .aqua-primary-nav__submenu,
.aqua-primary-nav__item--shop.is-open .aqua-primary-nav__submenu {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

.aqua-primary-nav__submenu li + li {
	margin-top: 2px;
}

.aqua-primary-nav__submenu a {
	display: block;
	padding: 8px 12px;
	border-radius: var(--radii-card-small);
	font-size: 14px;
	font-weight: 500;
	color: var(--color-ink-text-primary);
	text-decoration: none;
	white-space: nowrap;
}

.aqua-primary-nav__submenu a:hover,
.aqua-primary-nav__submenu a:focus-visible {
	background: var(--surfaces-lifted-tint);
	color: var(--cta-signal-primary);
}

/* ---- utilities: search toggle / cart / WhatsApp ----------------------- */
.aqua-site-header__utilities {
	display: flex;
	align-items: center;
	gap: 16px;
	flex: none;
	order: 4;
}

/* v2.9.1 — D9 P0 (audit row 2.7). This control used to be a CSS-DRAWN
   MAGNIFYING GLASS: a 15x15 `border-radius:50%` ring with an `::after`
   2x7px bar rotated -45deg for the handle. Assembled from CSS primitives
   rather than an .svg file, but a drawn representational object either
   way, and it rendered in the header of every page on the site.
   Replaced with the word "Search" — a text label, which is what the
   button's aria-label already said. The control is now a pill sized by its
   own text instead of a fixed 38px circle around a glyph. */
.aqua-header-search-toggle {
	height: 38px;
	padding: 0 16px;
	border-radius: var(--radii-cta-button);
	border: 1px solid var(--elevation-hairline);
	background: var(--surfaces-lifted-opaque);
	color: var(--cta-signal-primary);
	font-family: var(--type-text-en), Inter, system-ui, sans-serif;
	font-size: 14px;
	font-weight: 600;
	cursor: pointer;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	transition: background-color .15s ease, color .15s ease;
}

.aqua-header-search-toggle[aria-expanded="true"] {
	background: var(--cta-signal-primary);
	border-color: var(--cta-signal-primary);
	color: var(--color-ink-text-inverse);
}

.aqua-header-search-panel[hidden] {
	display: none;
}

.aqua-header-search-panel {
	border-top: 1px solid var(--elevation-hairline);
	background: var(--surfaces-lifted-opaque);
}

.aqua-header-search-panel__inner {
	padding: 16px var(--spacing-board-padding-x);
}

.aqua-header-search-panel .aqua-search-form {
	max-width: 560px;
	margin: 0;
}

.aqua-site-header__cart {
	display: flex;
	align-items: center;
	flex-shrink: 0; /* v2.3.3 — ensure the cart cluster keeps its room next to the WhatsApp pill instead of getting squeezed by the nav. */
}

.aqua-site-header__cart ul {
	list-style: none;
	margin: 0;
	padding: 0;
}

.aqua-site-header__cart a {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-size: 14px;
	font-weight: 600;
	color: var(--color-ink-text-primary);
	text-decoration: none;
	white-space: nowrap; /* v2.3.3 — fixes cart totals like "480,00 EGP" wrapping to 2 lines. */
}

.aqua-site-header__cart a:hover,
.aqua-site-header__cart a:focus-visible {
	color: var(--cta-signal-primary);
}

/* v2.9.1 — D9 (audit row 2.9). A 20x18 bordered rounded rectangle standing
   in for a shopping cart — a drawn object, only reachable via header.php's
   Storefront-missing fallback branch, but a violation wherever it renders.
   Replaced by a "Cart" text label in that branch. */
.aqua-header-cart-link__label {
	font-weight: 600;
	color: var(--cta-signal-primary);
}

.aqua-header-whatsapp {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	background-color: var(--color-semantic-success-eco);
	color: var(--color-ink-text-inverse);
	padding: 8px 16px;
	border-radius: var(--radii-cta-button);
	font-size: 14px;
	font-weight: 600;
	text-decoration: none;
	white-space: nowrap;
	transition: filter .15s ease;
}

.aqua-header-whatsapp:hover,
.aqua-header-whatsapp:focus-visible {
	filter: brightness(0.94);
	color: var(--color-ink-text-inverse);
}

/* v2.9.1 — D9 P0 (audit row 2.6). `.aqua-header-whatsapp__icon` painted a
   data-URI SVG CHAT-BUBBLE glyph as a CSS mask, sitewide in the header and
   again in the footer/checkout/contact pill. The v2.4.0 comment that stood
   here narrated drawing it in so many words ("swap the dot for an actual
   chat-bubble glyph"), which is the violation stated out loud. Both the
   rule and header.php's `<span>` are deleted — the pill's own "WhatsApp"
   TEXT label is the affordance, and a word is not a drawing.
   Consequence handled below: the <=900px collapse used to hide that text
   label and round the pill into a circle around the glyph. With no glyph
   that would leave an empty green circle, so the text now STAYS at every
   width and the pill simply tightens. Nothing in the header is now
   icon-only. */

/* ---- responsive: collapse to hamburger below 900px --------------------- */
@media (max-width: 900px) {
	.aqua-nav-toggle {
		display: inline-flex;
	}

	.aqua-header-whatsapp {
		padding: 8px 12px;
		font-size: 13px;
	}

	.aqua-primary-nav {
		flex-basis: 100%;
		max-height: 0;
		overflow: hidden;
		order: 5;
		transition: max-height .2s ease;
	}

	#masthead.is-nav-open .aqua-primary-nav {
		max-height: 70vh;
		overflow-y: auto;
	}

	.aqua-primary-nav__list {
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		padding: 12px 0 18px;
		border-top: 1px solid var(--elevation-hairline);
	}

	.aqua-primary-nav__item {
		flex-direction: column;
		align-items: stretch;
	}

	.aqua-primary-nav__link {
		padding: 12px 4px;
		display: block;
	}

	.aqua-primary-nav__caret {
		position: absolute;
		right: 0;
		top: 4px;
	}

	.aqua-primary-nav__submenu {
		position: static;
		box-shadow: none;
		opacity: 1;
		visibility: visible;
		transform: none;
		max-height: 0;
		overflow: hidden;
		padding: 0 0 0 14px;
		transition: max-height .2s ease;
	}

	.aqua-primary-nav__item--shop.is-open .aqua-primary-nav__submenu {
		max-height: 400px;
		padding: 6px 0 6px 14px;
	}
}

@media (max-width: 540px) {
	.aqua-header-search-panel__inner {
		padding: 14px 20px;
	}
}

/* ==========================================================================
   18. v2.9.0 — COMMERCE-GRID CREDIBILITY PASS (Ali)
   Job 2026-07-20-egfs-grid-credibility. Everything in this section is
   presentation-layer only: no lead-time/deposit business logic, no pricing
   logic, no plugin contract touched. Selectors are deliberately written to
   reach BOTH the theme's own bespoke card (templates/woocommerce/
   archive-product.php) and WooCommerce/Storefront's default loop item, so
   related products, upsells, cross-sells and any plugin-rendered
   [products] shortcode get the identical treatment — the standing "every
   change must apply to all pages/templates" rule.
   ========================================================================== */

/* -- D1, second half: WooCommerce's OWN loop title. The theme's bespoke
   card uses .aqua-card__title (§4), but every non-theme loop renders
   `.woocommerce-loop-product__title` instead, which Storefront sets in the
   heading face, centred. Same compact-sans/2-line/left treatment so the
   two never diverge. -- */
.woocommerce ul.products li.product .woocommerce-loop-product__title,
.woocommerce-page ul.products li.product .woocommerce-loop-product__title,
ul.products li.product .woocommerce-loop-product__title {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	font-family: var(--type-text-en), -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	font-size: 15px;
	font-weight: 600;
	letter-spacing: 0;
	line-height: 1.35;
	min-height: calc(1.35em * 2);
	color: var(--color-ink-text-primary);
	text-align: left;
	overflow-wrap: break-word;
	margin: 0 0 6px;
	padding: 0;
}

/* -- D1/D5: the price on a default loop item is centred and heading-sized
   in Storefront too. Match the theme card's .aqua-price treatment. -- */
.woocommerce ul.products li.product .price,
.woocommerce-page ul.products li.product .price {
	text-align: left;
	font-size: var(--type-price-px);
	font-weight: 600;
	color: var(--color-ink-text-primary);
}

/* --------------------------------------------------------------------------
   D3 — LEAD-TIME BADGE, GRID CONTEXT ONLY.
   The badge is rendered by the aqua-leadtime plugin, which owns its state
   machine, its copy and its colours; the theme owns ZERO of that and this
   version changes none of it. What it does change is how the GRID variant
   is presented, because at full verbosity on a ~250px card the badge wrapped
   to three lines in a filled salmon panel (plugin tokens
   #F3E7D2 bg / #8A5A22 text — neither is one of the six locked brand
   colours) and ended up visually louder than the price.

   Two things make this override necessary and safe:
   1. The plugin emits its colours as INLINE styles as a cache-safety
      fallback, so a stylesheet rule cannot win without `!important`. The
      `!important` here is scoped strictly to `--grid`; the pdp/cart/
      checkout/email variants keep the plugin's own painting untouched.
   2. The compact one-line LABEL itself is built theme-side by
      aqua_studio_leadtime_grid_label() (functions.php) from the plugin's
      own resolved state and its own stored day-range meta — the full
      plugin sentence is preserved verbatim as the element's title
      attribute and as visually-hidden text, so nothing is truncated away
      from a screen-reader user or from hover. See that function's docblock.
   The DOA link is hidden here and shown in full on the PDP, where there is
   room for it (.aqua-pdp__leadtime-badge-slot, §11 — unchanged).
   -------------------------------------------------------------------------- */
.aqua-leadtime-badge--grid,
.aqua-card .aqua-leadtime-badge--grid {
	display: inline-flex;
	align-items: center;
	gap: 0.45em;
	max-width: 100%;
	margin: 0 0 10px;
	padding: 0.24em 0.62em;
	border-radius: var(--radii-badge-pill);
	background-color: rgba(103, 50, 114, 0.07) !important;
	color: var(--color-base-luminous-deep) !important;
	border: 1px solid rgba(103, 50, 114, 0.18) !important;
	font-family: var(--type-text-en), -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	font-size: 11.5px;
	font-weight: 600;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	line-height: 1.3;
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	text-align: left;
}

.aqua-leadtime-badge--grid .aqua-leadtime-badge__dot {
	flex: none;
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background-color: var(--color-semantic-success-eco) !important;
}

.aqua-leadtime-badge--grid .aqua-leadtime-badge__text {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	min-width: 0;
}

/* The full explanatory copy + the DOA policy link belong on the single
   product page, not repeated on ~40 grid cards. */
.aqua-leadtime-badge--grid .aqua-leadtime-badge__doa-link {
	display: none;
}

/* Same compaction for the plugin's per-product deposit line wherever a
   default WooCommerce loop fires its grid hook (the theme's own card does
   not render it). Copy is the plugin's own 'compact' verbosity — see
   aqua_leadtime_get_deposit_copy( $state, 'compact' ) — not a new string. */
.aqua-leadtime-deposit-note--grid {
	margin: -4px 0 10px;
	font-family: var(--type-text-en), -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
	font-size: 11.5px;
	font-weight: 500;
	line-height: 1.35;
	color: var(--color-ink-text-primary) !important;
	text-align: left;
	opacity: 0.8;
}

/* Visually-hidden helper — carries the plugin's full lead-time sentence to
   assistive tech while the visible badge stays compact. Standard WP
   .screen-reader-text geometry. */
.aqua-visually-hidden {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* --------------------------------------------------------------------------
   D9 — BODY / LINK CONTRAST (WCAG 2.1 AA).
   Reported: "body copy is pale blue-grey on near-white". Root cause: this
   is a Storefront CHILD theme, and Storefront ships a Customizer-generated
   INLINE stylesheet (attached to the `storefront-style` handle) whose
   default body text is a mid-grey. §2's bare `body { color: ... }` rule
   did not reach the parent's more specific content selectors, so anything
   the theme did not explicitly style fell back to that grey. Same class of
   bug — and the same anchoring fix — as the v2.4.2 `#colophon` footer-link
   pass. `aqua-studio-style` is enqueued with `storefront-style` as a
   dependency, so it always loads after the parent's inline block and wins
   at equal specificity.
   Verified ratios (WebAIM formula, sRGB):
     ink #3A2A40 on paper #F9FDEC ....... 12.5:1  (AA + AAA, body)
     ink #3A2A40 on white #FFFFFF ....... 13.0:1  (AA + AAA, cards)
     violet #78417D on paper #F9FDEC .... 7.2:1   (AA + AAA, links)
     violet #78417D on white #FFFFFF .... 7.4:1   (AA + AAA, links)
     paper #F9FDEC on deep-purple #673272  8.9:1  (AA + AAA, buttons)
   No body or link pairing in the theme now falls below 4.5:1.
   -------------------------------------------------------------------------- */
body,
.site,
.site-content,
.site-main,
.entry-content,
.aqua-board,
.site-content p,
.site-content li,
.site-content dd,
.site-content td,
.entry-content p,
.entry-content li,
.aqua-board p,
.aqua-board li,
.woocommerce-page .site-content p,
.woocommerce-page .site-content li {
	color: var(--color-ink-text-primary);
}

.site-content a,
.entry-content a,
.aqua-board a,
.woocommerce-page .site-content a {
	color: var(--color-base-clear-mid);
}

/* Buttons/CTAs are painted by §5 and must not be re-coloured by the broad
   link rule above — they carry inverse text on the deep-purple fill. */
.site-content a.button,
.site-content a.aqua-cta,
.entry-content a.button,
.aqua-board a.button,
.aqua-board a.aqua-cta,
.woocommerce .site-content a.button,
.woocommerce-page .site-content a.button {
	color: var(--color-ink-text-inverse);
}

/* v2.9.1 — D7 (audit row 8.1), and a CORRECTION to that row, caught by
   rendering rather than by reading.
   The register recorded this link as emerald #438F49 on white = 3.99:1 and
   called it the theme's one real AA failure. Reading `.aqua-intent-card__link`
   in isolation, that is exactly what it says. But the intent cards sit inside
   `<section class="aqua-board …">`, so `.aqua-board a` above (0,2,0) outranks
   `.aqua-intent-card__link` (0,1,0) and has always won: the colour actually
   PAINTED was violet #78417D = 7.37:1, which passes. So the AA failure was
   never live — the audit measured the declaration, not the cascade.
   What WAS real is the confusion: the component declared one colour and
   rendered another, so anyone "fixing" the declared value (as this job first
   did) would have changed nothing and believed otherwise. Resolved by giving
   the component a rule that actually wins, here beside the other exceptions
   to the broad link rule, set to deep-purple #673272 = 9.23:1 — better than
   the 7.37:1 it was silently rendering, and now the declared colour and the
   painted colour are the same value. */
.aqua-board .aqua-intent-card__link,
.site-content .aqua-intent-card__link {
	color: var(--cta-signal-primary);
}

/* v2.9.0 — the two remaining low-opacity text treatments on the product
   card raised so that BOTH still clear 4.5:1 against the card's white
   surface (0.7 put the brand line at ~5.2:1; 0.78 lifts it to ~6.4:1 with
   the same visual hierarchy intact). */
.aqua-card__brand--text {
	opacity: 0.78;
}

/* -- v2.9.0 — per-context title sizes. The §4 base is tuned for the dense
   commerce grid (15px); two surfaces legitimately want more presence and
   are given it explicitly, at a specificity that does not depend on
   stylesheet load order (aqua-worlds.css is a separate enqueue). Both keep
   the base rule's family, weight, alignment and reserved-height behaviour —
   only the scale changes. -- */
.aqua-world-card .aqua-card__title,
.aqua-worlds-archive__grid .aqua-card__title {
	font-size: clamp(16px, 1.25vw, 19px);
}

/* Search results are page-level content, not comparison cards — allow a
   third line before clamping so a long post/product title is far less
   likely to be cut. */
.aqua-search__result-title.aqua-card__title {
	-webkit-line-clamp: 3;
	line-clamp: 3;
	min-height: 0;
}

/* -- v2.9.0 — D6 side-effect, and a bug fixed for free. archive-aqua_world.php
   marks its layout `.aqua-archive__layout--no-facets`, but that modifier had
   NO rule anywhere in the theme — so the Worlds archive inherited the old
   `220px 1fr` two-column track and dropped its single content column into
   the 220px facet slot. That is the open "Worlds archive renders cards in a
   single narrow left column instead of a grid" defect on record; collapsing
   `.aqua-archive__layout` to one full-width column (§10) resolves it. The
   modifier is given an explicit rule here so its intent is self-documenting
   and it can never silently inherit a future multi-column layout again. -- */
.aqua-archive__layout--no-facets {
	grid-template-columns: 1fr;
}

/* v2.9.1 — D1 P2 (audit rows 4.3 + 4.4). Both the Worlds ARCHIVE h1 and the
   single-World h1 used `.aqua-section-title` — the same 28px step as every
   in-page section heading on the site — so a page's primary object read at
   exactly the same weight as the "Related" strip below it, and on the
   single World the tank's own name read smaller than the hero image beside
   it. Page-level headings get their own step. Scoped to these two
   templates' own wrappers so no section title anywhere else moves. */
.aqua-worlds-archive > .aqua-archive__header .aqua-section-title,
.aqua-world > .aqua-world__header .aqua-section-title {
	font-size: clamp(32px, 3.4vw, 44px);
	line-height: 1.1;
}

/* v2.9.1 — audit row 4.1's second half: `.aqua-archive__main-column` had no
   rule anywhere either. Harmless today (it is the sole grid child and
   stretches by default) but undeclared, so it reads as an accident. Made
   explicit — `min-width: 0` is the load-bearing part: without it a grid
   item's automatic minimum size is its CONTENT size, which lets a long
   unbroken product/World title push the column wider than its track and
   re-create the exact "cards spill out of their column" class of defect
   this row exists to close. */
.aqua-archive__main-column {
	min-width: 0;
}


/* ==========================================================================
   CHANGELOG — keep at the BOTTOM of this file, always.
   WordPress only scans the first 8192 bytes of style.css for the theme
   header block. A previous release pushed `Theme Name:` to byte 12204 by
   growing a changelog above it and the theme stopped being recognised.
   The header block stays at byte 0; every historical note lives down here.
   ========================================================================== */

/**
 * v2.9.1 — Job 2026-07-20-egfs-audit-clearance (Ali) — AUDIT REGISTER
 * CLEARANCE, built on v2.9.0. Input: ops/audit-2026-07-19-cross-template.md
 * (40 defects / 22 files / P0 16, P1 11, P2 13).
 *
 * ### PRIORITY 1 — INVENTED GRAPHICS (D9). The standing no-authored-artwork
 * rule had regressed, and the v2.7.1 sweep that reported "zero found" missed
 * every one of these because it searched for `.svg` FILES. The artwork was
 * inline, CSS-drawn, or generated at runtime. All cleared:
 *   - home-intent-cards.php x4 — hand-authored inline SVGs, including A
 *     DRAWN FISH (body path, tail chevron, eye circle), plus an equalizer,
 *     an open book and a chat bubble. Deleted. Replaced with a step numeral
 *     on a flat tinted panel: typography and a rectangle, locked palette,
 *     no representational form. No icon library was pulled in.
 *   - style.css check-mark-in-circle mask (3x per PDP) — deleted; heading
 *     text already carried the message.
 *   - style.css chat-bubble mask (sitewide header + footer/checkout pill) —
 *     deleted; the "WhatsApp" text label is the affordance. The <=900px rule
 *     that hid that label and rounded the pill into a circle around the
 *     glyph is rewritten, or mobile would have shown an empty green dot.
 *   - style.css CSS-DRAWN MAGNIFYING GLASS (ring + rotated bar) in the
 *     sitewide header — replaced with the word "Search".
 *   - style.css CSS-drawn cart glyph (fallback branch) — text label.
 *   - assets/js/aqua-hero-caustics.js — procedurally DREW a caustics texture
 *     over the hero every frame. File, bootstrap, <canvas> and CSS all
 *     deleted. Nothing replaces it: v2.8.0 stripped the hero's tint layers
 *     on the owner's explicit "full crisp colour" directive, so adding a
 *     compensating gradient would walk back into a ruled-on defect.
 *   - motion.css §1 — dead .aqua-hero__shafts/__shimmer rules drawing light
 *     shafts and caustics in gradients. No PHP emitted the markup, so they
 *     were dormant violations waiting to go live. Section deleted.
 *   - aqua-hero-tank.css/.js (~1,200 lines, 12 off-palette hexes, a latent
 *     4.47:1 AA failure, canvas texture generators) — deleted. "Left on disk
 *     unreferenced" still ships in the zip.
 *   KEPT DELIBERATELY, for a panel ruling: the 3-bar CSS hamburger
 *   (header.php) and the 3px gradient ribbon (.aqua-surface-reef::before).
 *   Both are UI primitives — an affordance and a rule — not representational
 *   artwork, and both use only locked tokens. Flagged, not asserted.
 *
 * ### PRIORITY 2 — REMAINING P0s
 *   - Rows 4.1 / 1.2 / 1.5 / 1.6 / 1.7 / 7.5 were already closed by v2.9.0;
 *     re-verified rather than re-fixed. 4.1's second half (an unauthored
 *     `.aqua-archive__main-column`) is now declared, with `min-width:0` so a
 *     long title cannot push the column past its track.
 *   - Row 1.1 — the display stack fell back to `Georgia, SERIF` while Baloo 2
 *     is a sans. Every heading on the site rendered serif whenever the
 *     webfont was slow or blocked: the actual mechanism behind the "giant
 *     serif titles" defect. Corrected to a sans stack in both places it
 *     occurred. No serif fallback now exists anywhere in the theme.
 *   - Rows 3.1-3.3 — the tool-page gate dequeued the ENTIRE brand stylesheet
 *     on a SLUG match, so /guides/ and /species/ (both in the primary nav)
 *     lost all site chrome and rendered on tool-app.css's off-palette black.
 *     Gate narrowed from slug to TEMPLATE (is_tool_app_shell()), so only
 *     pages actually replacing the site shell lose it. tool-app.css rebuilt
 *     on locked tokens — ink ground, paper text (12.8:1), sand links
 *     (9.5:1); its four off-palette values are gone.
 *   - Row 6.1 — the literal string "[owner to furnish]" was rendering to
 *     CUSTOMERS inside the CPL 181/2018 legal block, on checkout at the
 *     point of payment and on /contact/. Both else-branches deleted; the
 *     block self-suppresses when unpopulated. No legal text or company
 *     detail was invented — the numbers are owner-input. The missing-data
 *     signal moves to a wp-admin notice.
 *   - Row 8.1 — emerald 13px/700 on white measured 3.99:1, the theme's one
 *     genuine AA failure. Repointed to deep-purple: 9.23:1. Emerald itself
 *     is untouched — it is a locked primary used correctly elsewhere, so the
 *     fix belongs at the call site, not in the palette.
 *
 * ### PRIORITY 3 + cheap remainder
 *   - Row 6.2 — cart quantity was static text while "Update cart" still
 *     rendered. Restored to woocommerce_quantity_input() with the standard
 *     cart[{key}][qty] name. Found and fixed a latent bug alongside it: the
 *     line quantity was being read through `woocommerce_cart_item_quantity`,
 *     which filters the control's HTML, not a number — correct only while
 *     nothing was hooked to it.
 *   - Row 6.4 — ORDER-DATA LOSS. The governorate select sat outside
 *     WooCommerce's field system: never validated, never saved, never
 *     emailed; `required` was browser-side only. Registered via
 *     woocommerce_checkout_fields with persistence and admin display, and
 *     the hand-rolled duplicate removed (two inputs sharing the name would
 *     have let the empty one overwrite the answered one).
 *   - Rows 1.4, 6.3, 7.1, 7.4, 1.8, 4.3-4.5, 6.5, 7.6 also cleared. Of
 *     these 1.4 is worth noting: `.aqua-category-accent` had no base rule at
 *     all, so the six category hues from the v2.5.0 P0 palette fix were
 *     painting a zero-by-zero empty span and had never actually been visible
 *     on the homepage tiles or archive header. The token fix was real; it
 *     had no box to paint. 7.4 was a latent FATAL: three functions declared
 *     in a template partial with no function_exists() guard.
 *
 * Verification: 30/30 PHP files pass `php -l` (PHP 8.5.1). Zero inline
 * `<svg`, zero `mask-image`, zero canvas draw calls, zero CSS-drawn
 * representational shapes remain in shipped code. `Theme Name:` at byte 3.
 *
 * Previous v2.9.0 changelog, UNCHANGED, follows below.
 */

/**
 * v2.9.0 — Job 2026-07-20-egfs-grid-credibility (Ali) — COMMERCE-GRID
 * CREDIBILITY PASS.
 *
 * ### D0 — THE ONE THAT MADE THE OTHERS KEEP COMING BACK (found during
 * render QA against the LIVE site, not in the brief). Production was
 * serving the ENTIRE pre-rebrand "Living Water" token set while running
 * theme v2.8.0 — every value on build/tokens.json's own "refuses"
 * blacklist: ink #0D2A44 navy, clear-mid #2E8FB8 blue, luminous-deep
 * #123E63, lagoon-light #DCEEF4, inverse #EAF6FB, eco #2FA36B, CTA
 * #C6402E rust, display face Fraunces, paper #F4FAFC, radii-card 14px,
 * nav-height 92px. CAUSE: tokens.css reached the browser ONLY through
 * `@import url("assets/css/tokens.css")`, and a CSS @import carries no
 * `?ver=` query. `style.css?ver=X` was cache-busted every release; the
 * token file it imported never was, so behind LiteSpeed Cache the browser
 * kept the pre-rebrand copy indefinitely. Every palette correction shipped
 * since v2.5.0 has been invisible on production — which is why the same
 * "wrong colour / wrong font" defects have been re-reported wave after
 * wave. This is the true root cause of D4 (rust buttons), the "display
 * serif" half of D1 (the live face was Fraunces, never Baloo 2), the "blue
 * link" in D7, and D9 (navy ink at low opacity over bluish paper).
 *   FIX (belt and braces): (1) tokens.css is now a real enqueued stylesheet
 *   on handle `aqua-studio-tokens` with AQUA_STUDIO_VERSION as its ?ver=,
 *   registered as a dependency of `aqua-studio-style`; (2) every
 *   un-versioned `@import url("tokens.css")` is removed theme-wide —
 *   style.css, aqua-worlds.css and tool-app.css (that last one also gains
 *   an explicit token dependency, since tool pages deliberately dequeue the
 *   main child stylesheet); (3) style.css §1 now declares the locked token
 *   set in its own :root, in the file that IS guaranteed cache-busted, so a
 *   stale token file in any cache layer we do not control can no longer put
 *   the brand out of lock.
 *
 * ### D0b — LOCKED DISPLAY FACE NEVER APPLIED. Separately verified in a
 * live browser: `--type-display-en: Baloo 2;` (unquoted) expands to
 * `font-family: Baloo 2, Georgia, serif`, which is INVALID CSS — a
 * <family-name> is a sequence of identifiers and an identifier may not
 * begin with a digit, so the browser drops the whole declaration and the
 * element keeps its inherited family. Baloo 2 has therefore never rendered
 * anywhere the token was used. Both family tokens are now emitted quoted,
 * and both generators (build/tokens-to-css.php and its Python stand-in)
 * were fixed so regeneration cannot reintroduce it. assets/css/tokens.css
 * was regenerated with the real PHP generator (PHP 8.5.1).
 * Nine owner-diagnosed defects (D1-D9) from a live visual
 * review of aquastudio.me against BulkReefSupply. Built on v2.8.0; the
 * v2.7.4 deposit terms and the whole aqua-leadtime plugin contract are
 * untouched — no lead-time or deposit LOGIC, state, or wording semantics
 * changed anywhere in this version.
 *
 * D1 PRODUCT-TITLE TYPOGRAPHY (root cause found). archive-product.php renders
 *   the loop title as `<h2 class="aqua-card__title">` and the v2.8.0 rule set
 *   no family/size/weight, so every product title inherited §3's `h1,h2,h3`
 *   DISPLAY face (Baloo 2) at the browser default h2 size (~25px) — a
 *   60-character name ran to five lines. Now Inter 15px/600/1.35, hard 2-line
 *   clamp with a reserved 2-line min-height (so titles cannot go ragged),
 *   left-aligned, margin reset. Applied to `.aqua-card__title` (reaches the
 *   archive, homepage tiles, Worlds cards, PDP cross-sells and search) AND to
 *   WooCommerce's own `.woocommerce-loop-product__title` (§18) so non-theme
 *   loops — related products, upsells, [products] shortcodes — match. Worlds
 *   cards and search results get explicit larger scales.
 * D2 MISSING IMAGES. ~61/120 products have no featured image and the slot
 *   painted them in the page's own background colour. The slot now carries a
 *   soft sand->paper wash on locked colours plus the product's own first
 *   INITIAL as plain typography (functions.php) — no drawn artwork, no icon,
 *   no motif; `.aqua-img-placeholder__mark` stays display:none. Same
 *   treatment given to `.aqua-photo__media--empty` (was solid deep-purple) so
 *   every empty image slot sitewide is one consistent treatment. Cards are
 *   flex columns with a fixed 1:1 image, a fixed-height title block and the
 *   actions row pinned by `margin-top: auto`, so a row of cards is level
 *   whether or not the products have photos.
 * D3 LEAD-TIME NOTICE. Grid/loop cards only: the badge is now a compact,
 *   single-line uppercase pill on a violet tint from the locked palette
 *   (replacing the plugin's #F3E7D2/#8A5A22 salmon, which is off-palette),
 *   with the DOA link hidden. The label is built by
 *   aqua_studio_render_leadtime_grid_badge() (functions.php) from the
 *   PLUGIN's own resolved state and its own stored day-range meta, read via
 *   the plugin's own constants; the plugin's full sentence is preserved
 *   verbatim as the badge's title attribute and as visually-hidden text, so
 *   nothing is withheld from hover or from assistive tech. PDP, cart,
 *   checkout and email badges are completely unchanged, DOA link included.
 *   `!important` appears only on the `--grid` variant, and only because the
 *   plugin emits its colours inline as a cache-safety fallback.
 * D4 BUTTONS. `--cta-signal-primary` moved #941E75 -> #673272 at the token
 *   source (build/tokens.json + assets/css/tokens.css). #941E75 was a
 *   wine/rust magenta and is NOT one of the six locked brand colours — it is
 *   the "rust-red block" reported on Add to cart and on the hero CTA. Deep
 *   Purple is the single sitewide primary: Emerald (#438F49) was the
 *   alternative but only reaches 3.89:1 against the paper text token and
 *   fails WCAG AA at control text sizes, where Deep Purple reaches 8.9:1.
 *   Emerald keeps its distinct existing jobs (success/eco, WhatsApp pill).
 *   Buttons dropped from a ~48px full-width block to a normal-height,
 *   auto-width control aligned to the card's left edge.
 * D5 ALIGNMENT. The whole card stack is left-aligned — card, body, actions,
 *   and WooCommerce's own default loop item and price (which Storefront
 *   centres).
 * D6 "STRAY TOOLTIP". Diagnosed: not a tooltip. It was the archive's own
 *   `.aqua-archive__facets` rail — a white sticky 220px card whose lead-time
 *   facet HINT was the sentence in question. The rail rendered zero working
 *   controls (two deliberately inert headings plus one explanatory <p>; no
 *   inputs, no handlers, no query), duplicated D3's per-card signal, and cost
 *   a fifth of the archive width, so it was removed from
 *   templates/woocommerce/archive-product.php and the layout collapsed to one
 *   full-width column (the grid now runs four across). Its CSS is kept for a
 *   future real filter rail. FREE FIX: archive-aqua_world.php's
 *   `.aqua-archive__layout--no-facets` modifier had no rule anywhere, so the
 *   Worlds archive was inheriting the 220px facet track — that is the
 *   recorded open "Worlds archive renders in a single narrow left column"
 *   defect, and it is resolved by this same change (plus an explicit rule so
 *   it cannot silently regress).
 * D7 CATEGORY TILES. Labels get a clamp()-scaled size bound to the viewport
 *   plus the shared wrap/2-line reservation, so they can no longer overflow
 *   their cell and be cropped on both sides. The DUPLICATE label is fixed at
 *   its source: the tile photo is now marked decorative (alt="") in
 *   aqua_studio_render_category_tile(). The repeated name was the image's alt
 *   text — announced a second time inside the same link for screen-reader
 *   users, and painted over the tile whenever the photo was slow or 404'd.
 *   The visible caption is kept rather than an overlay because it is real DOM
 *   text with guaranteed contrast, needs no scrim over unpredictable
 *   photography, and keeps the tile's accessible name out of a decorative
 *   layer. This is the correct call under WCAG 2.1 H67.
 * D8 HEADER LOGO BOX. Root cause: `.aqua-nav` had a FIXED height while
 *   `.aqua-site-header__inner` sets `flex-wrap: wrap`, so a wrapped row grew
 *   taller than the band and the branding block — whose logo SVG carries an
 *   opaque white 1024x1024 backing plate as its first <path> — spilled below
 *   the header's hairline and painted a white box over the hero. Changed to
 *   `min-height` (the token value stays the floor) plus vertical padding, so
 *   the band always contains its own content. Logo enlarged
 *   clamp(72px,8.5vw,116px) -> clamp(88px,9.5vw,132px) with
 *   --spacing-nav-height 124px -> 148px in the same pass. The logo FILE is
 *   untouched, sizing stays height-only with `width: auto`, and the true 1:1
 *   ratio is now stated explicitly — no width is ever forced (a hardcoded
 *   width="220" distorted this mark once before).
 * D9 BODY CONTRAST. Root cause: this is a Storefront CHILD theme and
 *   Storefront ships a Customizer-generated INLINE stylesheet whose default
 *   body text is a mid blue-grey; §2's bare `body { color }` rule never
 *   reached the parent's more specific content selectors. Fixed by anchoring
 *   ink on the real content containers (§18) — the same class of fix as the
 *   v2.4.2 `#colophon` footer pass — which wins because `aqua-studio-style`
 *   is enqueued with `storefront-style` as a dependency. Verified: ink on
 *   paper 12.5:1, ink on white 13.0:1, violet links on paper 7.2:1 and on
 *   white 7.4:1, paper on the deep-purple button 8.9:1. The card brand line's
 *   opacity was raised 0.7 -> 0.78 (5.2:1 -> 6.4:1). No body or link pairing
 *   in the theme is now below 4.5:1.
 *
 * LOCKED items unchanged: the three logo files (byte-identical, ratio
 * untouched), the six palette colours, Baloo 2 + Inter, AQ3D_BASE, the
 * Worlds CPT, and every deposit/lead-time string the plugin owns. No new
 * font, no new hex outside the lock, and zero authored graphics — the only
 * additions to the visual system are a two-stop colour gradient and one
 * typographic initial drawn from real product data.
 */

/**
 * v2.8.0 — Job 2026-07-20-egfs-visual-emergency (Ali) — VISUAL EMERGENCY FIX,
 * owner: site "looks ugly and cheap and amateur" next to bulkreefsupply.com.
 * Built on top of v2.7.4 (deposit terms, kept fully intact — no deposit
 * markup/copy/CSS touched). Four fixes:
 * (1) DUOTONE MASK KILLED — assets/css/aqua-mask.css + assets/js/aqua-mask.js
 * deleted outright (not just neutered). aqua_studio_mask_wrap()/
 * aqua_studio_mask_placeholder() (functions.php) renamed to
 * aqua_studio_photo_wrap()/aqua_studio_photo_placeholder() and rewritten to
 * emit plain full-colour markup — no grayscale/duotone filter, no grain
 * texture, no vignette — see the new ".aqua-photo" rules below (§4). Same
 * fix applied to the homepage hero (assets/css/aqua-hero-photo.css): the
 * saturate(0.92) pre-grade and the #aqHeroWash/#aqHeroGlow/#aqHeroVig
 * colour-wash/vignette layers are removed, markup pruned in front-page.php.
 * Category tiles, Worlds cards, product images, and the hero all render
 * real photography in full, crisp colour by default now; a gentle
 * transform-only zoom on hover/focus is the only interaction retained
 * (never a colour/saturation change).
 * (2) CLIPPED CATEGORY-TILE LABELS FIXED — root cause: ".aqua-card__title"
 * had no explicit wrap/height rule, so a 2-line caption (e.g. "Planted /
 * High-Tech") could exceed the bento grid's auto-sized row and get cropped
 * by ".aqua-card"'s own overflow:hidden (needed for the card's rounded
 * corners). Fixed with an explicit 2-line-safe min-height + guaranteed wrap
 * (§4) — every label now has guaranteed room, sitewide (category tiles,
 * archive header thumb, Worlds cards all share the one class).
 * (3) COMMERCE SIGNALS ADDED — the shop/category product-grid card
 * (templates/woocommerce/archive-product.php) already showed price; it was
 * missing an Add to Cart control entirely. Added a real
 * woocommerce_template_loop_add_to_cart() call in its own
 * ".aqua-card__actions" row (sibling to, not nested inside, the card's
 * anchor — avoids an invalid nested-link), styled full-width/solid via the
 * CTA rules already in §5 (".woocommerce a.button" — no new colour). Cross-
 * sell "Pairs well with" cards already had this button; both are now
 * full-width for a clearer, more prominent CTA (§10).
 * (4) TRUST BAR ADDED — a compact strip at the very top of the page
 * (header.php, before the masthead): honest lead times (sourced to order,
 * 21-30 days), Cash on Delivery, the 50%+ deposit term (v2.7.4, unchanged),
 * and a real WhatsApp link. Deep-Purple surface / paper-inverse text — the
 * exact token pairing ".aqua-world__cost-callout" already uses, zero new
 * hex. Plain type only, no icons/graphics/ornaments.
 * LOCKED brand/type unchanged; AQ3D_BASE, the Worlds CPT, and the deposit
 * copy/logic are untouched. See functions.php's own v2.8.0 header-comment
 * entry for the full renamed-function writeup.
 */

/**
 * v2.7.4 — Job 2026-07-20-egfs-deposit-term (Ali) — NEW COMMERCIAL TERM
 * (owner, verbatim): "all sourced to order items have to paid 50% or
 * more upfront and the rest upon delivery." Reuses the existing
 * aqua-leadtime plugin's lead-time state machine and 5 checkpoints —
 * no parallel system built. Deposit copy applies only to the 3 SOURCED
 * states (sourced_to_order, sourced_to_order_import, livestock), never
 * to ready_to_ship (paid on delivery like any COD order). Store is
 * Cash-on-Delivery only — no online payment gateway exists or is
 * implied anywhere in this copy; the deposit is arranged with the
 * customer over WhatsApp after the order is placed. New CSS this
 * version: `.aqua-checkout__deposit-notice*` (prominent standalone
 * checkout block, before the payment-methods/place-order area) and
 * `.aqua-pdp__deposit-note-slot` (PDP spacing only — the plugin-rendered
 * `.aqua-leadtime-deposit-note` element's own layout/color live in the
 * plugin's inline stylesheet, same "single source of truth for color"
 * split the lead-time badge already uses). Every new color reference is
 * an ALREADY-LOCKED token (--color-base-lagoon-light / sand,
 * --color-ink-text-primary / ink) — zero new hex, zero invented
 * graphic/icon/ornament, per the standing rule. See aqua-leadtime
 * README.md v1.1.2 for the plugin-side half of this change.
 *
 * Previously v2.7.3 — Job 2026-07-19-egfs-worlds-rest-fix-part2 (Ali) — version-bump-
 * only entry, zero CSS rule touched. v2.7.2's fix (below) was only
 * partial — the aqua_world CPT's REST `meta` property was still
 * completely absent and all 5 `_aqua_world_*` values were silently
 * dropped on write. Root cause (confirmed against WordPress core source,
 * not guessed): the CPT's `supports` array was missing `'custom-fields'`
 * — the exact flag WP_REST_Posts_Controller::get_item_schema() gates the
 * whole `meta` schema property on — plus a second bug where
 * `_aqua_world_expected_cost`'s multi-type schema tripped a strict
 * in_array() type check in WP_REST_Meta_Fields::get_registered_fields().
 * Both fixed entirely in inc/class-aqua-studio-worlds.php — see that
 * file's own v2.7.3 header-comment entry for the full root-cause
 * writeup.
 *
 * Previously v2.7.2 — Job 2026-07-19-egfs-worlds-rest-fix (Ali) — version-bump-only
 * entry, zero CSS rule touched. The actual fix (aqua_world CPT REST
 * exposure: 'editor' support + register_post_meta() for the 5
 * `_aqua_world_*` custom fields, so ops/worlds-seed.json can be seeded
 * via the REST API) lives entirely in inc/class-aqua-studio-worlds.php —
 * see that file's own v2.7.2 header-comment entry for the full writeup.
 *
 * Previously v2.7.1 — Job 2026-07-16-egfs-consolidation-logo-fix (Ali) — CONSOLIDATION +
 * CRITICAL brand-integrity fix. (1) assets/img/logo/aqua-studio-logo-primary.svg
 * was serving a STALE file — different SHA-256 than the agreed master in
 * creative/logo-final/ — replaced with a byte-identical copy (all 3 logo files
 * re-verified byte-identical to master via sha256). (2) Confirmed Chen's
 * assets/aquastudio-3d-app/designer.html + brand/ folder (light theme, mascot
 * removed) folded in; AQ3D_BASE unchanged. (3) .aqua-site-branding__logo's
 * height+width:auto rule (below, unchanged) was already correct — the bug was
 * header.php's stale width="220" HTML attribute fighting the logo's true 1:1
 * intrinsic ratio; fixed in header.php. (4) Full-theme invented-graphics
 * sweep: zero found.
 */

/**
 * Aqua Studio Theme — style.css — v2.9.2 — Job 2026-07-20-egfs-live-defect-clearance (Ali)
 * — C1-C8 clearance, verified against the LIVE rendered site (fetched HTML,
 * fetched CSS cascade, and in-browser measurement at a 1512px viewport), not
 * against a local render sample. The v2.9.0/v2.9.1 category-tile claims were
 * both false against production; see functions.php
 * aqua_studio_render_category_tile() for that correction in full.
 *
 * C1/C2/C4 (category tiles) — NOT a CSS defect. The six product_cat term
 *   thumbnails are COMPOSITED images with the category name, a violet wash,
 *   decorative dots and (Automation) an authored gauge panel rasterised into
 *   the JPEG. Live DOM carries exactly one name text node and alt="" was
 *   already correct, so no selector change could ever have fixed it. Handled
 *   in functions.php via aqua_studio_is_composited_category_asset(); CSS side
 *   only drops the now-redundant per-tile caption special cases.
 * C3 — .aqua-home__category-grid: the v2.5.0 bento is replaced by an even
 *   3-column grid. The featured tile measured 795px tall against 708px of
 *   content = 87px of empty card; no legitimate content exists to fill it and
 *   filler artwork is barred, so the span is dropped.
 * C5 — --spacing-nav-height 148px -> 120px, .aqua-nav padding 10px -> 4px,
 *   .aqua-site-branding__logo clamp(88px,9.5vw,132px) -> clamp(92px,9.8vw,138px).
 *   Band 160.07px -> 146px. The locked logo SVG's ink occupies only 25.5% of
 *   its 1024x1024 canvas (measured from the file's path data), so ~74.5% of
 *   the remaining "dead space" is inside the asset and cannot be removed from
 *   the band. Optical wordmark ~33.6px -> ~35.1px. Flagged to owner.
 * C6 — trust bar: `.aqua-board a` (0,1,1) was outranking `.aqua-trust-bar__item`
 *   (0,1,0), rendering the WhatsApp link #78417D on #673272 = 1.25:1. Re-asserted
 *   at 0,2,0 -> #F9FDEC on #673272 = 8.92:1, AA and AAA.
 * C7 — the /shop/ "phantom cell" is Storefront's float clearfix
 *   `ul.products::before/::after {content:"";display:table}` being blockified
 *   into grid ITEMS by our own `ul.products{display:grid}`. `content:none`
 *   stops them consuming slots. Not a facets-rail leftover.
 * C8 — image boxes were ALREADY identical at 227.2px; the real cause of the
 *   ~23px title misalignment is Storefront's `ul.products li.product img
 *   {margin:0 auto 1.618em}` (0,2,3) beating `.aqua-card__img{margin:0}`
 *   (0,1,0) = 23.36px under photo cards only. Re-stated at 0,3,3. Photo boxes
 *   and placeholder boxes now share one wash + hairline treatment.
 *
 * Previous changelog, UNCHANGED, follows.
 *
 * v2.7.0 — Job 2026-07-16-egfs-purge-invented-graphics (Ali) — OWNER RULE
 * ENFORCEMENT + DEFECT FIXES: undoes the v2.5.0 rule violation (agency-
 * authored assets/img/reef-motif.svg woven sitewide) and purges every other
 * drawn ornament/texture/gradient-blob found on a full-theme grep, per the
 * owner's absolute rule (no authored graphics/motifs/emblems/ornaments —
 * ever; only the 3 agreed logo files, real photography, and plain
 * typography/colour/layout). Deleted: assets/img/reef-motif.svg (+ every
 * usage — .aqua-reef-corner component/variants §9, .aqua-nav::before header
 * watermark, .aqua-footer__motif, .aqua-section-divider), plus orphaned
 * dead assets assets/img/logo-seal.svg, hero-living-water.svg, and
 * hero-brand-studio.svg (confirmed unreferenced in any live code path, same
 * "old footgun" class as the other two). Shop/category defect ("circle with
 * a photo, texture behind it, texture at the bottom"): .aqua-archive__thumb
 * and .aqua-card__img (product-grid/homepage-tiles/PDP cross-sell — one
 * shared class, fixed once) go from a circular "specimen avatar" + drop-
 * shadow frame to a plain rounded-rectangle, and the .aqua-reef-corner
 * spans that were the literal "texture behind/at the bottom" are gone from
 * archive-product.php. Also flattened while grepping: .aqua-img-placeholder
 * and aqua-mask.css's --placeholder variant were painting decorative
 * gradient blooms + a rotated-square "petal" mark for "no photo yet" slots
 * — now a flat brand-tint fill, no shape drawn (does NOT touch the
 * protected real-photo hover-reveal recipe — duotone/grain/vignette — which
 * stays byte-for-byte unchanged). motion.css's separate .aqua-soon__reef-
 * corner ornament (coming-soon.php) removed the same way. Footer logo
 * defect ("logo on white background, strange dimensions"): confirmed via
 * render that aqua-studio-logo-mono.svg bakes in its own opaque near-white
 * full-canvas background (not a transparent reversed mark — always plates
 * itself regardless of surface); switched to aqua-studio-logo-primary.svg
 * (still one of the 3 unmodified agreed files, genuinely transparent,
 * reads correctly on the dark footer) with corrected 1:1-ratio width/height
 * attributes. Locked palette/type/real photography/Worlds CPT/aqua-mask
 * hover-reveal interaction are all otherwise unchanged. Previous v2.6.1
 * changelog, UNCHANGED, follows.
 *
 * v2.6.1 — Job 2026-07-16-egfs-packaging-fix (Ali) — URGENT PACKAGING FIX,
 * no styles touched. v2.6.0's zip bundled the 208 aqstudio-3d texture
 * JPGs inside the theme, pushing it to 24.1MB — over Tarek's 10MB browser
 * theme-uploader cap, so the theme could not be installed. Version header
 * bump only, below (still safely under 8KB — see this block's own byte-3
 * "Theme Name:" note two versions up, unchanged this pass). The textures
 * are now shipped out-of-band as web/dist/aqstudio-3d-batches/ (2 batches,
 * <9MB each) for manual WP media upload; see functions.php's own v2.6.1
 * header-comment entry and web/dist/aqstudio-3d-batches/MANIFEST.md for
 * the full writeup. Previous v2.6.0 changelog, UNCHANGED, follows.
 *
 * v2.6.0 — Job 2026-07-16-egfs-foundation-wave (Ali) — FOUNDATION wave:
 * layout-agnostic infrastructure only, no page redesigned/restyled this
 * pass (the incoming Claude Design layout export owns that). Nothing in
 * this file was edited — every new style this wave lives in its own new
 * file (assets/css/aqua-mask.css — the masking recipe + hover-reveal
 * component; assets/css/aqua-worlds.css — the new Worlds CPT templates)
 * so this already-large stylesheet's existing sections/cascade stay
 * completely untouched. Both new files are token-driven (@import
 * tokens.css, var(--token) only, zero hardcoded hex) and built on top of
 * this file's own .aqua-card / .aqua-card-grid / .aqua-cta / .aqua-archive__thumb
 * primitives, so they inherit this file's cascade instead of fighting it.
 * See functions.php's own v2.6.0 header-comment entry for the full
 * four-system writeup (Worlds CPT, masking recipe, real photography
 * wiring, Aquarium Studio 3D embed). Version header bump only, below.
 * Previous v2.5.1 changelog, UNCHANGED, follows.
 *
 * v2.5.1 — Job 2026-07-11-egfs-hero-emergency-fix (Chen) — URGENT live fix, two parts. (1) THIS HEADER: WordPress only reads the first ~8KB of style.css to find "Theme Name:" and register the theme -- v2.5.0 buried it at byte ~12,300 because this entire changelog ran BEFORE the header block, so the theme silently failed to install/update on the live server. Fixed by moving the WP theme-header block (Theme Name ... License URI) into its own short comment at the very top of the file, with this full changelog now AFTER it -- "Theme Name:" now sits well under 1KB in. (2) HOMEPAGE HERO: v2.5.0's live WebGL tank hero (front-page.php) shipped broken -- its SSR poster + every per-world texture pointed at the undeployed 208-image WP media set (empty dark box on live, "LIVE PREVIEW"/"DRAG TO ORBIT" chrome floating over nothing), and even when loaded, the default world's credit was "Puerto Galera reef" -- an actual Philippine scuba dive site, i.e. an ocean photo, not an aquarium. Rebuilt with a same-origin bundled real aquascape TANK photograph (assets/img/hero-aquascape.jpg -- Pexels License, rights-ledger.md row 35) as an always-on base layer that can never be empty, brand-treated via new #aqHeroWash/#aqHeroGlow duotone + Sand-lift layers (new file assets/css/aqua-hero-photo.css, replaces aqua-hero-tank.css in the front-page-only enqueue, functions.php), plus an optional self-contained Canvas2D caustics shimmer (new file assets/js/aqua-hero-caustics.js -- no CDN, no external texture, silently no-ops on any failure). Designer-tool chrome (live-preview tag / drag-to-orbit hint / Wikimedia credit) removed from the homepage hero only -- the dedicated Aquarium Studio designer tool is untouched. New optional footer courtesy credit: .aqua-footer__photo-credit (footer.php) -- Pexels License does not require attribution, added anyway per the fix brief. Full writeup: front-page.php's own header comment. Previous v2.5.0 changelog, UNCHANGED, follows below.
 *

 * Aqua Studio Theme — style.css — v2.5.0 — Job 2026-07-11-egfs-option-a-premium-elevation — OWNER-REPORTED "looks like a cheap free theme, 1990, flat purple, tiny logo, brand not reflected" full Option-A elevation pass (Ali). v2.4.2's footer-contrast + green-WhatsApp-pill fix (below) is UNCHANGED and confirmed already live in this same working tree (diff-verified byte-identical against web/dist/aqua-studio-theme-v2.4.2.zip before this pass started — nothing to fold in, it was already folded). This pass, on top of it: (1) PALETTE BUG F01/P0 — build/tokens.json's category_keys had 4 of 6 keys + --cta-signal-primary collapsed to the same #673272; fixed at the token source with 6 independently-distinct, WCAG-AA-verified hues (freshwater #1C5F4F, planted #57772C, marine #673272 unchanged, coral #BF4A6D, automation #656383, livestock #EFD8AC unchanged) + a distinct CTA #941E75 — deliberately NOT the dispatch brief's suggested #C6402E, which is this same tokens.json's own explicit "refuses" list (banned: retired blue-era "Living Water" CTA-red, superseded by the current Violet/Deep-Purple/Emerald/Sand lock, BRAND.md 2026-07-06). A SECOND, independent wiring bug in this file's §7 (not in the original defect report, would have silently survived a value-only fix) is also fixed: `.cat-key-automation`/`.cat-key-freshwater` selectors were reading `--color-category-keys-marine`/`-main-brand` instead of their own tokens — see §7's own updated comment for the full writeup. Vestigial coral-reef/planted "_blue/_orange/_darkblue/_red/_magenta" token names (leftover from the retired blue "Lagoon"/"Reef" register, see v2.3.0 note below) renamed to true names (accent/pip/tag); the unused coral_reef_darkblue token dropped. (2) LOGO + MOTIFS — owner: "logo tiny... brand not reflected". Header logo clamp raised clamp(56px,7vw,92px)->clamp(72px,8.5vw,116px), nav row grown 92px->124px alongside it (render QA caught a first pass at 108px, LESS than the logo's own 116px max -- fixed to 124px so the mark has real headroom at every width instead of overflowing its own row). New reusable brand asset assets/img/reef-motif.svg (kelp-frond + coral-sprig cluster, on the corrected palette) woven into: the existing .aqua-reef-corner component (§9 below — was 3 abstract color-gradient blobs with ZERO actual coral/kelp iconography; now layers the real motif on top, reaching every template that already uses that component — category archive, page.php, 404, search, contact, unchanged elsewhere); a new low-opacity desktop-only header watermark (.aqua-nav::before); the footer brand row beside the mono logo; and a new home-page section-divider between the intent-cards/guides block and the category grid (creative-excellence §4 "one memorable signature element per page"). (3) CRAFT §4 — Baloo 2 (display) + Inter (text) pairing confirmed already wired sitewide (build/tokens.json type.*, functions.php enqueue) and unchanged; motion.css's existing micro-interaction/scroll-choreography components audited, unchanged (already met the checklist, real IntersectionObserver scroll-reveal already present, not decoration). Bespoke-grid: the general-purpose .aqua-card-grid stays a uniform auto-fill grid on real shopping surfaces (category archive, cross-sell) -- scannable comparison rows are the correct call there. The home page's 6-node showcase gets a NEW bento layout instead (.aqua-home__category-grid: node 1 as a large featured square, nodes 2-5 as stacked pairs, node 6 as a full-width closing banner) -- this did NOT already exist, it was a uniform auto-fill grid identical to the shopping surfaces before this pass. (4) §9 RENDER PASS caught two real bugs a code-only read would have missed: the bento grid's un-floored `auto` row-sizing let the two-row featured cell's content overflow past `.aqua-card`'s overflow:hidden, clipping every tile's title (fixed with an explicit grid-auto-rows: minmax(230px,auto) floor); and the nav-height/logo-max mismatch above. Full render pass at 1440 + mobile 390 covered home/category/PDP after both fixes — see ops/progress for the render paths and verdict. Previous v2.4.2 changelog, UNCHANGED, follows below.
 *
 * Previously v2.4.2 — Job 2026-07-11-egfs-footer-link-contrast-fix — BUG FIX (Ali): CONFIRMED-LIVE follow-up to v2.4.1. v2.4.1 assumed `.aqua-surface-reef a` (§8, specificity 0,1,1) would reach every footer link now that the duplicate footer was gone — FALSE on the live site, caught by a real render of https://aquastudio.me/policies/, not a footer.php-in-isolation check (that method is exactly what missed it last time). Root cause, confirmed against the live-fetched CSS cascade: Storefront core ships its own static `.site-footer a{color:#2c2d33;text-decoration:underline}` (parent style.css, tied 0,1,1 specificity) PLUS a Customizer-generated inline rule — `.site-footer a:not(.button):not(.components-button){color:#333}` — printed in `<head>` from this site's saved color-scheme settings (a DB option, not a theme file, so no repo grep for "clay"/"maroon" will ever find it). Each `:not(.class)` counts as a class for specificity, making that selector (0,3,1) — MORE specific than `.aqua-surface-reef a` — so it wins regardless of stylesheet load order, painting every plain footer link (policy list + credit line) at ~1.05:1 contrast against `--surfaces-reef-darkest-gutter` (#3A2A40), and painting the footer's `.aqua-cta` "Chat on WhatsApp" pill's text the same near-invisible color plus an unwanted underline (`.aqua-cta` never declared its own `text-decoration`, so the `.site-footer a` static rule's `underline` fell through uncontested). Fix (new rules at the end of §8, anchored on `#colophon` — footer.php's own real wrapper ID, confirmed absent from every Storefront/WooCommerce/Customizer stylesheet live, so an ID selector permanently outranks any class/:not() combination Storefront throws at it, no `!important` needed): footer links now resolve to `--color-ink-text-inverse` (12.8:1 on #3A2A40), hover to `--surfaces-lifted-opaque` white (13.25:1); the WhatsApp CTA additionally gets the `aqua-header-whatsapp` class added in trust-register.php (kept `aqua-cta` too, for the existing motion.css ripple hook) so its fill/text now literally reuse the header pill's green token (`--color-semantic-success-eco`) instead of the CTA-purple token, matching the header exactly. `.aqua-surface-reef a`/`.aqua-surface-reef h1,h2,h3` above are UNCHANGED and stay — they're still correct for any future non-footer dark-surface usage; the footer specifically needed the higher-specificity ID anchor because it's the one dark surface that also carries Storefront's own `.site-footer` class.
 *
 * Previously v2.4.1 — Job 2026-07-11-egfs-footer-duplication-fix — BUG FIX (Ali/Salma): CLIENT-REPORTED footer duplication ("two footers stacked, one light/one dark") + recurring "black-on-purple text" report. Root cause was in footer.php, not here (see footer.php's header comment): a leftover `do_action('storefront_footer')` was re-rendering Storefront core's own default footer-widgets block plus a second, wrongly-scoped credit line that sat outside this file's `.aqua-surface-reef a` reach. With that duplicate call removed, the existing v2.4.0 `.aqua-surface-reef a` / `.aqua-surface-reef h1,h2,h3` overrides (§8, unchanged this pass) now correctly reach every remaining footer text node — policy links, credit line, WhatsApp CTA, headings — sitewide, on every page. No new CSS rules were needed; this file's only change is the Version header bump below (cache-busting, matches functions.php's AQUA_STUDIO_VERSION). Full theme-wide re-audit this pass (all `.aqua-surface-reef` usages, every dark-background rule, nav/dropdown/cart/hero/cards/badges/chips) found no other dark-on-dark or dark-on-purple pairing — every other dark-background declaration in this file already pairs correctly with `--color-ink-text-inverse`.
 *
 * Previously v2.4.0 — Job 2026-07-11-egfs-premium-elevation — CLIENT-REPORTED "looks like a cheap free theme coded by a child — black-on-purple text, no hero photo, missing category photos" full elevation pass (Ali/Zeina/Salma). Highest-severity find: §8's .aqua-surface-reef sets color:var(--color-ink-text-inverse) on the dark footer surface, but the global §3 h1,h2,h3{color:var(--color-ink-text-primary)} rule directly targets any heading and beats an inherited color regardless of the ancestor's specificity — so every `<h3 class="aqua-widget-title">` inside footer.php (Contact/Policies/Payment Methods) rendered #3A2A40 text on a #3A2A40 background (the EXACT same hex as --surfaces-reef-darkest-gutter): fully invisible, sitewide, every page. Fixed with a targeted `.aqua-surface-reef h1,h2,h3` override (end of §8). This is almost certainly the client's "black-on-purple" report — an invisible-contrast bug cannot be caught by a text-extraction/code-only review, only a real render, which is why it was not already on the panel's defects register. Also this pass: hero fully rebuilt (assets/img/hero-brand-studio.svg was a near-flat pale wash, now a rich layered water-depth scene; framed/rounded hero media, generous copy spacing, responsive H1 clamp; front-page.php now also checks for a real assets/img/hero-photo.* first); category-archive header now renders the term thumbnail (was text-only, report-12 item 3); product-grid/cross-sell images become an inset circular "specimen" avatar sitewide, matching the locked-palette web/mockups/category.png exactly (was an edge-to-edge rounded-top rectangle); .aqua-trust-register (footer + checkout) gets its first-ever layout CSS (was completely unstyled, stacking as raw full-width blocks); WhatsApp pill icon swapped from a plain white dot (read as "WhatsApp's own badge" per live-panel LV-05) to a chat-bubble mask; raw emoji intent-card icons (LV-11) replaced (template-parts/home-intent-cards.php); hover-lift consistency added to guide/contact/availability/policy cards; small trust-icon added to the PDP Availability module.
 *
 * Previously v2.3.3 — Live-panel P0 polish (theme-only, no plugin changes): (1) header cart amount/link `.aqua-site-header__cart a` gets `white-space:nowrap` + the cart cluster gets `flex-shrink:0` so totals like "480,00 EGP" never wrap to 2 lines; (2) site-branding logo bumped `clamp(44px,6vw,64px)` → `clamp(56px,7vw,92px)` inside the unchanged 92px `--spacing-nav-height` row — reads premium, still a clean single row at the cap; (3) PDP "Specifications" de-duplicated — §11 `.aqua-spec-table` (WooCommerce attributes-only box, e.g. just "Brand: SUNSUN") folded into a new compact `.aqua-pdp__meta-line` under the title, leaving exactly one "Specifications" heading (the rich `table.aq-spec` inside the description, §12); (4) PDP gallery placeholder's leaked internal ops copy ("...minimum 3 rights-cleared photos required before publish") replaced with neutral customer-facing copy (single-product.php only); (5) WhatsApp pill audited — already on `var(--color-semantic-success-eco)` / `#438F49` Emerald token, no raw WhatsApp-green hex found anywhere in the theme, no CSS change needed. Previously v2.3.2 — New §17: header redesign (site-wide BUG FIX — see header.php's own header comment for the root-cause writeup). Single-row sticky header: logo-only branding (unchanged), condensed Shop-dropdown nav replacing the old flat 13-item wrap, search-icon toggle replacing the old permanently-inline search bar, cart, WhatsApp link, mobile hamburger panel. Deep Purple/Emerald/off-white tokens only, reuses existing §4 .aqua-nav primitive + motion.css's .aqua-nav-cat-chip underline-swell component — no new hex values. Builds on the CURRENT v2.3.1 content-pages wave (§16) — none of that CSS edited, this is purely additive. Previously v2.3.1 — New §16: content pages (page.php, 404.php, search.php/searchform.php). Before that, v2.3.0 — TEMPLATE REBUILD to pixel-match the owner-approved mockups (web/mockups/pdp.png, category.png, home-hero.png) using the layout richness of creative/comps-v3 + comps-v4 (their blue "Lagoon Light"/"Reef" register is superseded — purple/cream only). §13/14/15: PDP module rebuild, category-archive polish, cart/checkout visual elevation, contact-page rebuild.
 */

/* ==========================================================================
   v2.9.5 — Job 2026-07-20-egfs-v2.9.5 (Ali) — MEDIA-LIBRARY SLOT LAYER
   ==========================================================================
   NO CSS RULE CHANGED THIS RELEASE. This entry exists because the Version
   header at the top of this file moved to 2.9.5, which is what cache-busts
   every enqueued stylesheet and script (AQUA_STUDIO_VERSION, functions.php) —
   the v2.9.0 fix that stopped releases from being invisible behind LiteSpeed.

   WHAT SHIPPED. Site photography moves from flat files bundled in the theme
   and referenced by hardcoded path, onto WordPress media-library attachments
   addressed by ID. Owner's words: "add them to library so that wp can utilize
   and use them better." A hardcoded path is invisible to WordPress — it gets
   no generated intermediate sizes, emits no srcset/sizes, is never seen by
   LiteSpeed's WebP conversion (that runs over uploads/), has no editable alt
   text, and cannot be changed without a theme release.

   NEW  inc/class-aqua-studio-media.php — slot registry and resolution layer.
        A slot ('hero', 'tile_marine', 'world_poster') resolves: owner-assigned
        attachment ID -> seeded default attachment ID -> BUNDLED THEME FILE.
        That last step is the safety property of the entire release: no state
        of the options table, including completely empty, can produce a broken
        or missing image. It is why the bundled photography is deliberately
        NOT deleted even though most of it is now duplicated in the library —
        removing it would turn a mis-click in wp-admin into a broken homepage.
   NEW  assets/js/aqua-media-admin.js — core wp.media picker wiring for the
        admin screen. Nothing is drawn; previews are real attachment
        thumbnails and real theme-file URLs.
   NEW  Settings -> Aqua Studio Images, tabbed alongside the v2.9.4
        supplier-identity panel. The owner changes the hero or any category
        tile from wp-admin with no release. That is the point of the release.
   NEW  Four registered image sizes — aqua-hero 1600x1200 soft, aqua-tile
        720x720 and aqua-tile-sm 360x360 hard, aqua-poster 1200x800 soft,
        aqua-card-thumb 480x360 soft — so WordPress generates renditions
        instead of the browser downscaling a 2000px master.

   SEEDED: hero -> attachment 368, Automation tile -> 367 (the two whose
   library copy is already the file rendering live in v2.9.4). The other four
   tiles keep resolving to their bundled Pexels photography until the
   photography audit rules on them — a plumbing release must not silently
   change what the site looks like. Seeds are filename-verified before use
   (seeded_id()), so a bare integer cannot point at an unrelated image on a
   staging clone or a fresh install.

   PRESERVED, deliberately and explicitly: the v2.9.3 LiteSpeed lazy-load
   opt-out (data-no-lazy / data-skip-lazy), and fetchpriority="high" plus
   loading="eager" on the LCP hero — wp_get_attachment_image() would otherwise
   stamp loading="lazy" onto the site's own LCP element. Also preserved: the
   v2.9.2 aqua_studio_is_composited_category_asset() guard, now applied to the
   NEW attachment path as well as the term path, so a composited JPEG chosen
   in the new picker is refused exactly as one set on the term already was.
 */


/* ==========================================================================
   v2.9.6 — Job 2026-07-20-egfs-worlds-poster-render (Ali)
   WORLDS POSTER RENDER FIX. No CSS rule added, removed or changed this
   release — this entry is the changelog record and the Version: header bump
   above (cache-busting). The fix is two image-attribute changes, in
   template-parts/world-card.php and single-aqua_world.php.

   SYMPTOM: the ten Worlds repointed at newly licensed Adobe Stock masters
   rendered no poster on /worlds/ and no hero on the single World page. The
   single page additionally read as "title, description, pill, then nothing".

   RULED OUT, each verified against production rather than a local sample:
   the featured_media assignments (all correct), the attachment metadata,
   the generated intermediate sizes, and the emitted server HTML — which
   contains a complete, correct <img> with a full srcset for every affected
   World, and every one of the 56 srcset candidate URLs returns 200.

   ROOT CAUSE: LiteSpeed Cache lazy-load, rewriting get_the_post_thumbnail()
   and the_post_thumbnail() output to a 1x1 base64 GIF and parking the real
   URL in data-src. FIFTH resurfacing of a bug this theme has already fixed
   on the hero (v2.9.3), the six category tiles (v2.9.3), the header logo
   (v2.9.4) and the footer / coming-soon / tool-back-bar marks (v2.9.5) —
   and the first on a WordPress-GENERATED <img> rather than a theme-authored
   one. That is exactly why it was missed: the two Worlds templates are the
   only image slots in the theme that call WordPress's thumbnail functions
   directly instead of routing through Aqua_Studio_Media::render(), whose
   $common array has carried data-no-lazy / data-skip-lazy since v2.9.3.
   This card's own no-featured-image FALLBACK already had the opt-out; the
   featured-image path never did.

   WHY IT LOOKED LIKE THE NEW PHOTOGRAPHY BROKE AND THE OLD SURVIVED:
   identical code path, different latency. The blank window lasts until
   LiteSpeed's JS runs — it initialises on window.load, not
   DOMContentLoaded — and the new 2000px masters with a six-entry srcset
   take materially longer to fetch and decode than the 800px posters with
   four. The untouched Worlds filled fast enough to look fine; the
   reassigned ones did not. Nothing about the new attachments (no parent
   post, no side-load meta, aspect ratio, mime, alt text) was ever involved.

   NOT A SECOND DEFECT: the sparse single World page is the SAME bug.
   .aqua-world__hero is a 16/9 box capped at 520px, so a blanked hero leaves
   a 520px-tall empty band directly under the title and pushes Equipment,
   Matched Livestock and the cost sidebar below the fold. Every one of those
   sections was present and correct in the HTML throughout — confirmed by
   reading the live document and by scrolling the live page.

   PRESERVED: every earlier LiteSpeed opt-out (hero, tiles, header logo,
   footer logo, coming-soon logo, tool-back-bar logo), and the single World
   hero's fetchpriority="high" + loading="eager" — it is the page's LCP
   element and LiteSpeed was overriding both. No photograph reassignment was
   changed; the ten deliberate, visually-reviewed assignments stand exactly
   as made.
   ========================================================================== */
