/*
 * Trinix Commerce — shared design system.
 *
 * Linked from layouts/guest.php, layouts/shop.php and layouts/app.php —
 * every customer/admin view extends one of those three, so this is the
 * single place that reskins the whole app. Built on top of Bootstrap
 * 5.3's CSS-variable theming (no Sass recompile): redefining --bs-* here
 * recolors Bootstrap's own components, with a few explicit rules layered
 * on for things Bootstrap's variables don't fully cover (shadows,
 * transitions, hover states, typography).
 *
 * Store Admins can override --bs-primary/--bs-primary-rgb per tenant from
 * their own Primary/Secondary colour settings (see layouts/shop.php and
 * layouts/app.php) — everything below is written against those
 * variables, not hard-coded hex values, so a tenant's brand colour flows
 * through consistently.
 *
 * Storefront theme catalog: :root below is the base/fallback palette
 * (used by the shared cross-tenant /login gateway, and as the ultimate
 * fallback if a store's active_theme is ever unset). The real catalog is
 * six independently selectable, premium jewellery-boutique themes, each
 * a full [data-theme="…"] block further down: luxury_black_gold,
 * royal_purple_gold, peacock_teal_gold, blush_pastel, royal_navy_gold,
 * ivory_champagne (see ThemeCatalog/ThemeService/the `themes` table).
 * layouts/shop.php and the Customer branch of layouts/app.php set
 * data-theme="<slug>" on <html> from the store's active theme; a
 * tenant's custom brand colour (inline <style>, loaded after this file)
 * still wins over the theme for --bs-primary — themes set the full
 * palette, brand colour is an optional accent tweak on top.
 *
 * Phase 11 — admin panel light/dark: a SEPARATE, PARALLEL system, not an
 * extension of the above. Keyed off its own [data-admin-theme="dark"]
 * attribute (per signed-in admin user, see AdminThemeController), only
 * ever set on <html> for the sidebar/admin shell — see layouts/app.php.
 * A customer never sees data-admin-theme; an admin's own <html> never
 * carries data-theme. The two attribute names never collide, so a
 * store's storefront theme and an admin's own dark-mode preference
 * can't leak into each other. The admin shell is explicitly out of scope
 * for the storefront theme rewrite below — it keeps Inter throughout and
 * never picks up --tx-font-heading (see the .tx-storefront scoping rule).
 */

:root {
    /* ---- Brand palette (defaults; a tenant's own colours, when set,
       override --bs-primary/--bs-primary-rgb inline in layouts/app.php) ---- */
    --bs-primary: #4f46e5;
    --bs-primary-rgb: 79, 70, 229;
    --bs-primary-text-emphasis: #3730a3;
    --bs-primary-bg-subtle: #eef2ff;
    --bs-primary-border-subtle: #c7d2fe;
    --tx-primary-hover: #4338ca;
    --tx-primary-active: #3730a3;
    /* Foreground for text/icons sitting on a solid --bs-primary fill
       (buttons). Bootstrap's own .btn-primary bakes in a fixed white
       label at build time, which stays legible against every accent
       colour used below EXCEPT Dark & Gold's gold (light-on-light) — see
       that theme's override — so this token exists precisely to let
       .btn-primary's colour follow the theme instead of staying fixed. */
    --tx-on-primary: #ffffff;

    --tx-secondary: #64748b;

    /* ---- Neutrals ---- */
    --bs-body-bg: #f8fafc;
    --bs-body-color: #1e293b;
    --bs-border-color: #e2e8f0;
    --bs-secondary-color: #64748b;
    --tx-surface: #ffffff;
    --tx-muted-bg: #f1f5f9;

    /* ---- Semantic colours (slightly softer than Bootstrap defaults) ---- */
    --bs-success: #16a34a;
    --bs-success-rgb: 22, 163, 74;
    --bs-warning: #d97706;
    --bs-warning-rgb: 217, 119, 6;
    --bs-danger: #dc2626;
    --bs-danger-rgb: 220, 38, 38;
    --bs-info: #0891b2;
    --bs-info-rgb: 8, 145, 178;

    /* ---- Shape & motion ---- */
    --bs-border-radius: 0.5rem;
    --bs-border-radius-sm: 0.375rem;
    --bs-border-radius-lg: 0.75rem;
    --tx-shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
    --tx-shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.04);
    --tx-shadow-lg: 0 10px 25px -5px rgba(15, 23, 42, 0.1), 0 8px 10px -6px rgba(15, 23, 42, 0.06);
    --tx-transition: 150ms cubic-bezier(0.4, 0, 0.2, 1);

    /* ---- Chrome (navbar) & 3D viewer canvas — themeable, not hard-coded ---- */
    --tx-navbar-bg: linear-gradient(180deg, #1e293b 0%, #0f172a 100%);
    --tx-navbar-border-bottom: rgba(255, 255, 255, 0.06);
    --tx-viewer-bg: var(--tx-muted-bg);

    /* ---- Alerts (soft-tinted; tokenised so dark themes can re-tint them) ---- */
    --tx-alert-danger-bg: #fef2f2;
    --tx-alert-danger-border: #fecaca;
    --tx-alert-danger-color: #991b1b;
    --tx-alert-success-bg: #f0fdf4;
    --tx-alert-success-border: #bbf7d0;
    --tx-alert-success-color: #166534;
    --tx-alert-warning-bg: #fffbeb;
    --tx-alert-warning-border: #fde68a;
    --tx-alert-warning-color: #92400e;
    --tx-alert-info-bg: #ecfeff;
    --tx-alert-info-border: #a5f3fc;
    --tx-alert-info-color: #155e75;

    /* ---- Storefront chrome & decorative tokens ----
       --tx-navbar-color/--tx-wishlist-btn-bg are themed per [data-theme]
       block below (a light-header theme needs dark nav text, a dark
       product photo needs a light wishlist-circle) — these are just the
       base-theme/fallback values. */
    --tx-navbar-color: #f8fafc;
    --tx-wishlist-btn-bg: rgba(255, 255, 255, 0.85);

    /* ---- Typography ----
       Body stays Inter everywhere (admin included). The heading face is
       only ever applied inside .tx-storefront (customer-facing shop/
       account/guest pages) — see the scoping rule near body{} below —
       so the admin panel's own headings are untouched. */
    --tx-font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    --tx-font-heading: 'Playfair Display', Georgia, 'Times New Roman', serif;
}

/* ---------------------------------------------------------------
   Phase 11 — Admin panel light/dark mode. SEPARATE system from the
   storefront themes below: keyed off its own [data-admin-theme]
   attribute (set on <html> only for the sidebar/admin shell — see
   layouts/app.php), never [data-theme]. A Store Admin's own dark-mode
   preference must never change what their store's customers see, and
   picking a storefront theme must never change the admin's own chrome —
   this selector and [data-theme] below share no attribute name, so
   they can never collide on a normal page load.
   Deliberately placed BEFORE the [data-theme] blocks: the Phase 7
   Appearance page's live theme preview (store/appearance.php) works by
   JS-setting data-theme on <html> for an instant on-page preview of a
   storefront theme while still inside the admin shell — if an admin
   also has dark mode on, that preview must still show the storefront
   theme's TRUE colours, not the admin's. Source order (not specificity)
   decides ties here, so [data-theme] must come after this block to keep
   winning during that preview, exactly as it did before Phase 11.
   --------------------------------------------------------------- */
