/* Colors — warm paper neutrals, ink text, rust accent (a nod to the Rust runtime),
   brass hairlines for the "classic/fancy" register, and muted semantic states. */
:root{
  /* Paper — surfaces, lightest to deepest */
  --paper-0:#FFFFFF;
  --paper-1:#FCFAF7;
  --paper-2:#F6F2EB;
  --paper-3:#EFE9DF;
  --paper-4:#E6DED1;

  /* Ink — text and strokes */
  --ink-1:#17150F;
  --ink-2:#3A362D;
  --ink-3:#6B6558;
  --ink-4:#948D7E;
  --ink-5:#B8B1A2;

  /* Lines */
  --line-1:#EAE3D8;
  --line-2:#DED5C6;
  --line-3:#C9BEAB;

  /* Rust — primary accent */
  --rust-50:#FBF1EB;
  --rust-100:#F4DDCE;
  --rust-200:#E7BB9F;
  --rust-300:#D69468;
  --rust-400:#C2703C;
  --rust-500:#AC5426;
  --rust-600:#8F4320;
  --rust-700:#6F341A;

  /* Brass — hairlines, rules, small ornament */
  --brass-200:#E4D6B4;
  --brass-400:#BFA469;
  --brass-500:#A2874A;

  /* Ivy — secondary / success family */
  --ivy-50:#EDF3EE;
  --ivy-300:#8FB39A;
  --ivy-500:#3E7355;
  --ivy-600:#2E5A42;

  /* Semantic states */
  --amber-50:#FBF3E1;
  --amber-500:#9C7415;
  --claret-50:#FAEDEC;
  --claret-500:#A32E28;
  --claret-600:#83231E;
  --slate-50:#ECF1F5;
  --slate-500:#31607F;

  /* Cool neutrals — used ONLY by the site template's "white" and "dark" surface variants.
     The warm paper/ink ramps above are the brand default; these exist so a consuming site
     can pick a genuinely different neutral family rather than a lighter or darker cream. */
  --cool-0:#FFFFFF;
  --cool-1:#F5F7F9;
  --cool-2:#EFF2F5;
  --cool-3:#E3E8ED;
  --cool-4:#CBD3DC;
  --cool-5:#8B96A3;
  --cool-6:#5C6773;
  --cool-7:#3B4550;
  --cool-8:#111820;

  --night-0:#0F1216;
  --night-1:#171B21;
  --night-2:#1E232A;
  --night-3:#262C34;
  --night-4:#626C79;
  --night-5:#8B95A2;
  --night-6:#C2CAD4;
  --night-deep:#090B0E;

  /* ————— Semantic aliases ————— */
  --surface-page:var(--paper-2);
  --surface-card:var(--paper-0);
  --surface-sunken:var(--paper-3);
  --surface-rail:#1B1A15;          /* dark sidebar rail */
  --surface-rail-hover:#2A2822;
  --surface-inverse:var(--ink-1);
  --surface-accent-soft:var(--rust-50);

  --text-title:var(--ink-1);
  --text-body:var(--ink-2);
  --text-muted:var(--ink-3);
  --text-faint:var(--ink-4);
  --text-on-accent:#FFFFFF;
  --text-on-rail:#EDE7DB;
  --text-on-rail-muted:#9A9384;
  --text-link:var(--rust-600);
  --text-link-hover:var(--rust-700);

  --border-subtle:var(--line-1);
  --border-default:var(--line-2);
  --border-strong:var(--line-3);
  --border-focus:var(--rust-500);
  --border-hairline-brass:var(--brass-200);

  --accent:var(--rust-500);
  --accent-hover:var(--rust-600);
  --accent-press:var(--rust-700);
  --accent-quiet:var(--rust-50);

  --state-success:var(--ivy-500);
  --state-success-soft:var(--ivy-50);
  --state-warning:var(--amber-500);
  --state-warning-soft:var(--amber-50);
  --state-danger:var(--claret-500);
  --state-danger-soft:var(--claret-50);
  --state-info:var(--slate-500);
  --state-info-soft:var(--slate-50);
}

/* Type scale. Display/headings are serif; UI, body, data are sans; code/IDs/metrics mono. */
:root{
  --fs-display-1:44px;
  --fs-display-2:34px;
  --fs-title-1:26px;
  --fs-title-2:21px;
  --fs-title-3:17px;
  --fs-body:14px;
  --fs-body-sm:13px;
  --fs-caption:12px;
  --fs-micro:11px;

  --lh-tight:1.12; /* @kind other */
  --lh-title:1.22; /* @kind other */
  --lh-body:1.55; /* @kind other */
  --lh-loose:1.7; /* @kind other */

  --fw-light:300; /* @kind other */
  --fw-regular:400; /* @kind other */
  --fw-medium:500; /* @kind other */
  --fw-semibold:600; /* @kind other */
  --fw-bold:700; /* @kind other */

  --ls-display:-0.015em; /* @kind other */
  --ls-title:-0.01em; /* @kind other */
  --ls-body:0em; /* @kind other */
  --ls-caps:0.09em; /* @kind other */

  /* Semantic aliases */
  --type-page-title:var(--fw-regular) var(--fs-display-2)/var(--lh-title) var(--font-display); /* @kind font */
  --type-section-title:var(--fw-regular) var(--fs-title-2)/var(--lh-title) var(--font-display); /* @kind font */
  --type-card-title:var(--fw-medium) var(--fs-title-3)/var(--lh-title) var(--font-display); /* @kind font */
  --type-body:var(--fw-regular) var(--fs-body)/var(--lh-body) var(--font-sans); /* @kind font */
  --type-ui:var(--fw-medium) var(--fs-body-sm)/1.35 var(--font-sans); /* @kind font */
  --type-caption:var(--fw-regular) var(--fs-caption)/1.4 var(--font-sans); /* @kind font */
  --type-eyebrow:var(--fw-semibold) var(--fs-micro)/1.2 var(--font-sans); /* @kind font */
  --type-data:var(--fw-regular) var(--fs-body-sm)/1.45 var(--font-mono); /* @kind font */
}

/* Spacing (4px base), radii, and layout constants. */
:root{
  --sp-0:0px;
  --sp-1:4px;
  --sp-2:8px;
  --sp-3:12px;
  --sp-4:16px;
  --sp-5:20px;
  --sp-6:24px;
  --sp-8:32px;
  --sp-10:40px;
  --sp-12:48px;
  --sp-16:64px;
  --sp-20:80px;

  --radius-xs:3px;
  --radius-sm:5px;
  --radius-md:8px;
  --radius-lg:12px;
  --radius-xl:18px;
  --radius-pill:999px;

  --border-width:1px; /* @kind other */
  --border-width-strong:2px; /* @kind other */

  /* Layout */
  --rail-width:236px;
  --rail-width-collapsed:64px;
  --topbar-height:60px;
  --content-max:1200px;
  --gutter:28px;
  --field-height:36px;
  --field-height-lg:42px;
  --control-height-sm:28px;

  /* Semantic aliases */
  --space-card-pad:var(--sp-6);
  --space-card-gap:var(--sp-5);
  --space-section-gap:var(--sp-8);
  --space-field-gap:var(--sp-4);
  --radius-card:var(--radius-lg);
  --radius-control:var(--radius-sm);
}