[data-admin-theme="dark"] {
    --bs-primary: #818cf8;
    --bs-primary-rgb: 129, 140, 248;
    --bs-primary-text-emphasis: #c7d2fe;
    --bs-primary-bg-subtle: #1e2247;
    --bs-primary-border-subtle: #3730a3;
    --tx-primary-hover: #6366f1;
    --tx-primary-active: #4f46e5;

    --tx-secondary: #94a3b8;

    --bs-body-bg: #0f172a;
    --bs-body-color: #e2e8f0;
    /* Bootstrap 5.3's own .table reads --bs-emphasis-color (not
       --bs-body-color) for its text, and that variable is never
       redefined here otherwise — every dashboard table rendered with
       Bootstrap's hardcoded #000 default, black-on-navy. Same fix
       applied to each dark storefront theme below. */
    --bs-emphasis-color: #e2e8f0;
    --bs-emphasis-color-rgb: 226, 232, 240;
    --bs-border-color: #334155;
    --bs-secondary-color: #94a3b8;
    --tx-surface: #1e293b;
    --tx-muted-bg: #24334a;

    --tx-navbar-bg: linear-gradient(180deg, #1e293b 0%, #0b1120 100%);
    --tx-navbar-border-bottom: rgba(255, 255, 255, 0.08);
    --tx-viewer-bg: #131c2e;

    --tx-alert-danger-bg: #3f1d1d;
    --tx-alert-danger-border: #7f1d1d;
    --tx-alert-danger-color: #fecaca;
    --tx-alert-success-bg: #14301f;
    --tx-alert-success-border: #166534;
    --tx-alert-success-color: #bbf7d0;
    --tx-alert-warning-bg: #3a2a0f;
    --tx-alert-warning-border: #92400e;
    --tx-alert-warning-color: #fde68a;
    --tx-alert-info-bg: #0e3038;
    --tx-alert-info-border: #155e75;
    --tx-alert-info-color: #a5f3fc;
}

/* ---------------------------------------------------------------
   The six-theme premium jewellery-boutique catalog (the "Navya
   Collections" reference brief). Each is a genuinely separate,
   independently selectable/assignable theme (see ThemeCatalog/
   ThemeService/the `themes` table) — not a recolour of one another at
   runtime. Four are dark-canvas + gold-outlined-button themes; the two
   light ones (Blush Pastel, Ivory & Champagne) use a light header and a
   solid-fill button instead — see the two grouped overrides after the
   six palettes below. No gradients on the page body itself, no
   excessive animation beyond the app's existing ~150ms transitions —
   depth comes from real (subtle) shadows and a gold hairline, not glow.
   --------------------------------------------------------------- */

/* 1. Luxury Black & Gold — near-black canvas, rich metallic gold,
   antique-gold secondary, champagne-gold muted text, ivory body text. */
[data-theme="luxury_black_gold"] {
    --bs-primary: #d4af37;
    --bs-primary-rgb: 212, 175, 55;
    --bs-primary-text-emphasis: #e8cc7a;
    --bs-primary-bg-subtle: #241d0e;
    --bs-primary-border-subtle: #5c4a1f;
    --tx-primary-hover: #c4a030;
    --tx-primary-active: #b08f28;
    --tx-on-primary: #0a0a0a;
    --tx-secondary: #b8973f;

    --bs-body-bg: #0a0a0a;
    --bs-body-color: #f7f1e3;
    /* See the matching comment in [data-admin-theme="dark"] — Bootstrap
       tables read --bs-emphasis-color, not --bs-body-color. */
    --bs-emphasis-color: #f7f1e3;
    --bs-emphasis-color-rgb: 247, 241, 227;
    --bs-border-color: #3d331a;
    --bs-secondary-color: #cbb98a;
    --tx-surface: #141414;
    --tx-muted-bg: #1c1a15;

    --bs-border-radius: 0.375rem;
    --bs-border-radius-sm: 0.25rem;
    --bs-border-radius-lg: 0.5rem;
    --tx-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.6);
    --tx-shadow: 0 4px 14px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(212, 175, 55, 0.08);
    --tx-shadow-lg: 0 14px 34px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(212, 175, 55, 0.1);

    --tx-navbar-bg: #0a0a0a;
    --tx-navbar-color: #f2e6c8;
    --tx-navbar-border-bottom: rgba(212, 175, 55, 0.3);
    --tx-viewer-bg: #141414;
    --tx-wishlist-btn-bg: rgba(20, 20, 20, 0.6);

    --tx-alert-danger-bg: #241414;
    --tx-alert-danger-border: #4a2020;
    --tx-alert-danger-color: #e8a5a0;
    --tx-alert-success-bg: #132018;
    --tx-alert-success-border: #23422f;
    --tx-alert-success-color: #a8d9bd;
    --tx-alert-warning-bg: #241d0e;
    --tx-alert-warning-border: #4a3b1a;
    --tx-alert-warning-color: #e6c878;
    --tx-alert-info-bg: #131b22;
    --tx-alert-info-border: #253a4a;
    --tx-alert-info-color: #a9c6e0;

    /* Silver — this theme's own second metal, used sparingly as a
       counterpoint to the gold (hairlines, dividers, secondary badges)
       rather than as a second full accent colour of its own. */
    --tx-silver: #c8ccd2;
    --tx-silver-bright: #e8eaee;
    --tx-silver-dim: #6b7078;
}

/* 2. Royal Purple & Gold — deep royal purple canvas, plum/wine
   secondary, rich gold accent. Feminine, festive, regal. */
[data-theme="royal_purple_gold"] {
    --bs-primary: #d4af37;
    --bs-primary-rgb: 212, 175, 55;
    --bs-primary-text-emphasis: #e8cc7a;
    --bs-primary-bg-subtle: #362a48;
    --bs-primary-border-subtle: #5c4a1f;
    --tx-primary-hover: #c4a030;
    --tx-primary-active: #b08f28;
    --tx-on-primary: #2d1b3d;
    --tx-secondary: #7a4f8f;

    --bs-body-bg: #2d1b3d;
    --bs-body-color: #f5eef7;
    /* See the matching comment in [data-admin-theme="dark"]. */
    --bs-emphasis-color: #f5eef7;
    --bs-emphasis-color-rgb: 245, 238, 247;
    --bs-border-color: #4a3a5e;
    --bs-secondary-color: #d8c7e0;
    --tx-surface: #3d2650;
    --tx-muted-bg: #452c5a;

    --bs-border-radius: 0.375rem;
    --bs-border-radius-sm: 0.25rem;
    --bs-border-radius-lg: 0.5rem;
    --tx-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5);
    --tx-shadow: 0 4px 14px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(212, 175, 55, 0.1);
    --tx-shadow-lg: 0 14px 34px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(212, 175, 55, 0.12);

    --tx-navbar-bg: linear-gradient(180deg, #3d2650 0%, #2d1b3d 100%);
    --tx-navbar-color: #f0e6d8;
    --tx-navbar-border-bottom: rgba(212, 175, 55, 0.3);
    --tx-viewer-bg: #3d2650;
    --tx-wishlist-btn-bg: rgba(61, 38, 80, 0.55);
}

/* 3. Peacock Teal & Gold — deep peacock-teal canvas, emerald-teal
   secondary, antique-gold accent. Artistic, rich, jewel-toned. */
[data-theme="peacock_teal_gold"] {
    --bs-primary: #d4af37;
    --bs-primary-rgb: 212, 175, 55;
    --bs-primary-text-emphasis: #e8cc7a;
    --bs-primary-bg-subtle: #14413f;
    --bs-primary-border-subtle: #5c4a1f;
    --tx-primary-hover: #c4a030;
    --tx-primary-active: #b08f28;
    --tx-on-primary: #0d3b3e;
    --tx-secondary: #1f6b64;

    --bs-body-bg: #0d3b3e;
    --bs-body-color: #f5f5ee;
    /* See the matching comment in [data-admin-theme="dark"]. */
    --bs-emphasis-color: #f5f5ee;
    --bs-emphasis-color-rgb: 245, 245, 238;
    --bs-border-color: #235255;
    --bs-secondary-color: #bcd9d2;
    --tx-surface: #124548;
    --tx-muted-bg: #164d50;

    --bs-border-radius: 0.375rem;
    --bs-border-radius-sm: 0.25rem;
    --bs-border-radius-lg: 0.5rem;
    --tx-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5);
    --tx-shadow: 0 4px 14px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(212, 175, 55, 0.1);
    --tx-shadow-lg: 0 14px 34px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(212, 175, 55, 0.12);

    --tx-navbar-bg: linear-gradient(180deg, #124548 0%, #0d3b3e 100%);
    --tx-navbar-color: #f0ead8;
    --tx-navbar-border-bottom: rgba(212, 175, 55, 0.3);
    --tx-viewer-bg: #124548;
    --tx-wishlist-btn-bg: rgba(18, 69, 72, 0.55);
}

/* 4. Blush / Pastel Luxury — the one light-canvas theme where the
   button colour ISN'T gold: primary is a dusty rose/blush (kept
   saturated enough to stay legible, not childish-pink), champagne gold
   is the secondary/border accent instead. Header is light too (ivory/
   blush), unlike the four dark themes — see .tx-navbar below. */
[data-theme="blush_pastel"] {
    --bs-primary: #c9808f;
    --bs-primary-rgb: 201, 128, 143;
    --bs-primary-text-emphasis: #8a4a58;
    --bs-primary-bg-subtle: #f7e3e6;
    --bs-primary-border-subtle: #e6c3cb;
    --tx-primary-hover: #b96f7e;
    --tx-primary-active: #a35f6d;
    --tx-on-primary: #ffffff;
    --tx-secondary: #b5828a;

    --bs-body-bg: #fbeeea;
    --bs-body-color: #3a2a24;
    --bs-border-color: #e9cfc0;
    --bs-secondary-color: #8a7268;
    --tx-surface: #fff8f5;
    --tx-muted-bg: #f5e3db;

    --bs-border-radius: 0.375rem;
    --bs-border-radius-sm: 0.25rem;
    --bs-border-radius-lg: 0.5rem;
    --tx-shadow-sm: 0 1px 2px rgba(58, 42, 36, 0.08);
    --tx-shadow: 0 4px 14px rgba(58, 42, 36, 0.08), 0 0 0 1px rgba(201, 128, 143, 0.1);
    --tx-shadow-lg: 0 14px 34px rgba(58, 42, 36, 0.1), 0 0 0 1px rgba(201, 128, 143, 0.12);

    --tx-navbar-bg: linear-gradient(180deg, #fbeeea 0%, #f5e0d8 100%);
    --tx-navbar-color: #3a2a24;
    --tx-navbar-border-bottom: rgba(184, 134, 11, 0.3);
    --tx-viewer-bg: #f5e3db;
    --tx-wishlist-btn-bg: rgba(255, 255, 255, 0.85);
}

/* 5. Royal Navy & Gold — deep royal navy canvas, midnight-blue
   secondary, rich gold accent. Sophisticated, timeless, confident. */
[data-theme="royal_navy_gold"] {
    --bs-primary: #d4af37;
    --bs-primary-rgb: 212, 175, 55;
    --bs-primary-text-emphasis: #e8cc7a;
    --bs-primary-bg-subtle: #182a4a;
    --bs-primary-border-subtle: #5c4a1f;
    --tx-primary-hover: #c4a030;
    --tx-primary-active: #b08f28;
    --tx-on-primary: #0f1f3d;
    --tx-secondary: #1e3a6b;

    --bs-body-bg: #0f1f3d;
    --bs-body-color: #f3f0e6;
    /* See the matching comment in [data-admin-theme="dark"]. */
    --bs-emphasis-color: #f3f0e6;
    --bs-emphasis-color-rgb: 243, 240, 230;
    --bs-border-color: #2a3c60;
    --bs-secondary-color: #b7c2d9;
    --tx-surface: #16294f;
    --tx-muted-bg: #1a2e58;

    --bs-border-radius: 0.375rem;
    --bs-border-radius-sm: 0.25rem;
    --bs-border-radius-lg: 0.5rem;
    --tx-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.5);
    --tx-shadow: 0 4px 14px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(212, 175, 55, 0.1);
    --tx-shadow-lg: 0 14px 34px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(212, 175, 55, 0.12);

    --tx-navbar-bg: linear-gradient(180deg, #16294f 0%, #0f1f3d 100%);
    --tx-navbar-color: #eee3c8;
    --tx-navbar-border-bottom: rgba(212, 175, 55, 0.3);
    --tx-viewer-bg: #16294f;
    --tx-wishlist-btn-bg: rgba(22, 41, 79, 0.55);
}

/* 6. Ivory & Champagne — the other light-canvas theme, champagne gold
   throughout (primary AND accent — no rose/blush contrast hue here).
   Minimal, bridal, timeless. Light header, like Blush Pastel above. */
[data-theme="ivory_champagne"] {
    --bs-primary: #b8860b;
    --bs-primary-rgb: 184, 134, 11;
    --bs-primary-text-emphasis: #8f680a;
    --bs-primary-bg-subtle: #f4e6cc;
    --bs-primary-border-subtle: #e2c98f;
    --tx-primary-hover: #a3770a;
    --tx-primary-active: #8f680a;
    --tx-on-primary: #ffffff;
    --tx-secondary: #c1a874;

    --bs-body-bg: #f7ede1;
    --bs-body-color: #33261a;
    --bs-border-color: #e6d5b8;
    --bs-secondary-color: #8f7f6a;
    --tx-surface: #fffaf3;
    --tx-muted-bg: #efe0c8;

    --bs-border-radius: 0.375rem;
    --bs-border-radius-sm: 0.25rem;
    --bs-border-radius-lg: 0.5rem;
    --tx-shadow-sm: 0 1px 2px rgba(51, 38, 26, 0.08);
    --tx-shadow: 0 4px 14px rgba(51, 38, 26, 0.08), 0 0 0 1px rgba(184, 134, 11, 0.08);
    --tx-shadow-lg: 0 14px 34px rgba(51, 38, 26, 0.1), 0 0 0 1px rgba(184, 134, 11, 0.1);

    --tx-navbar-bg: linear-gradient(180deg, #f7ede1 0%, #f0e2cf 100%);
    --tx-navbar-color: #33261a;
    --tx-navbar-border-bottom: rgba(184, 134, 11, 0.3);
    --tx-viewer-bg: #efe0c8;
    --tx-wishlist-btn-bg: rgba(255, 255, 255, 0.85);
}

/* Gold-outlined button — the four dark themes. Reads as premium (the
   pattern real jewellery/fashion sites use) and sidesteps the "what
   colour should the label be" problem a solid gold fill creates. Fills
   with gold only transiently, on hover/active. */
[data-theme="luxury_black_gold"] .btn-primary,
[data-theme="royal_purple_gold"] .btn-primary,
[data-theme="peacock_teal_gold"] .btn-primary,
[data-theme="royal_navy_gold"] .btn-primary {
    --bs-btn-bg: transparent;
    --bs-btn-border-color: var(--bs-primary);
    --bs-btn-color: var(--bs-primary);
    --bs-btn-hover-bg: var(--bs-primary);
    --bs-btn-hover-border-color: var(--bs-primary);
    --bs-btn-hover-color: var(--tx-on-primary);
    --bs-btn-active-bg: var(--tx-primary-active);
    --bs-btn-active-border-color: var(--tx-primary-active);
    --bs-btn-active-color: var(--tx-on-primary);
}

/* Blush Pastel and Ivory & Champagne keep the default solid-fill
   .btn-primary (declared once, above, in the shared Buttons section) —
   an outline in their accent colour would read washed-out at this
   light contrast, unlike gold-on-black. */

/* ---------------------------------------------------------------
   Luxury Black & Gold — the one theme deliberately taken past this
   file's usual "shadows, not glow" restraint: a moving gold/silver
   shine sweep on primary buttons, a two-metal ornament divider, and a
   shimmering gradient on the homepage's hero heading. Every effect is
   scoped to [data-theme="luxury_black_gold"] only — the other five
   themes keep their original, calmer treatment untouched.
   --------------------------------------------------------------- */
[data-theme="luxury_black_gold"] .btn-primary {
    position: relative;
    overflow: hidden;
}
[data-theme="luxury_black_gold"] .btn-primary::after {
    content: "";
    position: absolute;
    inset: 0;
    left: -150%;
    width: 55%;
    background: linear-gradient(115deg,
        transparent 0%,
        rgba(232, 234, 238, 0.55) 45%,
        var(--tx-silver-bright) 50%,
        rgba(232, 234, 238, 0.55) 55%,
        transparent 100%);
    transform: skewX(-18deg);
    transition: left 650ms cubic-bezier(0.4, 0, 0.2, 1);
    pointer-events: none;
}
[data-theme="luxury_black_gold"] .btn-primary:hover::after {
    left: 150%;
}

[data-theme="luxury_black_gold"] .tx-ornament-divider-dot {
    background: linear-gradient(135deg, var(--tx-silver-bright) 0%, var(--bs-primary) 55%, var(--tx-primary-active) 100%);
    box-shadow: 0 0 8px rgba(212, 175, 55, 0.55);
}
[data-theme="luxury_black_gold"] .tx-ornament-divider::before {
    background: linear-gradient(90deg, transparent, var(--tx-silver));
}
[data-theme="luxury_black_gold"] .tx-ornament-divider::after {
    background: linear-gradient(90deg, var(--bs-primary), transparent);
}

/* Shimmering gold/silver hero heading — a slow-panning gradient text
   fill, the single most "shiny" moment on the page since it's the
   first thing a shopper reads. */
[data-theme="luxury_black_gold"] .tx-hero h1 {
    /* Plain gold fallback first: only browsers that actually support
       background-clip: text (checked below) ever get color: transparent,
       so a browser without it still shows solid gold text, never blank. */
    color: var(--bs-primary);
}
@supports (background-clip: text) or (-webkit-background-clip: text) {
    [data-theme="luxury_black_gold"] .tx-hero h1 {
        background: linear-gradient(110deg,
            var(--bs-primary) 0%,
            var(--tx-silver-bright) 22%,
            var(--bs-primary) 40%,
            var(--bs-primary) 60%,
            var(--tx-silver-bright) 78%,
            var(--bs-primary) 100%);
        background-size: 220% auto;
        background-position: 0% center;
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
        animation: tx-shine-sweep 7s linear infinite;
    }
}

@keyframes tx-shine-sweep {
    to { background-position: 220% center; }
}

/* A fine gold/silver hairline ring around the "TX" brand medallion —
   catches the light-sweep motif from the buttons above in miniature. */
[data-theme="luxury_black_gold"] .tx-brand-mark {
    box-shadow: var(--tx-shadow), 0 0 0 1px var(--tx-silver-dim), inset 0 1px 0 rgba(232, 234, 238, 0.35);
}

/* Product cards get a gold hairline that only appears on hover — the
   metal accent this theme is built around, echoed at small scale. */
[data-theme="luxury_black_gold"] .tx-product-card:hover {
    box-shadow: var(--tx-shadow-lg), 0 0 0 1px rgba(212, 175, 55, 0.4);
}

body {
    font-family: var(--tx-font-body);
    -webkit-font-smoothing: antialiased;
    background-color: var(--bs-body-bg);
    color: var(--bs-body-color);
    transition: background-color var(--tx-transition), color var(--tx-transition);
}

a {
    transition: color var(--tx-transition);
}

/* ---------------------------------------------------------------
   Storefront typography — the elegant serif heading face is scoped to
   .tx-storefront (shop/account/guest pages — see the body class in
   layouts/shop.php, layouts/app.php's Customer branch, and
   layouts/guest.php) so the admin panel's own headings are never
   affected, per the "don't touch admin" rule.
   --------------------------------------------------------------- */
.tx-storefront h1,
.tx-storefront h2,
.tx-storefront h3,
.tx-storefront h4,
.tx-storefront h5,
.tx-storefront h6,
.tx-storefront .navbar-brand,
.tx-storefront .tx-brand-mark {
    font-family: var(--tx-font-heading);
}

/* ---------------------------------------------------------------
   Navbar — storefront (layouts/shop.php) and the Customer top-bar
   (layouts/app.php's non-sidebar branch) share this component. Colour
   is fully theme-driven rather than the fixed navbar-dark/bg-dark/
   text-light Bootstrap utilities the markup used to hard-code, because
   two of the six themes (Blush Pastel, Ivory & Champagne) need a LIGHT
   header with dark nav text — the other four keep the dark header the
   old hard-coded classes always produced.
   --------------------------------------------------------------- */
.tx-navbar {
    --bs-bg-opacity: 1;
    background: var(--tx-navbar-bg) !important;
    box-shadow: 0 1px 0 var(--tx-navbar-border-bottom), var(--tx-shadow);
    position: sticky;
    top: 0;
    z-index: 1030;
    transition: box-shadow var(--tx-transition);
}
/* Toggled by a small scroll listener in layouts/shop.php — a deeper
   shadow once the page has actually scrolled under the sticky navbar,
   so it reads as "lifted above the page" instead of just "stuck". */
.tx-navbar-scrolled {
    box-shadow: 0 1px 0 var(--tx-navbar-border-bottom), var(--tx-shadow-lg);
}

.navbar-brand {
    /* Matches the product-title treatment (.tx-product-card h2, e.g.
       "Silk Thread Bangles") rather than a heavier weight fighting a
       tight negative letter-spacing, which read as squeezed/condensed
       next to the logo. */
    font-weight: 500;
    letter-spacing: normal;
    white-space: nowrap;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    color: var(--tx-navbar-color) !important;
}

.navbar-brand img {
    border-radius: 0.25rem;
}

/* Store logo — sized to actually read as a logo rather than a favicon-
   sized icon next to the store name, while still fitting the navbar's
   height and never overflowing it on narrow screens. */
.tx-brand-logo {
    height: 3rem;
    max-height: 3rem;
    max-width: 11rem;
    width: auto;
    object-fit: contain;
}

@media (max-width: 767.98px) {
    .tx-brand-logo {
        height: 2.25rem;
        max-height: 2.25rem;
        max-width: 8rem;
    }
}

.tx-navbar-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    color: var(--tx-navbar-color) !important;
    opacity: 0.92;
    text-decoration: none;
    transition: opacity var(--tx-transition), transform var(--tx-transition);
}

/* Underline sweeps in from the center on hover/focus rather than just
   fading opacity — same "give it real motion" treatment as the rest
   of the storefront (product-card float, badge pop, flash-in). */
.tx-navbar-link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -3px;
    height: 2px;
    border-radius: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: center;
    transition: transform 280ms cubic-bezier(0.4, 0, 0.2, 1);
}