/* Elevation — soft, warm-tinted, low-contrast. Light UI: shadows are quiet, borders do the work. */
:root{
  --shadow-hairline:0 0 0 1px var(--line-1);
  --shadow-xs:0 1px 1px rgba(23,21,15,.04);
  --shadow-sm:0 1px 2px rgba(23,21,15,.05),0 1px 1px rgba(23,21,15,.03);
  --shadow-md:0 2px 6px rgba(23,21,15,.06),0 1px 2px rgba(23,21,15,.04);
  --shadow-lg:0 10px 28px rgba(23,21,15,.10),0 2px 6px rgba(23,21,15,.05);
  --shadow-xl:0 24px 60px rgba(23,21,15,.16),0 4px 12px rgba(23,21,15,.06);
  --shadow-inset:inset 0 1px 2px rgba(23,21,15,.05);
  --shadow-focus:0 0 0 3px rgba(172,84,38,.20);
  --shadow-focus-danger:0 0 0 3px rgba(163,46,40,.20);

  /* Semantic aliases */
  --elevation-card:var(--shadow-sm);
  --elevation-card-hover:var(--shadow-md);
  --elevation-popover:var(--shadow-lg);
  --elevation-modal:var(--shadow-xl);
  --elevation-field:var(--shadow-inset);

  /* Overlays, veils, protection */
  --veil-modal:rgba(23,21,15,.38);
  --veil-frost:rgba(252,250,247,.72);
  --blur-frost:saturate(140%) blur(10px); /* @kind other */
  --scrim-bottom:linear-gradient(to top,rgba(23,21,15,.55),rgba(23,21,15,0)); /* @kind other */
}

/* Motion — short, calm, no bounce. Admin software should feel instant, not animated. */
:root{
  --dur-instant:80ms; /* @kind other */
  --dur-fast:130ms; /* @kind other */
  --dur-base:190ms; /* @kind other */
  --dur-slow:280ms; /* @kind other */
  --dur-veil:220ms; /* @kind other */

  --ease-standard:cubic-bezier(.2,0,.2,1); /* @kind other */
  --ease-out:cubic-bezier(.16,1,.3,1); /* @kind other */
  --ease-in:cubic-bezier(.4,0,1,1); /* @kind other */

  /* border-color is deliberately NOT transitioned: a custom-property change on an ancestor
     never starts a transition on the dependent property, so a transitioned border-color
     freezes on its previous paint whenever a theme token changes at runtime. Borders do the
     structural work in this system and should switch instantly. */
  --transition-control:background-color var(--dur-fast) var(--ease-standard),color var(--dur-fast) var(--ease-standard),box-shadow var(--dur-fast) var(--ease-standard); /* @kind other */
  --transition-surface:box-shadow var(--dur-base) var(--ease-standard),transform var(--dur-base) var(--ease-standard); /* @kind other */
}

/* Webfonts.
   The attached codebase (wp-rust-engine) is a Rust backend reimplementation and ships NO
   brand fonts of its own. Per the brief ("serif for titles/headings") these are the nearest
   Google Fonts matches and are loaded from the Google Fonts CDN.
   SUBSTITUTION FLAG — see readme.md ("Font substitutions"). Drop real .woff2 files into
   assets/fonts/ and replace these @import lines with local @font-face rules. */

@import url("https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400..900;1,400..700&display=swap");
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,300..700;1,400..600&display=swap");
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&display=swap");

:root{
  --font-display:"Playfair Display",Georgia,"Times New Roman",serif;
  --font-sans:"IBM Plex Sans","Helvetica Neue",Helvetica,sans-serif;
  --font-mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  /* semantic aliases */
  --text-face-title:var(--font-display);
  --text-face-body:var(--font-sans);
  --text-face-code:var(--font-mono);
}

/* Base — minimal element defaults so a bare HTML page inherits the brand voice.
   Components carry their own inline/token styling; this file sets page-level ground truth only. */
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--surface-page);color:var(--text-body);font:var(--type-body);letter-spacing:var(--ls-body);-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
h1,h2,h3,h4,h5{font-family:var(--font-display);color:var(--text-title);font-weight:var(--fw-regular);letter-spacing:var(--ls-title);margin:0 0 var(--sp-3)}
h1{font-size:var(--fs-display-2);line-height:var(--lh-title)}
h2{font-size:var(--fs-title-1);line-height:var(--lh-title)}
h3{font-size:var(--fs-title-2);line-height:var(--lh-title)}
h4{font-size:var(--fs-title-3);font-weight:var(--fw-medium)}
p{margin:0 0 var(--sp-4);text-wrap:pretty}
/* align-self keeps the token underline hugging the text when an anchor is a flex/grid item
   (flex items are blockified, which would otherwise stretch the rule across the whole cell) */
a{color:var(--text-link);text-decoration:none;border-bottom:1px solid rgba(143,67,32,.28);transition:var(--transition-control);align-self:flex-start;width:fit-content}
a:hover{color:var(--text-link-hover);border-bottom-color:var(--rust-400)}
a:focus-visible{outline:none;box-shadow:var(--shadow-focus);border-radius:var(--radius-xs)}
code,kbd,pre,samp{font-family:var(--font-mono);font-size:.92em}
hr{border:none;border-top:1px solid var(--border-subtle);margin:var(--sp-6) 0}
small{font-size:var(--fs-caption);color:var(--text-muted)}
::selection{background:var(--rust-100);color:var(--ink-1)}
:focus-visible{outline:none;box-shadow:var(--shadow-focus)}
table{border-collapse:collapse}
input,select,textarea,button{font-family:inherit;font-size:inherit}
*,*::before,*::after{box-sizing:border-box}