.tx-navbar-link:hover,
.tx-navbar-link:focus-visible {
    opacity: 1;
    transform: translateY(-1px);
}

.tx-navbar-link:hover::after,
.tx-navbar-link:focus-visible::after {
    transform: scaleX(1);
}

.tx-navbar .form-control {
    background-color: rgba(127, 127, 127, 0.12);
    border-color: var(--tx-navbar-border-bottom);
    color: var(--tx-navbar-color);
}

.tx-navbar .form-control::placeholder {
    color: var(--tx-navbar-color);
    opacity: 0.65;
}

.tx-btn-navbar-outline {
    border-color: var(--tx-navbar-color);
    color: var(--tx-navbar-color);
    background: transparent;
}

.tx-btn-navbar-outline:hover {
    background: var(--tx-navbar-color);
    border-color: var(--tx-navbar-color);
    color: var(--tx-navbar-bg);
}

/* ---------------------------------------------------------------
   Footer — deliberately reuses the navbar's own background/text
   tokens (every theme's design brief describes the footer as matching
   the header), so a theme only ever has to define one dark/light
   "chrome" pairing, not two.
   --------------------------------------------------------------- */
.tx-footer {
    background: var(--tx-navbar-bg);
    color: var(--tx-navbar-color);
    border-top: 1px solid var(--tx-navbar-border-bottom);
}