/* Aquaria theme — token OVERRIDES only, per architecture/03-template-rendering.md
   ("The token pipeline"): the engine serves Ferro's base tokens/*.css
   (colors.css, typography.css, spacing.css, elevation.css, motion.css,
   fonts.css, base.css) unmodified, then concatenates this file after it, so
   every declaration below either *redefines* an existing --token already
   shipped in the base set, or introduces a new --aq-* name for a concept
   the base set has no vocabulary for. No component markup in templates/
   ever hardcodes a color or size — everything routes through a name
   declared here or in the base tokens. Every raw hex value in this file is
   the right-hand side of a --token: value; declaration, which is the one
   place crates/render/src/conformance.rs's linter allows one; raw px is
   allowed here (and only here) because this file is where the scale is
   authored, not consumed.

   Source: ui_kits/shop_bath/README.md ("Register: what makes it not Volt",
   "Tweaks") and ui_kits/_shared/ShopTheme.jsx (shopThemeVars()), evaluated
   at Aquaria's own documented DEFAULT tweak state — README's "Defaults
   here: teal palette, white surface, hairline borders, serif headings,
   1280px", plus AQ_TWEAK_DEFAULTS in ui_kits/shop_bath/AqApp.jsx (cards
   "bordered", darkBlocks "palette", corners "soft", grid 4-up wide plates,
   prices sans, gallery rail, collection lead image, header split, hero
   banner). This file is the static, shipped equivalent of that one
   resolved state; ShopThemeTweaks (the live editor panel itself) has no
   server-side equivalent and isn't reproduced, same as
   themes/storefront/tokens.css and themes/volt/tokens.css don't reproduce
   it either.

   Where a mixed value was needed (accent hover/press, the hairline border
   ramp), it is computed with the same linear-light mixHex() the mockup
   uses and emitted here as a concrete hex, for the same reason
   ShopTheme.jsx gives: a CSS color-mix() value cannot be interpolated, so
   a transitioned border-color resolving to one freezes mid-transition. */
:root {
  /* Island control theming. Every one of these has a generic default
     baked into the island; leaving it undefined is what made the
     checkout form render at UA sizes inside a ported theme. */
  --island-fs-body: var(--aq-fs-body-lg);
  --island-fs-label: var(--aq-fs-ui);
  --island-fs-item: var(--aq-fs-card-head);
  --island-fs-meta: var(--aq-fs-line-meta);
  --island-fs-qty: var(--aq-fs-body-lg);
  --island-fs-input: var(--aq-fs-body-lg);
  --island-fs-input-lg: var(--aq-fs-body-lg);
  --island-fs-price: var(--aq-fs-card-head);
  --island-fs-line-total: var(--aq-fs-card-head);
  --island-fs-subtotal: var(--aq-fs-body-lg);
  --island-fs-total: var(--aq-fs-price);
  --island-fw-button: var(--fw-semibold);
  --island-fw-cart-total: var(--aq-fw-price);
  --island-btn-h: var(--aq-btn-h-lg);
  --island-btn-h-sm: var(--aq-cart-field-h);
  --island-btn-radius: var(--radius-sm);
  --island-field-h: var(--aq-cart-field-h);
  --island-field-pad: 0 var(--sp-4);
  --island-field-border: var(--border-default);
  --aq-fw-name: 550; /* AqCart line-item product name */
  /* Basket and checkout, from ui_kits/shop_bath/AqCart.jsx. The
     storefront standalone has no basket screen, so the kit is the
     authority for these; names follow the property family they
     belong to, never the bare value. */
  --aq-sp-7: 7px; /* gap inside a cart line's inline link pair */
  --aq-sp-9: 9px; /* gap between a line item's stacked meta rows */
  --aq-cart-rail-w: 380px; /* order-summary rail, the kit's fixed second column */
  --aq-cart-plate: 112px; /* line-item thumbnail plate */
  --aq-cart-qty-w: 34px; /* stepper +/- button width */
  --aq-cart-qty-h: 38px; /* stepper +/- button height */
  --aq-cart-qty-val: 30px; /* stepper value column */
  --aq-cart-field-h: 44px; /* promo-code field */
  --aq-fs-summary-title: 21px; /* "Order summary" heading */
  --aq-fs-total-label: 18px; /* "Total, incl. VAT" label */
  --aq-fs-line-meta: 15px; /* line-item article/finish meta and the instalment line */
  --aq-size-34: var(--aq-menu-swatch);
  --aq-size-44: var(--aq-menu-row-h);
  --aq-size-460: var(--aq-menu-max-h);
  --aq-sp-44: 44px;
  /* Catalogue mega-menu — the panel the Catalogue button opens. */
  --aq-menu-col-min: 240px;   /* category column, lower bound */
  --aq-menu-col-max: 300px;   /* category column, upper bound */
  --aq-menu-row-h: 44px;      /* category row */
  --aq-menu-swatch: 34px;     /* collection swatch */
  --aq-menu-max-h: 460px;     /* panel scroll height */
  --aq-currency-menu-w: 150px; /* currency disclosure panel, topbar */
  /* Sizes the standalone template uses that neither the design system
     nor this theme had a name for. Value-derived names, grouped by the
     property family they belong to, so a spacing step can never be
     retargeted by a change to the type scale. */
  --aq-x-15_95: 15.95px;
  --aq-x-17_4: 17.4px;
  --aq-x-18_85: 18.85px;
  --aq-x-20_3: 20.3px;
  --aq-x-21_025: 21.025px;
  --aq-x-21_75: 21.75px;
  /* Sizes the standalone template uses that neither the design system
     nor this theme had a name for. Value-derived names, grouped by the
     property family they belong to, so a spacing step can never be
     retargeted by a change to the type scale. */
  --aq-r-11: 11px;
  --aq-size-178: 178px;
  --aq-size-17: 17px;
  --aq-size-1: 1px;
  --aq-size-21: 21px;
  --aq-size-22: 22px;
  --aq-size-26: 26px;
  --aq-size-27: 27px;
  --aq-size-52: 52px;
  --aq-size-620: 620px;
  --aq-size-6: 6px;
  --aq-sp-11: 11px;
  --aq-sp-13: 13px;
  --aq-sp-14: 14px;
  --aq-sp-1: 1px;
  --aq-sp-22: 22px;
  --aq-sp-26: 26px;
  --aq-sp-2: 2px;
  --aq-sp-3: 3px;
  --aq-sp-5: 5px;
  --aq-x-3: 3px;
  --aq-frame-pad: clamp(16px, 2.4vw, 32px);            /* reference frame inset */
  --aq-inset-hairline: 0 0 0 var(--border-width) rgba(0, 0, 0, 0.18) inset;
  --aq-media-max: 440px;      /* hero media plate max width */
  --aq-copy-max: 520px;       /* hero copy column max width */
  --aq-card-basis: 150px;     /* product-card flex basis in the reference grids */
  --aq-showroom-min-h: 300px; /* showroom media min height */
  --aq-footer-col-max: 340px; /* footer column max width */

  /* Sizes the standalone template uses that this design system has no name
     for. Named rather than inlined because the conformance gate only permits
     px in a template behind var(--…) — the pixel values are the reference's,
     unchanged. */
  --aq-topbar-pad-y: 6px;     /* utility bar vertical padding */
  --aq-icon-inline: 18px;     /* inline icon beside utility-bar text */
  --aq-icon-inline-pad: 7px;  /* its optical inset */
  --aq-dot: 9px;              /* live-chat status dot */
  --aq-catbar-pad: 10px;      /* category-bar link padding */
  --aq-icon-sm: 23px;         /* small action icon */
  --aq-search-min: 240px;     /* search field min width */
  --aq-search-basis: 280px;   /* search field flex basis */

  /* Compatibility aliases for the standalone template.
     The reference markup is lifted verbatim from "Aquaria Storefront
     (standalone)", and that export carries a handful of token names from the
     storefront/volt namespaces — they are defined on its app-root div, not at
     :root, which is why they look undefined at first glance. Every one of them
     resolves to a value this design system already has a name for, so they are
     aliases rather than new colours: the theme stays themeable and no literal
     is introduced. */
  --sf-accent-fg: var(--accent);
  --sf-head-weight: var(--fw-bold);
  --sf-max: var(--content-max);
  --sf-r-img: var(--radius-md);
  --sf-rhythm: 1;
  --vl-border: var(--line-2);
  --vl-border-w: var(--border-width);
  --vl-card-bg: var(--paper-0);
  --vl-card-border: var(--line-2);
  --vl-dark-muted: var(--aq-dark-muted);
  --vl-sale: var(--aq-sale);

  /* Section-level roles read off the standalone. These used to share
     --aq-fs-body-lg (17.5), which is a fourth distinct size in that file. */
  --aq-fs-section-lede: 18px;   /* lede under a section heading */
  --aq-fs-card-desc: 17px;      /* collection-card description */
  --aq-fs-card-head: 19px;      /* advice-card title */
  --aq-fs-panel-title: 27.5px;  /* SEO panel heading */

  --aq-fw-tile: 550;          /* catalogue tile name — the standalone sits between 500 and 600 */
  --aq-cat-icon: 27px;        /* catalogue tile icon */
  --aq-cat-tile-min-h: 158px; /* catalogue tile height in the standalone */

  /* Measured off "Aquaria Storefront (standalone)", which is the authority for
     this theme. The hero there is a LIGHT band, not the dark plate this theme
     was carrying: cool-1 ground, cool-8 type, and a media plate on cool-2 with
     a deep soft shadow. */
  --aq-fs-hero-lede: 20px;        /* hero lede — the post lede is 19.5, a different role */
  --aq-fs-stat-label: 15px;       /* mono label under a hero stat */
  --aq-hero-plate-shadow: 0 30px 70px rgba(0, 0, 0, 0.28);

  --aq-fs-quote: 25px;  /* pull-quote body — the kit's largest 400-weight sans is 25, not 27.5 */
  /* The footer was the last inverted band in this theme: near-black pine with
     near-white text, where the kit's footer is a light cool grey with dark
     text. The kit uses no dark band of this kind on any screen — its only
     large dark fills are an image scrim and the teal hero on the index. The
     dark tokens stay defined because home.html and blocks.html still use them
     for that teal band. */
  --aq-footer-bg: var(--cool-1);
  --aq-footer-fg: var(--cool-8);
  --aq-footer-muted: var(--cool-6);
  --aq-footer-line: var(--line-2);
  --island-fs-cta: 13.5px;  /* kit's bold small step is 13.5, not 13 */

  --aq-fs-spec-mono: 15.5px;  /* product spec/technical line, mono — kit 15.5/400 */
  --aq-fs-promise: 18px;      /* delivery/returns row heading — kit 18/600 */
  --aq-fs-label: 14.5px;      /* small bold label (chips, buttons) — kit 14.5/600 */
  --aq-fs-eyebrow-mono: 14.5px; /* mono section eyebrow — kit 14.5/400 */
  --aq-fs-featured-title: clamp(28px, 2.75vw, 40px);  /* blog featured post — kit 39.6 */
  --aq-fs-card-title: 20px;  /* advice/blog card title — kit 20/600, not 21 */
  --aq-fs-post-title: clamp(34px, 4vw, 55px);      /* article title — kit 55 */
  --aq-fs-checkout-title: clamp(30px, 2.95vw, 42px); /* checkout title — kit 42 */

  --island-fs-section: 21px;   /* kit checkout section heading */
  --island-fw-section: 650;

  /* The mini-basket is a React island shared by every theme; before these it
     sized itself with bare numbers and looked the same under all four. */
  /* The reference product card is a single outlined add button, not a
     filled pill beside a quantity stepper. */
  --island-add-bg: transparent;
  --island-add-fg: var(--accent);
  --island-add-border: var(--border-width) solid var(--accent);
  --island-add-radius: var(--radius-sm);
  --island-add-h: var(--aq-btn-h-md);
  --island-add-flex: 1 1 auto;
  --island-cart-h: var(--aq-control-h);   /* the reference's header controls are all 58 */
  --island-cart-radius: var(--radius-sm); /* and radius 5, matching its sibling tiles */
  --island-fs-cart-total: 17px;
  --island-ff-cart-total: var(--font-sans);
  --island-fs-title: var(--aq-fs-stat);      /* "Your cart is empty" — kit 22 */

  /* Sizes read off the kit's own listing screen, role by role. Several of
     these used to share --aq-fs-meta (14.5) or --aq-fs-body-lg (17.5), which
     made one token answer for four different roles at four different kit
     sizes. */
  --aq-fs-tile-label: 17px;     /* sub-category tile name — kit 17/600 */
  --aq-fs-count: 15px;          /* "N sub-categories · N products" — kit 15 mono */
  --aq-fs-logo-footer: 32px;    /* the footer wordmark is 2px smaller than the header's */
  --aq-fs-footer-link: 16px;    /* footer column links — kit 16/400 */
  --aq-fs-eyebrow: var(--fs-micro);       /* 11 — header eyebrow */
  --aq-fs-footer-head: var(--fs-body-sm); /* 13 — footer column headings */
  --aq-fs-footer-legal: var(--fs-body);   /* 14 — VAT + copyright line */
  --aq-fs-contact: 15px;                  /* footer email; 15.5 is a different tier */
  --rating-star-size: 20px;  /* review-form island; a step this kit actually uses */
  /* The kit's smallest MONO meta tier is 10px (SKUs, article codes,
     small labels), which is below the design system's scale — that
     bottoms out at --fs-micro: 11px. Using micro made every one of
     those lines a pixel large against the reference. */
  /* ---- Aquaria's wide plate measure ---------------------------------------
     README Tweaks table "Content width", Aquaria default 1280. Overrides
     the base 1200px the same way themes/storefront/tokens.css overrides it
     to 1180px and themes/volt/tokens.css to 1320px for their registers. */
  --content-max: 1280px;

  /* ---- Surface: "white" (cool neutrals) — Aquaria's default --------------
     ShopTheme.jsx's SHOP_SURFACES.white ramp, reproduced through the
     shared --cool-* family tokens/colors.css already ships "ONLY [for] the
     site template's 'white' and 'dark' surface variants", so no new hex is
     needed here — only var() reassignment. Every --border-*/--surface-*/
     --text-* semantic alias in the base tokens already resolves through
     var(--paper-*)/var(--ink-*)/var(--line-*), so redefining these ramps
     repaints the whole theme. Calm ceramic white is the point of the
     register: sanitaryware photographed on warm cream reads dirty. */
  --paper-0: var(--cool-0);
  --paper-1: var(--cool-0);
  --paper-2: var(--cool-1);
  --paper-3: var(--cool-2);
  --paper-4: var(--cool-3);
  --ink-1: var(--cool-8);
  --ink-2: var(--cool-7);
  --ink-3: var(--cool-6);
  --ink-4: var(--cool-5);
  --ink-5: var(--cool-4);
  --surface-rail: var(--cool-8);
  --surface-rail-hover: var(--paper-4);
  --veil-frost: rgba(255, 255, 255, 0.78);

  /* ---- Hairline borders ---------------------------------------------------
     shopThemeVars()'s mixLine(): the default border swatch (SHOP_BORDERS[2],
     == --cool-4) mixed toward the white surface's --paper-1 at "hairline"
     border-weight's 40/62/84% steps. None of the three lands on an existing
     cool stop, so each gets its own declaration. Thin edges are the
     register: "wide plates, thin edges". */
  --line-1: #ECEFF2;
  --line-2: #E1E5EA;
  --line-3: #D4DBE2;

  /* ---- Teal palette -------------------------------------------------------
     SHOP_PALETTES[4] — teal (accent) · pine (deep, the dark blocks) ·
     ochre (sale) · pale teal (tint/on-dark). The base token set has no
     teal family at all, so these five are the theme's only genuinely new
     colour declarations; every consumer below routes through them. */
  --aq-teal-500: #1F6E6A;
  --aq-teal-600: #1D6561;
  --aq-teal-700: #1B5A57;
  --aq-teal-50: #F2F4F4;
  --aq-teal-100: #C2D8D5;
  --aq-pine: #12211F;
  --aq-ochre: #B0641C;

  /* The base set's semantic aliases resolved against the rust family on
     :root in tokens/colors.css, so repointing --accent alone would leave
     every --rust-* consumer on the un-themed warm literals; the whole
     family is redirected, exactly as shopThemeVars() does. */
  --accent: var(--aq-teal-500);
  --accent-hover: var(--aq-teal-600);
  --accent-press: var(--aq-teal-700);
  --accent-quiet: var(--aq-teal-50);
  --rust-50: var(--aq-teal-50);
  --rust-100: var(--aq-teal-100);
  --rust-200: var(--aq-teal-100);
  --rust-500: var(--aq-teal-500);
  --rust-600: var(--aq-teal-600);
  --rust-700: var(--aq-teal-700);
  --text-link: var(--aq-teal-600);
  --text-link-hover: var(--aq-teal-700);
  --border-focus: var(--aq-teal-500);
  --surface-accent-soft: var(--aq-teal-50);
  --shadow-focus: 0 0 0 3px rgba(31, 110, 106, 0.3);

  /* ---- Corners: "soft" ----------------------------------------------------
     SHOP_RADII.soft. Overrides every step of the shared radius scale, the
     same way themes/storefront/tokens.css flattens all of them to 0 for
     its own square register. --aq-r-img is the plate corner, independently
     addressable from the control radius (the same "value raw tokens can't
     express" --sf-r-img covers for Storefront). */
  --radius-xs: 3px;
  --radius-sm: 5px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 18px;
  --radius-pill: 999px;
  --aq-r-img: 8px;

  /* ---- Aquaria semantics --------------------------------------------------
     The --aq-* names the README's tweak table documents, resolved at the
     default state noted at the top of this file. */

  /* Sale/discount colour: "auto" -> the palette's own third slot (ochre).
     Deliberately NOT red: this is a dealer catalogue where a discount is
     secondary information, not the spine (README: "Prices | mono,
     strikethrough-first [Volt] | sans 650, discount is secondary"). */
  --aq-sale: var(--aq-ochre);

  /* Chrome: "ink" -> the surface's solid button fill (search submit,
     catalogue button fallback, selected chips). */
  --aq-chrome-bg: var(--cool-8);
  --aq-chrome-fg: #FFFFFF;

  /* Utility strip — a quiet tinted band, not a dark one (AqHeader renders
     it on --paper-2 with --ink-3 text). */
  --aq-strip-bg: var(--paper-2);
  --aq-strip-fg: var(--ink-3);

  /* Dark blocks: "palette" -> the palette's deep pine. Used by the home
     hero banner, the collection full-bleed lead and the footer. The
     on-dark foreground is a fixed warm off-white regardless of surface
     (shopThemeVars() hardcodes that literal), and the muted step is tinted
     toward the pine rather than reusing the warm --text-on-rail-muted,
     which reads brown on a green-black ground. */
  --aq-dark-bg: var(--aq-pine);
  --aq-dark-fg: #FCFAF7;
  --aq-dark-muted: #9A9384; /* ShopTheme.jsx --vl-dark-muted, default darkBlocks */
  --aq-dark-line: rgba(255, 255, 255, 0.22);
  --aq-dark-plate: var(--cool-2); /* media plate on the hero band; the kit uses cool-2 here */

  /* An "ink" button fill that must invert on a dark surface — the same
     --sf-btn-* semantic themes/storefront/tokens.css documents. */
  --aq-btn-bg: var(--ink-1);
  --aq-btn-fg: var(--paper-0);

  /* Cards: "bordered" — AqCard's framed plate sits in a bordered card with
     a lift on hover. */
  --aq-card-bg: var(--paper-0);
  --aq-card-border: var(--line-2);
  --aq-card-shadow: none;
  --aq-card-shadow-hover: 0 16px 36px rgba(15, 18, 22, 0.13); /* AqParts.jsx AqCard hover */
  --aq-border-w: 1px;

  /* ---- Placeholder plate texture -----------------------------------------
     AqPlate's tonal hatch, the dark blocks' stripe overlay and the
     technical-drawing shot's graph paper. Each is a gradient carrying raw
     px stops that a template's style attribute is not allowed to contain,
     so each gets a token here — the same rationale as the structural group
     below. */
  --aq-plate-hatch: repeating-linear-gradient(135deg, rgba(0, 0, 0, 0.027) 0, rgba(0, 0, 0, 0.027) 1px, transparent 1px, transparent 9px);
  --aq-band-hatch: repeating-linear-gradient(135deg, rgba(0, 0, 0, 0.027) 0, rgba(0, 0, 0, 0.027) 1px, transparent 1px, transparent 12px);
  --aq-stripe-dark: repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.045) 0 1px, transparent 1px 12px);
  --aq-drawing-grid: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.05) 0 1px, transparent 1px 24px), repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.05) 0 1px, transparent 1px 24px);

  /* ---- Structural measurements --------------------------------------------
     Recur across templates/partials with no equivalent step in
     tokens/spacing.css — same rationale as themes/storefront/tokens.css's
     --sf-* group and themes/volt/tokens.css's --vl-* group. Sizes that DO
     already land on an existing step reuse that token directly in
     templates instead of being duplicated here. */
  --aq-header-h: 76px; /* AqHeader main row, desktop */
  --aq-header-h-mobile: 60px; /* AqHeader main row, mobile */
  --aq-strip-h: 52px; /* Utility strip min-height */
  --aq-catbar-h: 54px; /* Category bar row — measured off the standalone */
  --aq-hit-min: 44px; /* WCAG touch-target minimum on icon-only controls */
  --aq-control-h: 58px; /* Header search / catalogue / square icon buttons */
  --aq-btn-h-sm: 40px; /* AqBtn size="sm" */
  --aq-btn-h-md: 48px; /* AqBtn size="md" (default) */
  --aq-btn-h-lg: 56px; /* AqBtn size="lg" */
  --aq-qty-h: 50px; /* Buy-box quantity stepper */
  --aq-sticky-top: 16px; /* Pinned-rail offset — the reference pins its order summary at sp-4 from the viewport top (AqSummary: sticky top 16); the old 96px cleared a sticky header this theme does not have and read as a dead band above every pinned block. */
  --aq-buybox-w: 400px; /* Product buy-box column, desktop */
  --aq-filter-w: 288px; /* the reference listing's filter rail */ /* Listing facet rail, desktop */
  --aq-minibag-w: 380px; /* Header mini-basket dropdown */
  --aq-thumb: 76px; /* Product gallery thumbnail column, desktop */
  --aq-thumb-mobile: 72px; /* Product gallery thumbnail, mobile strip */
  --aq-drawer-w: 330px; /* Mobile catalogue drawer */
  --aq-touch-min: 44px;      /* comfortable tap target, drawer rows and icon buttons */
  --aq-hero-min-h: 420px; /* Home hero banner */
  --aq-tile-min-h: 118px; /* Catalogue tile */
  --aq-promo-min-h: 178px; /* Promo row tile */
  --aq-footer-col-min: 180px; /* Footer column grid minmax() floor */
  --aq-edge-pad: clamp(21px, 3vw, 42px); /* AqFrame side padding */
  --aq-block-pad: clamp(42px, 5.75vw, 116px); /* Full-bleed dark block padding */
  --aq-measure-lede: 46rem; /* Lede / section-sub max width */
  --aq-measure-prose: 62rem; /* Page & post body max width */

  /* ---- Aquaria display type ------------------------------------------------
     The kit's README says "serif headings" for Aquaria, and I followed that,
     leaving --font-display on the base set's Playfair. The RENDERED reference
     screens disagree: every heading in them — the "Aquaria" wordmark, the
     collection H1 ("Onda: cast stone in one block"), the listing H1 ("Showers
     & enclosures") — is a heavy grotesque SANS, not Playfair. ShopTheme.jsx
     only reaches for Playfair when headingFont === "serif", so the reference
     renders were produced with the sans setting.
     The renders are the artefact being matched, so they win over the prose.
     --font-display therefore routes to the sans stack; a site that wants
     serif headings can still set it as a theme tweak, which is the layer
     that choice belongs in.
     These
     are the sizes AqParts/AqChrome/AqHome/AqCollection/AqProduct use that
     have no matching step in tokens/typography.css (whose scale tops out
     at 44px); sizes that DO land on an existing step (21px == --fs-title-2,
     26px == --fs-title-1) reuse that token directly in templates. */
  --font-display: var(--font-sans);
  /* ---- AqListing chrome scale (AqListing.jsx literals) ---------------------
     The facet rail and sort bar were routed through --fs-body (14px) and
     --fs-body-sm (13px). The kit uses 16.5 for every interactive label
     (sort chips, "N of M shown", "Reset all", checkbox labels), 17 for a
     facet block title and 19.5 for the "Filters" heading. Same failure as
     the card: nothing individually obvious, the whole rail under-scaled. */
  --aq-fs-ui: 16.5px;            /* sort chips, facet labels, links */
  --aq-fs-facet-title: 17px;     /* facet block heading */
  --aq-fs-filters-title: 19.5px; /* "Filters" */
  --aq-fs-meta: 14.5px;          /* counts and small meta */
  --aq-fs-body-sm: 15.5px;       /* secondary body + chrome (AqChrome/AqProduct) */
  --aq-fs-btn: 13.5px;           /* AqBtn lg/md label */
  --aq-fs-btn-sm: 12px;          /* AqBtn sm label */
  --aq-checkbox-size: 18px;      /* AqFacets Checkbox control */

  /* ---- AqCard's own scale (AqParts.jsx literals) ----------------------------
     The card was routed through the DESIGN SYSTEM's body scale
     (--fs-body 14px / --fs-body-sm 13px) and the --sp-* spacing steps. The kit
     does not use that scale here: its card literals are 18.5 / 15 / 14.5 for
     type and 18 / 14 / 14 / 12 for padding and gaps. Every card was therefore
     a few px small in every dimension at once, which is what "all the sizes
     are wrong" looks like — no single value obviously off, the whole tile
     quietly under-scaled. */
  --aq-fs-card-name: 18.5px;   /* product name */
  --aq-fs-card-body: 15px;     /* stock, collection, lead time */
  --aq-fs-card-meta: 14.5px;   /* article code, small meta */
  --aq-card-pad: 18px;         /* card padding */
  --aq-card-img-pad: 14px;     /* image well padding */
  --aq-card-gap: 14px;         /* card column gap */
  --aq-card-gap-sm: 12px;      /* inner stack gap */
  --aq-fs-logo: 34px; /* Header + footer wordmark, desktop */
  --aq-fs-logo-mobile: 26px; /* Header wordmark, mobile */
  --aq-fs-hero: clamp(40px, 5vw, 71px); /* Home hero H1 */
  --aq-fs-page-title: clamp(34px, 3.75vw, 53px);
  /* Cart and product run a step smaller than blog/page in the kit
     (shop_bath cart.html and product.html are 45px, blog.html and
     info.html are 53px), so the basket cannot share the page token. */
  --aq-fs-cart-title: clamp(32px, 3.25vw, 45px); /* Page / blog / cart H1 */
  --aq-fs-collection-title: clamp(42px, 5vw, 74px); /* Collection lead H1 */
  --aq-fs-product-title: clamp(30px, 3.13vw, 45px); /* Product H1 */
  --aq-fs-section-title: clamp(28px, 2.63vw, 40px); /* AqSectionHead */
  --aq-fs-listing-title: clamp(32px, 3.25vw, 48px); /* AqListing.jsx's category h1 */
  --aq-tile-min: 168px; /* AqListing.jsx's sub-category tile min track */
  --aq-cat-tile-h: 118px; /* AqHome.jsx catalogue tile min-height */
  --aq-measure-listing-head: 620px; /* AqListing.jsx header copy maxWidth */
  --aq-fs-block-title: 28.5px; /* Promo tile / SEO panel heading */
  --aq-fs-tile-name: 18.5px; /* AqCard product name */
  --aq-fs-price-lg: 40px; /* Buy-box price */
  --aq-fs-price: 28px; /* Card price */
  --aq-fs-price-sm: 21px; /* Basket-line price */
  --aq-fs-lede: 19.5px; /* Hero / collection lede */
  --aq-fs-body-lg: 17.5px; /* Aquaria's roomier body step */
  --aq-fs-stat: 22px; /* Hero / collection stat figure */
  --aq-fs-review-score: 40px; /* summary score — 52 is off this kit's scale; 40/650 is its largest */ /* Reviews summary score */

  /* Prices are set in sans at 650 — the one weight the shared --fw-* scale
     has no step for, and the single most distinctive type decision in the
     kit (README: "Prices | sans 650"). */
  --aq-fw-price: 650;
  --aq-fw-title: 600; /* AqCard / advice-tile titles */
  --aq-ls-label: 0.12em; /* AqLabel */
  --aq-ls-eyebrow: 0.14em; /* AqSectionHead eyebrow, footer column heads */
  --aq-ls-wordmark: 0.18em; /* Wordmark sub-line */
}