.tx-footer a {
    color: var(--tx-navbar-color) !important;
    opacity: 0.85;
}

.tx-footer a:hover {
    opacity: 1;
    color: var(--bs-primary) !important;
}

.tx-footer .tx-footer-copyright {
    opacity: 0.75;
}

.tx-footer-top {
    border-bottom: 1px solid var(--tx-navbar-border-bottom);
}

.tx-footer-heading {
    font-weight: 600;
    letter-spacing: .02em;
    margin-bottom: .75rem;
}

.tx-footer-contact a {
    opacity: 1;
}

.tx-footer-social a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    border: 1px solid var(--tx-navbar-border-bottom);
    opacity: 1;
    transition: transform .15s ease, background-color .15s ease, border-color .15s ease;
}

.tx-footer-social a:hover {
    transform: translateY(-2px);
    background: var(--bs-primary);
    border-color: var(--bs-primary);
    color: var(--tx-on-primary) !important;
}

/* ---------------------------------------------------------------
   Buttons
   --------------------------------------------------------------- */
.btn {
    font-weight: 500;
    transition: background-color var(--tx-transition), border-color var(--tx-transition),
        box-shadow var(--tx-transition), transform var(--tx-transition);
}

.btn:active {
    transform: translateY(1px);
}

.btn-primary {
    --bs-btn-bg: var(--bs-primary);
    --bs-btn-border-color: var(--bs-primary);
    --bs-btn-hover-bg: var(--tx-primary-hover);
    --bs-btn-hover-border-color: var(--tx-primary-hover);
    --bs-btn-active-bg: var(--tx-primary-active);
    --bs-btn-active-border-color: var(--tx-primary-active);
    --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
    --bs-btn-color: var(--tx-on-primary);
    --bs-btn-hover-color: var(--tx-on-primary);
    --bs-btn-active-color: var(--tx-on-primary);
    --bs-btn-disabled-bg: var(--bs-primary);
    --bs-btn-disabled-border-color: var(--bs-primary);
    --bs-btn-disabled-color: var(--tx-on-primary);
    box-shadow: var(--tx-shadow-sm);
}

.btn-primary:hover {
    box-shadow: var(--tx-shadow);
}

.btn-outline-primary {
    --bs-btn-color: var(--bs-primary);
    --bs-btn-border-color: var(--bs-primary);
    --bs-btn-hover-bg: var(--bs-primary);
    --bs-btn-hover-border-color: var(--bs-primary);
}

/* ---------------------------------------------------------------
   Cards, panels ("bg-white p-4 border rounded" is the app's ad hoc
   panel pattern throughout — smooth it out without touching every view).
   Bootstrap's .bg-white utility hard-codes #fff; every one of its uses in
   this app is this same panel/table-surface pattern (never "must stay
   literally white regardless of theme"), so it's retargeted to the
   --tx-surface token here rather than editing every view that uses it.
   --------------------------------------------------------------- */
.bg-white {
    background-color: var(--tx-surface) !important;
}

.card {
    --bs-card-bg: var(--tx-surface);
    background-color: var(--tx-surface);
    color: var(--bs-body-color);
}

.card,
.bg-white.border.rounded {
    border: 1px solid var(--bs-border-color) !important;
    box-shadow: var(--tx-shadow-sm);
    border-radius: var(--bs-border-radius-lg) !important;
}

.card {
    border-radius: var(--bs-border-radius-lg);
}

.card-body {
    padding: 1.5rem;
}

/* ---------------------------------------------------------------
   Forms
   --------------------------------------------------------------- */
.form-control,
.form-select {
    background-color: var(--tx-surface);
    border-color: var(--bs-border-color);
    color: var(--bs-body-color);
    transition: border-color var(--tx-transition), box-shadow var(--tx-transition),
        background-color var(--tx-transition), color var(--tx-transition);
}

.form-control:focus,
.form-select:focus {
    background-color: var(--tx-surface);
    color: var(--bs-body-color);
}

.form-control::placeholder {
    color: var(--bs-secondary-color);
    opacity: 0.75;
}

.form-control:disabled,
.form-select:disabled {
    background-color: var(--tx-muted-bg);
}

.form-control:focus,
.form-select:focus {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.15);
}

.form-label {
    font-weight: 500;
    font-size: 0.875rem;
    color: var(--bs-body-color);
}

.form-check-input {
    background-color: var(--tx-surface);
    border-color: var(--bs-border-color);
}

.form-check-input:checked {
    background-color: var(--bs-primary);
    border-color: var(--bs-primary);
}

.form-check-input:focus {
    box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.15);
}

/* Larger, more prominent on/off switches (e.g. store/payments.php's COD /
   Online Payment toggles) — Bootstrap's default .form-switch is sized for
   a dense settings list, too small to be the sole focal point of a card. */
.tx-payment-toggle .form-check-input {
    width: 2.75rem;
    height: 1.5rem;
    cursor: pointer;
}

.tx-payment-toggle .form-check-label {
    cursor: pointer;
}

/* ---------------------------------------------------------------
   Tables
   --------------------------------------------------------------- */
.table {
    --bs-table-hover-bg: var(--tx-muted-bg);
}

.table-bordered {
    border-color: var(--bs-border-color);
}

.table > :not(caption) > * > * {
    border-bottom-color: var(--bs-border-color);
    padding: 0.6rem 0.75rem;
    vertical-align: middle;
}

.table thead th {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--bs-secondary-color);
    background-color: var(--tx-muted-bg);
    border-bottom-width: 1px;
    font-weight: 600;
}

.table tbody tr {
    transition: background-color var(--tx-transition);
}

/* ---------------------------------------------------------------
   List groups (dashboard "available areas" lists)
   --------------------------------------------------------------- */
.list-group-item {
    border-color: var(--bs-border-color);
    transition: background-color var(--tx-transition);
    padding: 0.85rem 1.1rem;
}

.list-group-item:hover {
    background-color: var(--tx-muted-bg);
}

/* ---------------------------------------------------------------
   Badges & alerts — soften Bootstrap's high-saturation defaults
   --------------------------------------------------------------- */
.badge {
    font-weight: 600;
    letter-spacing: 0.01em;
    padding: 0.4em 0.65em;
}

.alert {
    border: 1px solid transparent;
    border-radius: var(--bs-border-radius);
    box-shadow: var(--tx-shadow-sm);
}

.alert-danger {
    background-color: var(--tx-alert-danger-bg);
    border-color: var(--tx-alert-danger-border);
    color: var(--tx-alert-danger-color);
}

.alert-success {
    background-color: var(--tx-alert-success-bg);
    border-color: var(--tx-alert-success-border);
    color: var(--tx-alert-success-color);
}

.alert-warning {
    background-color: var(--tx-alert-warning-bg);
    border-color: var(--tx-alert-warning-border);
    color: var(--tx-alert-warning-color);
}

.alert-info {
    background-color: var(--tx-alert-info-bg);
    border-color: var(--tx-alert-info-border);
    color: var(--tx-alert-info-color);
}

/* ---------------------------------------------------------------
   Pagination (Phase 12) — first real use is the Phase 13 customer
   product listing/search, but themed here alongside everything else so
   every future list (admin or storefront) picks it up automatically.
   --------------------------------------------------------------- */
.pagination .page-link {
    color: var(--bs-primary);
    background-color: var(--tx-surface);
    border-color: var(--bs-border-color);
}

.pagination .page-link:hover {
    background-color: var(--tx-muted-bg);
    color: var(--tx-primary-hover);
}

.pagination .page-item.active .page-link {
    background-color: var(--bs-primary);
    border-color: var(--bs-primary);
    color: var(--tx-on-primary);
}

.pagination .page-item.disabled .page-link {
    background-color: var(--tx-muted-bg);
    border-color: var(--bs-border-color);
    color: var(--bs-secondary-color);
}

/* ---------------------------------------------------------------
   Storefront (Phase 7 home page, Phase 13 listing/categories) — shared
   here (not a per-page <style> block) so every shop page that renders
   product cards or category tabs gets the same look for free.
   --------------------------------------------------------------- */
.tx-hero {
    background: var(--tx-surface);
    border: 1px solid var(--bs-border-color);
}
.tx-banner-carousel {
    border-radius: var(--bs-border-radius-lg);
    overflow: hidden;
    box-shadow: var(--tx-shadow-lg);
    border: 1px solid var(--bs-border-color);
}
.tx-banner-carousel .carousel-item img {
    width: 100%;
    height: 22rem;
    object-fit: cover;
}
@media (max-width: 767.98px) {
    .tx-banner-carousel .carousel-item img {
        height: 14rem;
    }
}
/* Ken Burns: a slow, barely-there zoom for as long as a slide stays
   active — restarts each time `.active` is re-applied (Bootstrap swaps
   the class, not the element), giving every slide the same quiet drift
   rather than a static, inert photo. */
.tx-banner-carousel .carousel-item.active img {
    animation: tx-kenburns 6s ease-out both;
}
@keyframes tx-kenburns {
    from { transform: scale(1.06); }
    to   { transform: scale(1); }
}
.tx-banner-caption {
    position: absolute;
    inset: auto 0 0 0;
    padding: 2.5rem 1.5rem 1.5rem;
    background: linear-gradient(0deg, rgba(0, 0, 0, 0.72) 0%, rgba(0, 0, 0, 0.35) 55%, transparent 100%);
    text-align: left;
    color: #ffffff;
}
.tx-banner-caption h2 {
    color: #ffffff;
    font-size: 1.5rem;
    margin-bottom: 0.25rem;
}
.tx-banner-caption p {
    color: rgba(255, 255, 255, 0.88);
    margin-bottom: 0.75rem;
    max-width: 32rem;
}
.tx-banner-carousel .carousel-indicators [data-bs-target] {
    background-color: var(--bs-primary);
}
.tx-banner-carousel .carousel-control-prev,
.tx-banner-carousel .carousel-control-next {
    width: 3rem;
    opacity: 0;
    transition: opacity var(--tx-transition);
}
.tx-banner-carousel:hover .carousel-control-prev,
.tx-banner-carousel:hover .carousel-control-next {
    opacity: 0.85;
}
.tx-category-tabs {
    display: flex;
    gap: .5rem;
    overflow-x: auto;
    padding-bottom: .25rem;
    border-bottom: 1px solid var(--bs-border-color);
}
.tx-category-tab {
    flex: 0 0 auto;
    padding: .5rem 1rem;
    border-radius: var(--bs-border-radius);
    /* !important: the generic a:not(.btn) link-colour rule further down
       this file has higher specificity (0,1,1 vs this class's 0,1,0) and
       would otherwise win — same fix .tx-navbar-link already uses for
       the identical collision. Without it, the active tab's text
       silently rendered the same gold as its own gold background. */
    color: var(--bs-body-color) !important;
    text-decoration: none;
    font-size: .9rem;
    font-weight: 500;
    white-space: nowrap;
    transition: background-color var(--tx-transition), color var(--tx-transition), transform var(--tx-transition), box-shadow var(--tx-transition);
}
.tx-category-tab:hover {
    background: var(--tx-muted-bg);
    transform: translateY(-1px);
}
.tx-category-tab-active {
    background: var(--bs-primary);
    color: var(--tx-on-primary) !important;
    box-shadow: var(--tx-shadow-sm);
}
.tx-category-tab-active:hover {
    background: var(--bs-primary);
    transform: none;
}
/* ---------------------------------------------------------------
   Product cards — elevated at rest (not just on hover), a zooming
   image, a quick-add bar that reveals on hover, and a staggered
   fade/rise-in as the grid first paints. Every new rule here reads
   colour only from the existing --tx- and --bs- tokens above, so it
   re-tints correctly under every theme and any tenant brand-colour
   override without a single new hex value of its own.
   --------------------------------------------------------------- */
.tx-product-card {
    overflow: hidden;
    box-shadow: var(--tx-shadow);
    transition: box-shadow var(--tx-transition), transform var(--tx-transition), border-color var(--tx-transition);
    animation: tx-card-in 420ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
.tx-product-card:hover {
    box-shadow: var(--tx-shadow-lg);
    border-color: rgba(var(--bs-primary-rgb), 0.35);
    /* Lifts on entry (the transition above), then keeps a gentle,
       continuous bob for as long as the cursor stays on the card —
       the "floating" feel, not just a static lift. */
    animation: tx-product-float 2.2s ease-in-out infinite;
}
@keyframes tx-product-float {
    0%, 100% { transform: translateY(-4px); }
    50%      { transform: translateY(-9px); }
}
/* Staggers up to the first 12 cards of any grid; anything past that
   simply shares the last delay rather than growing unbounded. */
.row > .col:nth-child(1) .tx-product-card { animation-delay: 0ms; }
.row > .col:nth-child(2) .tx-product-card { animation-delay: 40ms; }
.row > .col:nth-child(3) .tx-product-card { animation-delay: 80ms; }
.row > .col:nth-child(4) .tx-product-card { animation-delay: 120ms; }
.row > .col:nth-child(5) .tx-product-card { animation-delay: 160ms; }
.row > .col:nth-child(6) .tx-product-card { animation-delay: 200ms; }
.row > .col:nth-child(7) .tx-product-card { animation-delay: 240ms; }
.row > .col:nth-child(8) .tx-product-card { animation-delay: 280ms; }
.row > .col:nth-child(n+9) .tx-product-card { animation-delay: 320ms; }
@keyframes tx-card-in {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
}

.tx-product-media {
    position: relative;
    height: 200px;
    overflow: hidden;
    background: var(--tx-muted-bg);
}
.tx-product-media-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform 500ms cubic-bezier(0.16, 1, 0.3, 1);
}
.tx-product-card:hover .tx-product-media-img {
    transform: scale(1.08);
}

.tx-discount-badge {
    position: absolute;
    top: .6rem;
    left: 0;
    background: var(--bs-success);
    color: #fff;
    font-size: .7rem;
    font-weight: 700;
    line-height: 1;
    padding: .3rem .5rem .3rem .45rem;
    border-radius: 0 var(--bs-border-radius-sm) var(--bs-border-radius-sm) 0;
    box-shadow: var(--tx-shadow-sm);
    animation: tx-badge-pop 420ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
    animation-delay: 200ms;
}
@keyframes tx-badge-pop {
    from { opacity: 0; transform: scale(0.6) translateX(-4px); }
    to   { opacity: 1; transform: scale(1) translateX(0); }
}

.tx-wishlist-form {
    position: absolute;
    top: .5rem;
    right: .5rem;
    margin: 0;
    z-index: 2;
}
.tx-wishlist-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    border-radius: 50%;
    border: none;
    background: var(--tx-wishlist-btn-bg);
    color: var(--bs-danger);
    font-size: 1rem;
    cursor: pointer;
    box-shadow: var(--tx-shadow-sm);
    transition: transform var(--tx-transition), background-color var(--tx-transition);
}
.tx-wishlist-btn:hover {
    transform: scale(1.1);
}

/* Quick-add: a full-width bar tucked just below the image's visible
   frame, sliding up to meet it on hover — the classic "reveal on
   hover" e-commerce card pattern. Touch devices have no hover state
   to reveal it from, so `pointer: coarse` pins it visible instead of
   hiding a control mobile shoppers could never otherwise reach. */
.tx-quick-add {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    margin: 0;
    z-index: 2;
    padding: .4rem;
    transform: translateY(100%);
    transition: transform var(--tx-transition);
    background: linear-gradient(0deg, rgba(0, 0, 0, 0.55) 0%, transparent 100%);
}
@media (hover: hover) {
    .tx-quick-add {
        transform: translateY(100%);
    }
    .tx-product-card:hover .tx-quick-add,
    .tx-product-card:focus-within .tx-quick-add {
        transform: translateY(0);
    }
}
@media (pointer: coarse) {
    .tx-quick-add {
        position: static;
        background: none;
        padding: .5rem .75rem 0;
    }
}
.tx-price {
    font-size: 1.05rem;
}