/* Any inline or class-level display: value silently outranks the UA
   stylesheet's [hidden] { display: none } (author rules beat UA rules) —
   the mobile drawer nav in themes/storefront/templates/partials/header.html
   shipped exactly this bug, rendering permanently open. One global guard
   ends the class of landmine: the hidden attribute always wins; JS that
   opens something must remove the attribute (which the theme JS already
   does). */
[hidden] { display: none !important; }

/* ————————————————————————————————————————————————————————————————————————
   Self-hosted webfonts — the reference standalone embeds these exact IBM
   Plex woff2 files (same subsets, same unicode-ranges); fonts.css's Google
   Fonts @import cannot take effect here because theme.css concatenates it
   mid-file, where CSS requires @import rules to be ignored. The files ship
   in themes/aquaria/assets/fonts/ and are served by the server's
   /assets/fonts/{file} route (apps/server/src/main.rs), so the relative
   url("fonts/…") below resolves against this stylesheet's own
   /assets/theme.css URL. Playfair Display is deliberately absent: this
   theme's --font-display routes to the sans stack (see above), so the
   serif face never renders and would be dead weight on every page load.
   Raw values throughout are fine here for the same reason the hex ramps
   above are: tokens.css is where values are AUTHORED.
   ———————————————————————————————————————————————————————————————————————— */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: italic;
  font-weight: 400 600;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-italic-400_600-cyr-ext.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: italic;
  font-weight: 400 600;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-italic-400_600-cyr.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: italic;
  font-weight: 400 600;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-italic-400_600-greek.woff2") format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: italic;
  font-weight: 400 600;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-italic-400_600-viet.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: italic;
  font-weight: 400 600;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-italic-400_600-latin-ext.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: italic;
  font-weight: 400 600;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-italic-400_600-latin.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 300 700;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-normal-300_700-cyr-ext.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 300 700;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-normal-300_700-cyr.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 300 700;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-normal-300_700-greek.woff2") format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 300 700;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-normal-300_700-viet.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 300 700;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-normal-300_700-latin-ext.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 300 700;
  font-stretch: 100%;
  font-display: swap;
  src: url("fonts/IBMPlexSans-normal-300_700-latin.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-400-cyr-ext.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-400-cyr.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-400-viet.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-400-latin-ext.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-400-latin.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-500-cyr-ext.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-500-cyr.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-500-viet.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-500-latin-ext.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-500-latin.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-600-cyr-ext.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-600-cyr.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-600-viet.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-600-latin-ext.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("fonts/IBMPlexMono-normal-600-latin.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ————————————————————————————————————————————————————————————————————————
   React-island styling hooks. The shared islands
   (frontend/src/islands/checkout.tsx, cart.tsx) style every control
   through `--island-*` custom properties whose fallbacks reproduce the
   old generic look — a theme that defines nothing changes nothing. These
   values give the islands this theme's exact form metrics, straight from
   the reference checkout's rendered DOM (panel: paper-0 card, hairline
   --vl-border, --radius-md, --sp-5 padding; heading: sans 650 at 21px;
   label: 13px medium with a danger asterisk; input: --field-height with
   --sp-3 side padding and the inset field shadow; the quoted delivery
   rate presented as the kit's selected-method row).
   ———————————————————————————————————————————————————————————————————————— */
:root {
  --island-panel-bg: var(--paper-0);
  --island-panel-border: var(--vl-border-w) solid var(--vl-border);
  --island-panel-radius: var(--radius-md);
  --island-panel-pad: var(--sp-5);
  --island-panel-gap: var(--sp-4);
  --island-panel-stack-gap: var(--sp-5);
  --island-panel-head-gap: 0px;
  --island-fs-section: 21px;
  --island-fw-section: 650;
  --island-fs-label: var(--fs-body);
  --island-fw-label: var(--fw-medium);
  --island-label-color: var(--ink-1);
  --island-required-color: var(--state-danger);
  --island-field-h: 56px;         /* review note 2026-08-21: "much bigger just like in google" — Google-form scale, not the DS 36px */
  --island-field-pad: 0 var(--sp-4);
  --island-field-border: var(--border-default);
  --island-fs-input: 17px;
  --island-fs-hint: var(--fs-body-sm);
  --island-rate-bg: var(--accent-quiet);
  --island-rate-border: var(--border-width) solid var(--accent);
  --island-rate-pad: var(--sp-4);
  --island-btn-h: 56px;
  --island-btn-h-sm: 48px;
  --island-btn-radius: var(--radius-sm);
  --island-fs-cta: 13.5px;
  --island-fw-button: var(--fw-semibold);
}

/* Info-page (page.html) additions — reference AqInfo values. */
:root {
  --aq-info-rail-w: 232px;    /* info-page topic rail column (ref grid 232px 1fr) */
  --aq-measure-info: 720px;   /* info article text measure (ref max-width 720px) */
  --aq-fs-info-body: 19px;    /* info body paragraph — kit text block 19/1.75 */
  --aq-fs-info-head: 26px;    /* info block head (editor h2) — kit 26/700 */
  --aq-sp-6: 6px;             /* narrow topic-rail chip gap (kit isNarrow gap 6) */
  --aq-sp-10: 10px;           /* narrow topic-rail chip side padding (kit 8px 10px) */
}

/* Basket (cart.html) additions — reference AqCart values. */
:root {
  --aq-notice-info-border: #C3D5E1;  /* DS Notice info-tone border — free-delivery notice frame */
  --aq-size-16: 16px;                /* Notice info icon wrapper (DS Icon size 16) */
  --aq-cart-promo-basis: 200px;      /* promo-code input flex-basis — ref "flex: 1 1 200px" */
  --aq-cart-plate-sm: 88px;          /* narrow line-row plate column (kit isNarrow) */
}

/* Blog / article (blog_index.html, post.html) additions — reference AqBlog/AqArticle values. */
:root {
  --aq-measure-blog-head: 700px;   /* blog intro copy max-width (kit 700) */
  --aq-fs-featured-lede: 19px;     /* featured-post standfirst (kit 19/1.65) */
  --aq-article-rail-w: 280px;      /* article rail column (kit 280) */
  --aq-measure-article: 760px;     /* article column max-width (kit 760) */
  --aq-fs-article-lede: 21.5px;    /* article standfirst (kit 21.5/1.65) */
}

/* Listing (collection.html) additions — DS control boxes the reference uses. */
:root {
  --aq-size-36: 36px;  /* price min/max field height (AqFacets input) */
  --aq-size-28: 28px;  /* DS IconButton sm box — pagination arrows */
  --aq-size-15: 15px;  /* DS Icon size-15 wrapper — pagination chevrons, chip x */
  --aq-size-62: 62px;  /* DS Pagination counter min-width */
  /* Export-name aliases: the standalone emits --vl-chrome-* from
     shopThemeVars; this theme authored the same values as --aq-chrome-*. */
  --vl-chrome-bg: var(--aq-chrome-bg);
  --vl-chrome-fg: var(--aq-chrome-fg);
}

/* Product page (product.html) additions — reference AqProduct values. */
:root {
  --aq-fs-price-was: 25px;            /* buy-box struck was-price (AqPrice lg 40 × 0.62) */
  --aq-fs-qty: 18px;                  /* qty stepper value, mono */
  --aq-qty-btn-w: 38px;               /* stepper +/- hit width */
  --aq-size-20: 20px;                 /* download icon in Downloads rows */
  --aq-size-12: 12px;                 /* review-row star (AqStars default) */
  --aq-measure-product-title: 780px;  /* product h1 maxWidth (ref 780) */
  --aq-spec-label-min: 120px;         /* AqSpecRows label column minmax floor */
}

/* Header interactivity (mega / quick search / mini basket) — reference values. */
:root {
  --aq-mega-shadow: 0 30px 60px rgba(15,18,22,.18);      /* AqMega panel */
  --aq-suggest-shadow: 0 22px 48px rgba(15,18,22,.18);   /* AqSearch dropdown */
  --aq-minibasket-shadow: 0 26px 56px rgba(15,18,22,.2); /* AqMiniBasket */
  --aq-minibasket-w: 440px;
  --aq-size-46: 46px;  /* search-suggestion plate */
  --aq-size-60: 60px;  /* mini-basket line plate */
  --aq-size-34: 34px;  /* mega collections-column plate (AqMega 34x34) */
  --aq-toast-w: 300px; /* DS Toast min width */
}

/* Quick-search dropdown + mini basket (AqSearch / AqMiniBasket values). */
:root {
  --aq-fs-suggest-name: 16.5px;    /* suggestion row title (AqSearch 16.5/600) */
  --aq-fs-suggest-meta: 13.5px;    /* suggestion row mono meta */
  --aq-size-18: 18px;              /* mini-basket remove icon */
  --aq-minibasket-list-h: 340px;   /* mini-basket line list scroll box (kit maxHeight 340) */
  --aq-fs-line-title: 18px;        /* mini-basket empty-state title (kit 18/600) */
}

/* Review note 2026-08-21: "I don't like these semi transparent outlines,
   must be like in google input fields" — the DS's global :focus-visible
   halo (--shadow-focus, a 30%-alpha 3px ring) reads as a smudge on form
   fields. Google's outlined inputs sharpen the border itself instead: on
   focus the field shows a solid 2px accent edge (1px real border +
   1px inset ring — no layout shift), no glow. Buttons and links keep the
   DS ring; this targets only fields. The theme's own search input sits
   borderless inside its bordered wrapper, so it opts back out. */
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  /* !important: the island fields carry their border inline, which would
     otherwise keep the hairline gray under the ring. */
  border-color: var(--accent) !important;
  box-shadow: inset 0 0 0 1px var(--accent);
}
[data-island="live-search"] input:focus-visible,
[data-search-input]:focus-visible {
  box-shadow: none;
}