/* Product detail page: the same "zoom the image, ring the active
   thumbnail" treatment shoppers already get on the card grid, applied
   here to the single hero image + its thumbnail strip. */
.tx-hero-media {
    overflow: hidden;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    background: var(--tx-viewer-bg);
}
.tx-hero-media img {
    width: 100%;
    max-height: 480px;
    object-fit: contain;
    display: block;
    transition: transform 400ms cubic-bezier(0.16, 1, 0.3, 1);
}
.tx-hero-media:hover img {
    transform: scale(1.05);
}
.tx-thumb {
    width: 4.5rem;
    height: 4.5rem;
    object-fit: cover;
    padding: .2rem;
    border: 2px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-sm);
    cursor: pointer;
    opacity: .75;
    transition: opacity var(--tx-transition), border-color var(--tx-transition), transform var(--tx-transition);
}
.tx-thumb:hover {
    opacity: 1;
    transform: translateY(-2px);
}
.tx-thumb-active {
    opacity: 1;
    border-color: var(--bs-primary);
}

/* Restrained decorative divider — a thin accent-coloured hairline with
   a centred diamond, in the spirit of the jewellery-boutique reference
   ("thin gold dividers", "subtle ornamental line elements") without
   tipping into a busy or twee ornamental pattern. Colour follows
   --bs-primary, so it automatically re-tints with whichever theme (and
   tenant brand colour) is active. */
.tx-ornament-divider {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    max-width: 12rem;
    margin: 1rem auto;
    opacity: 0.8;
}
.tx-ornament-divider::before,
.tx-ornament-divider::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    background: var(--bs-primary);
}
.tx-ornament-divider-dot {
    width: 0.4rem;
    height: 0.4rem;
    flex-shrink: 0;
    background: var(--bs-primary);
    transform: rotate(45deg);
}

/* ---------------------------------------------------------------
   Guest (login / password reset) shell
   --------------------------------------------------------------- */
.tx-guest-shell {
    background:
        radial-gradient(circle at 15% 20%, rgba(var(--bs-primary-rgb), 0.08), transparent 40%),
        radial-gradient(circle at 85% 80%, rgba(var(--bs-primary-rgb), 0.06), transparent 40%),
        var(--bs-body-bg);
    min-height: 100vh;
}

.tx-guest-card {
    border-radius: var(--bs-border-radius-lg);
    box-shadow: var(--tx-shadow-lg);
    border: 1px solid var(--bs-border-color);
}

/* Install wizard step indicator (app/Views/install/layouts/install.php) */
.tx-install-steps li {
    flex: 1;
    text-align: center;
    color: var(--bs-secondary-color);
}

.tx-install-steps li.tx-install-step-done {
    color: var(--bs-success);
}

.tx-install-steps li.fw-semibold {
    color: var(--bs-primary);
}

.tx-brand-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 3rem;
    height: 3rem;
    border-radius: var(--bs-border-radius);
    background: linear-gradient(135deg, var(--bs-primary), var(--tx-primary-hover));
    /* --tx-on-primary, not a hardcoded white: a light accent colour
       (e.g. this app's gold themes) puts white text below WCAG AA
       against its own gradient — this is the same token every other
       "text on --bs-primary" surface in this file already uses. */
    color: var(--tx-on-primary);
    font-weight: 700;
    font-size: 1.1rem;
    box-shadow: var(--tx-shadow);
}

/* ---------------------------------------------------------------
   Links
   --------------------------------------------------------------- */
a:not(.btn) {
    color: var(--bs-primary);
}

a:not(.btn):hover {
    color: var(--tx-primary-hover);
}

/* ---------------------------------------------------------------
   Admin shell (Phase 8) — sidebar + top header, used for Super Admin
   and Store Admin/Staff only (see layouts/app.php: everyone else, e.g.
   Customer, keeps the plain top-navbar layout this replaced). Colours
   are the same tokens the rest of the app uses; which palette applies
   is now decided by [data-admin-theme] (Phase 11, above) rather than
   the storefront's [data-theme] — this is purely a structural layer,
   unaffected by which of the two is active.

   Breakpoints: <768px = off-canvas ("mobile"); >=768px = persistent,
   collapsible sidebar (covers both "tablet: collapsible" and
   "desktop: sidebar+header+content" from the spec — desktop is simply
   the uncollapsed resting state of the same mechanism).
   --------------------------------------------------------------- */
.tx-brand-mark-sm {
    width: 2.25rem;
    height: 2.25rem;
    font-size: 0.85rem;
    flex-shrink: 0;
}

.tx-shell {
    display: flex;
    min-height: 100vh;
}

.tx-sidebar {
    display: flex;
    flex-direction: column;
    width: 260px;
    flex-shrink: 0;
    background: var(--tx-surface);
    border-right: 1px solid var(--bs-border-color);
    transition: width var(--tx-transition), transform var(--tx-transition);
}

.tx-sidebar-brand {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 1rem 1.1rem;
    border-bottom: 1px solid var(--bs-border-color);
    overflow: hidden;
    white-space: nowrap;
}

.tx-sidebar-brand-text {
    font-weight: 700;
    font-size: 0.85rem;
    letter-spacing: 0.02em;
    color: var(--bs-body-color);
}

.tx-sidebar-nav {
    flex: 1 1 auto;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 0.75rem 0.6rem;
}

.tx-nav-group {
    margin-bottom: 0.75rem;
}

.tx-nav-group-label {
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    color: var(--bs-secondary-color);
    padding: 0.4rem 0.6rem 0.25rem;
    white-space: nowrap;
}

.tx-nav-link {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.55rem 0.6rem;
    margin-bottom: 0.1rem;
    border-radius: var(--bs-border-radius);
    /* !important: same a:not(.btn) specificity collision as
       .tx-category-tab/.tx-navbar-link — without it every sidebar link
       rendered in --bs-primary instead of the intended body colour. */
    color: var(--bs-body-color) !important;
    text-decoration: none;
    font-size: 0.875rem;
    white-space: nowrap;
    border-left: 3px solid transparent;
    transition: background-color var(--tx-transition), color var(--tx-transition);
}

.tx-nav-link i {
    font-size: 1rem;
    width: 1.1rem;
    text-align: center;
    flex-shrink: 0;
}

.tx-nav-link:hover {
    background: var(--tx-muted-bg);
    color: var(--bs-body-color);
}

.tx-nav-link-active {
    background: var(--bs-primary-bg-subtle);
    border-left-color: var(--bs-primary);
    color: var(--bs-primary-text-emphasis) !important;
    font-weight: 600;
}

.tx-nav-link-disabled {
    opacity: 0.55;
    cursor: not-allowed;
}

.tx-nav-link-text {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tx-nav-soon {
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--bs-secondary-color);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-sm);
    padding: 0.1rem 0.35rem;
    flex-shrink: 0;
}

.tx-sidebar-footer {
    border-top: 1px solid var(--bs-border-color);
    padding: 0.5rem;
    display: flex;
    justify-content: flex-end;
}

.tx-sidebar-collapse-btn {
    border: none;
    background: transparent;
    color: var(--bs-secondary-color);
    width: 2.25rem;
    height: 2.25rem;
    border-radius: var(--bs-border-radius);
    transition: background-color var(--tx-transition), transform var(--tx-transition);
}

.tx-sidebar-collapse-btn:hover {
    background: var(--tx-muted-bg);
}

.tx-sidebar-backdrop {
    display: none;
    border: none;
    padding: 0;
}

.tx-main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.tx-topheader {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem 1.25rem;
    background: var(--tx-surface);
    border-bottom: 1px solid var(--bs-border-color);
    position: sticky;
    top: 0;
    z-index: 20;
}

.tx-page-title {
    flex: 1 1 auto;
    font-size: 1.15rem;
    font-weight: 600;
    margin: 0;
    color: var(--bs-body-color);
}

.tx-topheader-actions {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

/* The Phase 11 theme-toggle button is a real <form> (POST, no JS
   framework) rather than a bare button, so it needs to not introduce
   its own box in this flex row. */
.tx-theme-toggle-form {
    margin: 0;
    display: flex;
}

.tx-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.35rem;
    height: 2.35rem;
    border-radius: var(--bs-border-radius);
    border: none;
    background: transparent;
    color: var(--bs-secondary-color);
    font-size: 1.05rem;
    cursor: pointer;
    transition: background-color var(--tx-transition);
}

.tx-icon-btn:hover {
    background: var(--tx-muted-bg);
}

.tx-profile-btn {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.3rem 0.5rem;
    border: none;
    background: transparent;
    border-radius: var(--bs-border-radius);
    cursor: pointer;
    transition: background-color var(--tx-transition);
}

.tx-profile-btn:hover {
    background: var(--tx-muted-bg);
}

.tx-profile-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    border-radius: 50%;
    background: var(--bs-primary);
    color: var(--tx-on-primary);
    font-weight: 700;
    font-size: 0.85rem;
    flex-shrink: 0;
}

.tx-profile-info {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.15;
}

.tx-profile-name {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--bs-body-color);
}

.tx-profile-role {
    font-size: 0.72rem;
    color: var(--bs-secondary-color);
}

.tx-content {
    flex: 1 1 auto;
    padding: 1.25rem 1.5rem 2.5rem;
}

/* Collapsed (icon-only) sidebar — desktop/tablet only, toggled via JS. */
.tx-sidebar-collapsed .tx-sidebar {
    width: 68px;
}

.tx-sidebar-collapsed .tx-sidebar-brand-text,
.tx-sidebar-collapsed .tx-nav-group-label,
.tx-sidebar-collapsed .tx-nav-link-text,
.tx-sidebar-collapsed .tx-nav-soon {
    display: none;
}

.tx-sidebar-collapsed .tx-sidebar-footer {
    justify-content: center;
}

.tx-sidebar-collapsed .tx-sidebar-collapse-btn i {
    transform: rotate(180deg);
    display: inline-block;
}

/* Mobile — off-canvas sidebar. */
@media (max-width: 767.98px) {
    .tx-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        z-index: 1050;
        width: 280px;
        transform: translateX(-100%);
        box-shadow: var(--tx-shadow-lg);
    }

    .tx-sidebar-collapsed .tx-sidebar {
        /* Collapsed state is a desktop/tablet-only concept — ignored on mobile. */
        width: 280px;
    }

    .tx-sidebar-collapsed .tx-sidebar-brand-text,
    .tx-sidebar-collapsed .tx-nav-group-label,
    .tx-sidebar-collapsed .tx-nav-link-text,
    .tx-sidebar-collapsed .tx-nav-soon {
        display: initial;
    }

    .tx-sidebar-footer {
        display: none;
    }

    .tx-sidebar-open .tx-sidebar {
        transform: translateX(0);
    }

    .tx-sidebar-open .tx-sidebar-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.5);
        z-index: 1040;
    }

    .tx-content {
        padding: 1rem;
    }

    .tx-profile-info {
        display: none !important;
    }
}

/* ---------------------------------------------------------------
   Storefront entrance/feedback animations — flash messages, page
   content, the cart badge, and the WhatsApp button all get a small,
   deliberate motion cue rather than appearing inertly, matching the
   product-card stagger-in above. Covered by the reduced-motion block
   below like everything else in this file.
   --------------------------------------------------------------- */
.tx-flash-in {
    animation: tx-flash-in 350ms cubic-bezier(0.4, 0, 0.2, 1) both;
}
@keyframes tx-flash-in {
    from { opacity: 0; transform: translateY(-8px); }
    to   { opacity: 1; transform: translateY(0); }
}

.tx-page-fade-in {
    animation: tx-page-fade-in 400ms cubic-bezier(0.4, 0, 0.2, 1) both;
}
@keyframes tx-page-fade-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}

.tx-cart-badge {
    animation: tx-badge-pop 420ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.tx-whatsapp-fab {
    position: fixed;
    right: 1.25rem;
    bottom: 1.25rem;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: 50%;
    background: #25D366;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--tx-shadow, 0 2px 10px rgba(0, 0, 0, .25));
    z-index: 1050;
    font-size: 1.5rem;
    animation: tx-whatsapp-in 500ms cubic-bezier(0.34, 1.56, 0.64, 1) 300ms both,
               tx-whatsapp-pulse 2.4s ease-in-out 1.2s 3;
    transition: transform var(--tx-transition), box-shadow var(--tx-transition);
}
.tx-whatsapp-fab:hover {
    color: #fff;
    transform: scale(1.08);
    box-shadow: 0 4px 16px rgba(0, 0, 0, .35);
}
/* Clears the fixed bottom tab bar on phones instead of sitting behind it. */
@media (max-width: 767.98px) {
    .tx-whatsapp-fab {
        bottom: calc(4.75rem + env(safe-area-inset-bottom, 0px));
    }
}

/* ---------------------------------------------------------------
   Mobile bottom tab bar — the storefront's real "native app" nav:
   phones get 5 persistent icon+label tabs instead of the desktop
   text-link row (see layouts/shop.php / layouts/app.php's customer
   branch), which had no collapse mechanism at all below md and just
   wrapped every link into a cramped row.
   --------------------------------------------------------------- */
.tx-bottom-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1040;
    display: flex;
    background: var(--tx-navbar-bg);
    border-top: 1px solid var(--tx-navbar-border-bottom);
    box-shadow: 0 -2px 10px rgba(0, 0, 0, .12);
    padding-bottom: env(safe-area-inset-bottom, 0px);
}
.tx-bottom-nav-item {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .15rem;
    padding: .5rem 0 .4rem;
    color: var(--tx-navbar-color) !important;
    opacity: .68;
    text-decoration: none;
    font-size: .68rem;
    line-height: 1;
    transition: opacity var(--tx-transition), transform var(--tx-transition), color var(--tx-transition);
}
.tx-bottom-nav-item:active {
    transform: scale(0.92);
}
.tx-bottom-nav-icon {
    position: relative;
    font-size: 1.25rem;
    line-height: 1;
}
.tx-bottom-nav-badge {
    position: absolute;
    top: -.4rem;
    right: -.6rem;
    font-size: .55rem;
    padding: .2rem .35rem;
}
.tx-bottom-nav-active {
    opacity: 1;
    color: var(--bs-primary) !important;
}
.tx-bottom-nav-active .tx-bottom-nav-icon {
    animation: tx-badge-pop 320ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

/* Keeps page content (and the WhatsApp button, handled above) clear
   of the fixed bar's height + notch inset. */
.tx-has-bottom-nav {
    padding-bottom: calc(4.5rem + env(safe-area-inset-bottom, 0px));
}
@media (min-width: 768px) {
    .tx-has-bottom-nav {
        padding-bottom: 0;
    }
}
@keyframes tx-whatsapp-in {
    from { opacity: 0; transform: scale(0.5) translateY(12px); }
    to   { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes tx-whatsapp-pulse {
    0%, 100% { box-shadow: 0 2px 10px rgba(0, 0, 0, .25), 0 0 0 0 rgba(37, 211, 102, .5); }
    50%      { box-shadow: 0 2px 10px rgba(0, 0, 0, .25), 0 0 0 8px rgba(37, 211, 102, 0); }
}

/* ---------------------------------------------------------------
   Reduced motion — every hover transform/transition in this file (card
   lift, wishlist-button scale, sidebar slide, theme-switch colour
   fade) is disabled for users who've asked the OS for less motion,
   rather than tuned down piecemeal per rule.
   --------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}