/* Review note 2026-08-21: "1 input per row!" — the checkout form stacks
   every field full-width, Google-form style. */
:root {
  --island-field-cols: 1fr;
  /* The flat/floor/entrance/lift detail row stays multi-up ("except this
     row") — --island-field-cols-sm keeps the island's auto-fit default. */
  /* Styled select trigger: no native arrow, the DS chevron drawn at the
     field's own padding (review note: "why arrow shifted"). Encoded SVG,
     stroke = ink-3 cool. */
  --island-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%235C6773' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}

/* Review notes 2026-08-21 (second round): the island's secondary button is
   the kit's dark chrome pair ("lost styles of apply btn?"), and custom
   dropdown popups share the suggestion card's shadow. */
:root {
  --island-btn2-bg: var(--aq-chrome-bg);
  --island-btn2-fg: var(--aq-chrome-fg);
  --island-popup-shadow: var(--aq-suggest-shadow);
  /* Wishlist active state — the "reddish" pair the save button and its
     filled heart flip to (bootstrap.ts's rePaintLists). Warm red tuned to
     sit beside the teal accent without matching --vl-sale's ochre. */
  --aq-wish: #C2453A;
  --aq-wish-quiet: #FAEDEB;
  /* Auth card width (account sign-in / register). */
  --aq-auth-max: 460px;
}

/* Toast CSS-fallback lifetime (JS removes at 2600ms; this covers an
   interrupted bundle). */
:root { --aq-toast-life: 3s; }
