/*
Theme Name: Khomfy Essence
Template: blocksy
Version: 1.0.0
Text Domain: khomfy
*/

/*
 * Khomfy Essence Design System
 * Ported from Context/Assets/khomfy-essence.css (rev 14).
 * Components consume semantic tokens. Semantic tokens consume primitives.
 *
 * rev 15 — see CHANGELOG.md.
 * Which token to reach for: F1 §6, F2 §5, F3 §5, F5 §8, F6 §8.
 * Recorded exceptions (the only literal values permitted in this file):
 *   --header-height mobile 74px  — F4 §8, deliberately off the spacing ramp
 *   --surface-raised dark #291105, --surface-sunken dark #090301,
 *   --surface-brand-subtle dark #2C1205, --link-hover-bg dark #2C1205,
 *   Page canvas is Blush 50 (F1 §2) and the header band sits on the same
 *   canvas — no deviation from the system here.
 *   surface.default/raised/floating/modal light #FFFFFF  — F1 §2
 *   .button-primary--sm hit-area inset 4px  — F3 §6 pad-the-hit-area
 *   .status min-height 32px  — F1/T1 §6, non-tappable by definition
 */

/* PP Neue Montreal — self-hosted in themes/khomfy/fonts/ (Build Guide §6.3).
   Fonts live here, not on a CDN: metered data and no external dependency. */
@font-face {
  font-family: "PP Neue Montreal";
  src: url("fonts/ppneuemontreal-book.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "PP Neue Montreal";
  src: url("fonts/ppneuemontreal-medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "PP Neue Montreal";
  src: url("fonts/ppneuemontreal-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "PP Neue Montreal";
  src: url("fonts/ppneuemontreal-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

:root {
  color-scheme: light;

  /* Read by the showroom to detect a stale stylesheet. Bump on every release. */
  --essence-rev: 15;

  /* Primitive colour ramps */
  --clay-50: #F9F4F1; --clay-100: #F0E3DD; --clay-200: #DDC5B9;
  --clay-300: #C4A190; --clay-400: #A57761; --clay-500: #84543C;
  --clay-600: #663923; --clay-700: #4A2511; --clay-800: #331607;
  --clay-900: #1F0C03; --clay-950: #0F0502;

  --blush-50: #FEF6F3; --blush-100: #FBE6DF; --blush-200: #F4CCC0;
  --blush-300: #EBB09E; --blush-400: #E0917A; --blush-500: #D1735A;
  --blush-600: #B85B44; --blush-700: #973F2F; --blush-800: #742C21;
  --blush-900: #4E1B14; --blush-950: #33100C;

  --red-50: #FDF2F2; --red-100: #FAE0E0; --red-200: #F2BDBD;
  --red-300: #E79595; --red-400: #D96666; --red-500: #C13B3B;
  --red-600: #A32E2E; --red-700: #872525; --red-800: #6E1C1C;
  --red-900: #4A1212; --red-950: #2E1414;

  --gold-50: #FDF8E9; --gold-100: #F9EFCE; --gold-200: #EFDCA0;
  --gold-300: #E0C46B; --gold-400: #C9A63A; --gold-500: #B08D1E;
  --gold-600: #96700F; --gold-700: #7A5C0C; --gold-800: #5E4608;
  --gold-900: #40300A; --gold-950: #2A2008;

  --sage-50: #F1F5EF; --sage-100: #DFE9DC; --sage-200: #C8D8C2;
  --sage-300: #A9C9AE; --sage-400: #7FA986; --sage-500: #5F8A66;
  --sage-600: #4F7A55; --sage-700: #3D5F42; --sage-800: #2F4A33;
  --sage-900: #243A28; --sage-950: #16211A;

  --blue-50: #EFF4F6; --blue-100: #DAE6EB; --blue-200: #C2D4DB;
  --blue-300: #9CBCCA; --blue-400: #7FAEC2; --blue-500: #5A8CA1;
  --blue-600: #3E6B7D; --blue-700: #305565; --blue-800: #274453;
  --blue-900: #1C3642; --blue-950: #142027;

  /* Gradient primitives — stop pairs only, angle applied at the call site */
  --grad-blush-50-100: var(--blush-50), var(--blush-100);
  --grad-blush-200-300: var(--blush-200), var(--blush-300);
  --grad-blush-50-200: var(--blush-50), var(--blush-200);
  --grad-blush-200-400: var(--blush-200), var(--blush-400);
  --grad-clay-950-900: var(--clay-950), var(--clay-900);
  --grad-clay-900-700: var(--clay-900), var(--clay-700);
  --grad-clay-800-700: var(--clay-800), var(--clay-700);
  --grad-clay800-blush700: var(--clay-800), var(--blush-700);
  --grad-clay950-blush900: var(--clay-950), var(--blush-900);

  /* Typography primitives */
  --display-xl: 38px; --display-lg: 32px; --display-md: 26px; --display-sm: 22px;
  --text-xl: 20px; --text-lg: 18px; --text-md: 16px; --text-sm: 14px; --text-xs: 12px;
  --lh-display-xl: 1.05; --lh-display-lg: 1.10; --lh-display-md: 1.15; --lh-display-sm: 1.20;
  --lh-text-xl: 1.50; --lh-text-lg: 1.40; --lh-text-md: 1.60; --lh-text-sm: 1.50; --lh-text-xs: 1.30;
  --tr-display-xl: -0.03em; --tr-display-lg: -0.025em; --tr-display-md: -0.02em; --tr-display-sm: -0.015em;
  --tr-text-xl: -0.01em; --tr-text-lg: 0; --tr-text-md: 0; --tr-text-sm: 0.005em; --tr-text-xs: 0.08em;
  --weight-regular: 400; --weight-medium: 500; --weight-bold: 700;
  --measure: 560px;

  /* Space, shape, and layout primitives */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
  --space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px;
  --space-12: 48px; --space-16: 64px; --space-20: 80px; --space-24: 96px; --space-32: 128px;
  --radius-none: 0; --radius-sm: 4px; --radius-full: 999px;
  --border-width-hairline: 1px; --border-width-default: 1.5px; --border-width-strong: 2px;
  --focus-offset: 2px;
  --container-max: 1200px; --grid-columns: 4; --grid-gutter: var(--space-4); --grid-margin: var(--space-4);
  --header-height: 74px;               /* recorded exception — F4 §8 */
  --announce-height: var(--space-12);  /* 48px mobile */
  --space-section: var(--space-16); --space-section-major: var(--space-24);
  --space-block: var(--space-10); --space-stack: var(--space-4); --space-stack-tight: var(--space-2);
  --space-inline: var(--space-2); --space-card: var(--space-4); --space-control: var(--space-3);

  /* Control geometry — one drawn height per size, hit area always 44px */
  --control-height-sm: 36px;
  --control-height-md: 40px;
  --control-height-lg: 44px;   /* the default — the 44px tap target */
  --control-height-xl: 48px;
  --control-height: var(--control-height-lg);

  /* Media and icon primitives */
  --ratio-portrait: 4 / 5; --ratio-editorial: 3 / 4; --ratio-square: 1 / 1; --ratio-wide: 16 / 9;
  --icon-sm: 16px; --icon-md: 20px; --icon-lg: 24px; --icon-stroke: 1.5;

  /* Depth and motion primitives */
  --shadow-none: none;
  --shadow-raised: 0 1px 3px rgb(42 23 16 / 0.06);
  --shadow-overlay: 0 2px 6px rgb(42 23 16 / 0.06), 0 12px 32px rgb(42 23 16 / 0.10);
  --scrim: rgb(42 23 16 / 0.45);   /* supersedes F1 §2 surface.overlay — see CHANGELOG T1 */
  --z-base: 0; --z-raised: 10; --z-sticky: 100; --z-scrim: 200; --z-overlay: 300; --z-toast: 400;
  --duration-instant: 0ms; --duration-fast: 150ms; --duration-base: 250ms; --duration-slow: 350ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1); --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); --ease-in: cubic-bezier(0.4, 0, 1, 1);
  --ease-anticipate: cubic-bezier(0.68, -0.02, 0.32, 1);   /* anticipation — ~1.6px wind-back before firing (header reveal) */
  --transition-control: var(--duration-fast) var(--ease-out);
  --transition-surface: var(--duration-base) var(--ease-out);
  --transition-overlay: var(--duration-slow) var(--ease-out);
  --transition-dismiss: var(--duration-fast) var(--ease-in);

  /* PP Neue Montreal is the single brand family (F2). Blocksy types everything
     via --theme-font-family, so point it at the self-hosted face. */
  --theme-font-family: "PP Neue Montreal", "Helvetica Neue", sans-serif;

  /* Blocksy registers PP Neue Montreal with the block editor as a WP font
     preset, but ships the preset with no fallback ("PP Neue Montreal" alone).
     Re-state the stack so a failed load or a missing glyph does not drop to
     the browser default serif. */
  --wp--preset--font-family--pp-neue-montreal: "PP Neue Montreal", "Helvetica Neue", sans-serif;
}

@media (min-width: 768px) {
  :root {
    --display-xl: 64px; --display-lg: 48px; --display-md: 36px; --display-sm: 28px;
    --text-xl: 21px; --text-lg: 19px; --text-md: 17px;
    --grid-columns: 6; --grid-gutter: var(--space-6); --grid-margin: var(--space-8);
    --header-height: var(--space-20);    /* 80px — closes F3 open item 4 */
    --announce-height: var(--space-10);  /* 40px */
    --space-section: var(--space-24); --space-section-major: var(--space-32);
    --space-block: var(--space-12); --space-card: var(--space-6);
  }
}

@media (min-width: 1200px) {
  :root { --grid-columns: 12; --grid-gutter: var(--space-8); }
}

/* Semantic theme layer */
:root, [data-theme="light"] {
  --surface-canvas: var(--blush-50); --surface-default: #FFFFFF; --surface-raised: #FFFFFF;
  --surface-floating: #FFFFFF; --surface-modal: #FFFFFF; --surface-sunken: var(--blush-100);
  --surface-brand: var(--blush-200); --surface-brand-subtle: var(--blush-100); --surface-brand-strong: var(--clay-700);
  /* Translucent header veil — Blush 50 at 20%. The sticky header rises on a
     soft wash rather than a solid block, so the blush logo/text stay on the
     same treatment in both states (requested 2 Oct 2026). */
  --surface-veil: color-mix(in srgb, var(--surface-canvas) 20%, transparent);
  --text-primary: var(--clay-900); --text-secondary: var(--clay-600); --text-tertiary: var(--clay-500);
  --text-muted: var(--clay-400); --text-inverse: var(--blush-50); --text-brand: var(--blush-700); --text-on-brand: var(--clay-900);
  --border-subtle: var(--clay-100); --border-default: var(--clay-200); --border-strong: var(--clay-400);
  --border-on-brand: var(--clay-500); --border-brand: var(--blush-400);
  --action-primary: var(--clay-700); --action-primary-hover: var(--clay-800); --action-primary-active: var(--clay-900); --action-primary-text: var(--blush-50);
  --action-disabled-bg: var(--clay-100); --action-disabled-text: var(--clay-400);
  --link-default: var(--clay-700); --link-hover: var(--clay-900); --link-hover-bg: var(--blush-100); --link-disabled: var(--clay-400);
  --focus-ring: var(--blush-700);
  --chart-series-1: var(--clay-700); --chart-series-2: var(--blush-500); --chart-series-3: var(--blue-600); --chart-series-4: var(--sage-600); --chart-series-5: var(--gold-600);
  --chart-grid: var(--clay-100); --chart-axis: var(--clay-400);
  --error-surface: var(--red-50); --error-border: var(--red-200); --error-icon: var(--red-600); --error-text: var(--red-700); --error-strong: var(--red-900);
  --warning-surface: var(--gold-50); --warning-border: var(--gold-200); --warning-icon: var(--gold-600); --warning-text: var(--gold-700); --warning-strong: var(--gold-900);
  --success-surface: var(--sage-50); --success-border: var(--sage-200); --success-icon: var(--sage-600); --success-text: var(--sage-700); --success-strong: var(--sage-900);
  --info-surface: var(--blue-50); --info-border: var(--blue-200); --info-icon: var(--blue-600); --info-text: var(--blue-700); --info-strong: var(--blue-900);
  --gradient-surface-subtle: var(--grad-blush-50-100); --gradient-surface-inverse: var(--grad-clay-900-700); --gradient-brand: var(--grad-blush-200-300);
  --gradient-mkt-wash: var(--grad-blush-50-200); --gradient-mkt-warm: var(--grad-blush-200-400); --gradient-mkt-deep: var(--grad-clay800-blush700); --gradient-mkt-night: var(--grad-clay950-blush900);
}

[data-theme="dark"] {
  color-scheme: dark;
  --surface-canvas: var(--clay-950); --surface-default: var(--clay-900); --surface-raised: #291105;
  --surface-floating: var(--clay-800); --surface-modal: var(--clay-800); --surface-sunken: #090301;
  --surface-brand: var(--clay-800); --surface-brand-subtle: #2C1205; --surface-brand-strong: var(--blush-200);
  --text-primary: var(--blush-50); --text-secondary: var(--clay-200); --text-tertiary: var(--clay-300); --text-muted: var(--clay-400);
  --text-inverse: var(--clay-900); --text-brand: var(--blush-300); --text-on-brand: var(--clay-900);
  --border-subtle: var(--clay-800); --border-default: var(--clay-700); --border-strong: var(--clay-400); --border-on-brand: var(--clay-400); --border-brand: var(--blush-500);
  --action-primary: var(--blush-200); --action-primary-hover: var(--blush-100); --action-primary-active: var(--blush-300); --action-primary-text: var(--clay-900);
  --action-disabled-bg: var(--clay-800); --action-disabled-text: var(--clay-600);
  --link-default: var(--blush-200); --link-hover: var(--blush-100); --link-hover-bg: #2C1205; --link-disabled: var(--clay-600); --focus-ring: var(--blush-300);
  --chart-series-1: var(--blush-200); --chart-series-2: var(--blush-400); --chart-series-3: var(--blue-400); --chart-series-4: var(--sage-400); --chart-series-5: var(--gold-300);
  --chart-grid: var(--clay-800); --chart-axis: var(--clay-500);
  --error-surface: var(--red-950); --error-border: var(--red-800); --error-icon: var(--red-300); --error-text: var(--red-200); --error-strong: var(--red-100);
  --warning-surface: var(--gold-950); --warning-border: var(--gold-800); --warning-icon: var(--gold-300); --warning-text: var(--gold-200); --warning-strong: var(--gold-100);
  --success-surface: var(--sage-950); --success-border: var(--sage-800); --success-icon: var(--sage-400); --success-text: var(--sage-300); --success-strong: var(--sage-100);
  --info-surface: var(--blue-950); --info-border: var(--blue-800); --info-icon: var(--blue-400); --info-text: var(--blue-300); --info-strong: var(--blue-100);
  --gradient-surface-subtle: var(--grad-clay-950-900); --gradient-surface-inverse: var(--grad-clay-900-700); --gradient-brand: var(--grad-clay-800-700);
}

/* --------------------------------------------------------------------------
   Blocksy bridge — point the Customizer's theme variables at the system.
   Blocksy types everything through --theme-* variables resolved at :root by
   its dynamic global.css, which loads BEFORE this file. Re-declaring them on
   :root here makes the whole page resolve from the design tokens. No hexes:
   every value is a var(--). Lift-off: Blocksy's defaults run #2872fa blue,
   #FAFBFC canvas and #3A4F66 text — countered here token-for-token.
-------------------------------------------------------------------------- */
:root {
  /* Palette slots. Blocksy's defaults 1–5 are blue/slate (#2872fa, #1559ed,
     #3A4F66, #192a3d, #e1e8ed) and leak into links, active tabs, badges and
     form accents. Point every slot at the system so no blue survives. */
  --theme-palette-color-1: var(--action-primary);        /* accent — links, active tabs */
  --theme-palette-color-2: var(--action-primary-hover);  /* accent hover */
  --theme-palette-color-3: var(--text-primary);          /* body text */
  --theme-palette-color-4: var(--text-primary);          /* headings */
  --theme-palette-color-5: var(--border-subtle);         /* dividers, borders */
  --theme-palette-color-6: var(--surface-brand-subtle);  /* Blush 100 */
  --theme-palette-color-7: var(--surface-canvas);        /* Blush 50 */
  --theme-palette-color-8: var(--surface-default);       /* white */

  /* Text */
  --theme-text-color: var(--text-primary);
  --theme-headings-color: var(--text-primary);

  /* Links — Blocksy's real variables are --theme-link-initial-color / -hover /
     -active. Earlier revisions set --theme-link-color, which Blocksy never
     reads, leaving the default blue in place. */
  --theme-link-initial-color: var(--link-default);
  --theme-link-hover-color: var(--link-hover);
  --theme-link-active-color: var(--action-primary);

  /* Borders */
  --theme-border-color: var(--border-subtle);

  /* Primary action — the button lifecycle maps onto Blocksy's own vars */
  --theme-button-text-initial-color: var(--action-primary-text);
  --theme-button-text-hover-color: var(--action-primary-text);
  --theme-button-background-initial-color: var(--action-primary);
  --theme-button-background-hover-color: var(--action-primary-hover);

  /* Selection — Clay 700 ground, Blush 50 text */
  --theme-selection-text-color: var(--action-primary-text);
  --theme-selection-background-color: var(--action-primary);
}

/* --------------------------------------------------------------------------
   Theme integration — Blocksy structure reconciled with the design system.
   Blocksy's breakpoints are 690 / 1000; the system's are 768 / 1200 (F4 §1).
   The shop grid is the one place the mismatch is visible, so it is overridden
   here at the system tiers. Everything else is identity layer on Blocksy's
   own markup — never a change to the layout mechanism.
-------------------------------------------------------------------------- */

/* Shop grid -------------------------------------------------------------
   Blocksy sets --shop-columns on [data-products] via .columns-N in
   woocommerce.min.css (which loads AFTER this file) at ≥1000px, and via its
   dynamic CSS at 690/1000. ul.products[data-products] (0,2,1) out-specifies
   [data-products].columns-N (0,2,0), so the system tiers win. Orphan cards
   left-align by default — no centering rule is added. */
[data-products] {
	--shop-columns: repeat(1, minmax(0, 1fr));
}

@media (min-width: 768px) {
	ul.products[data-products] {
		--shop-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1200px) {
	ul.products[data-products] {
		--shop-columns: repeat(3, minmax(0, 1fr));
	}
}

/* Header — identity layer ---------------------------------------------- */

/* Height: our token is 74 mobile / 80 desktop (F4 §8). Blocksy shadows
   --header-height on <body data-header> with 120/70 and drives the row with
   --height, so re-assert ours and point the row at it. */
[data-header*="type-1"] {
	--header-height: 74px; /* mobile — recorded exception, F4 §8 */
}

@media (min-width: 768px) {
	[data-header*="type-1"] {
		--header-height: var(--space-20); /* 80px */
	}
}

[data-header*="type-1"] .ct-header [data-row*="middle"] {
	--height: var(--header-height);
	--theme-border-bottom: var(--border-width-hairline) solid var(--border-subtle);
	background-color: var(--surface-canvas);
	position: relative;
	/* Paint extension above the row to cover the ~1.6px recline gap during
	   auto-hide. Sits off-screen at rest in every header state (including
	   the transparent-over-hero state A); enters the viewport only during
	   the wind-back, filling the strip with the header's ground. The ::before is a
	   real paint layer, not a box-shadow, so the Blocksy #header [data-row]
	   box-shadow override (which would beat a host-level shadow) doesn't
	   reach it. pointer-events:none so the 12px strip never blocks clicks. */
}
[data-header*="type-1"] .ct-header [data-row*="middle"]::before {
	content: "";
	position: absolute;
	top: -12px;
	left: 0;
	right: 0;
	height: 12px;
	background: var(--surface-canvas);
	pointer-events: none;
}

/* Filled / sticky header — Blocksy paints its sticky row with
   --theme-palette-color-8 (white) via [data-sticky*="yes"], at a specificity
   the base row rule does not beat. Re-assert the branded ground so the
   Blush 50 nav stays legible when the header reveals on scroll-up. */
[data-header*="type-1"] .ct-header [data-sticky*="yes"] [data-row*="middle"] {
	background-color: var(--surface-canvas);
	--theme-border-bottom: var(--border-width-hairline) solid var(--border-subtle);
}

/* Non-home pages never go transparent — force the ground even where Blocksy
   marks a row transparent, so the header is always readable there. */
body:not(.home)[data-header*="type-1"] .ct-header [data-transparent-row="yes"][data-row*="middle"] {
	background-color: var(--surface-canvas);
	--theme-border-bottom: var(--border-width-hairline) solid var(--border-subtle);
}

/* Logo — every page except the homepage carries the brown wordmark, because
   the header sits on Blush 50 where the light logo would vanish. The light
   SVG stays as the <img> (it is the Blocksy logo and the homepage mark);
   elsewhere it is hidden and the Clay 700 wordmark is painted behind it, so
   the box and layout are unchanged. */
body:not(.home) .ct-header .site-logo-container .default-logo {
	visibility: hidden;
}
body:not(.home) .ct-header .site-logo-container {
	background-image: url("assets/logo-clay-700.svg");
	background-repeat: no-repeat;
	background-position: center;
	background-size: contain;
}

/* Mobile trigger icon follows the same rule: brown on the light ground. */
body:not(.home) .ct-header .ct-header-trigger {
	color: var(--text-primary);
	--theme-icon-color: var(--text-primary);
}

/* Nav labels — type.label: the brand's characteristic 12px tracked cap.
   Default resting colour is text.secondary (Clay 600) per F1 §6; hover
   action.primary.hover, active action.primary. The homepage swaps these to the
   blush ramp further down. */
.ct-header .menu-container .ct-menu-link {
	font-size: var(--text-xs);
	font-weight: var(--weight-medium);
	letter-spacing: var(--tr-text-xs);
	text-transform: uppercase;
	color: var(--text-secondary);
}

.ct-header .menu-container .ct-menu-link:hover {
	color: var(--action-primary-hover);
}

.ct-header .menu-container li.current-menu-item > a.ct-menu-link,
.ct-header .menu-container li.current_page_item > a.ct-menu-link {
	color: var(--action-primary);
}

/* Focus ring — outline + offset, never box-shadow (stripped in Windows
   High Contrast mode). */
.ct-header .menu-container .ct-menu-link:focus-visible {
	outline: var(--border-width-strong) solid var(--focus-ring);
	outline-offset: var(--focus-offset);
}

/* Homepage only — the transparent-over-hero treatment. Blush logo and nav text
   in both states; only the ground changes: transparent at the top, a 20% Blush
   50 veil when the header reveals on scroll-up. No hairline. */
.home [data-header*="type-1"] .ct-header [data-row*="middle"] {
	--theme-border-bottom: none;
	background-color: var(--surface-veil);
}
.home [data-header*="type-1"] .ct-header [data-transparent-row="yes"][data-row*="middle"] {
	background-color: transparent;
}
.home [data-header*="type-1"] .ct-header [data-sticky*="yes"] [data-row*="middle"] {
	background-color: var(--surface-veil);
}
.home [data-header*="type-1"] .ct-header [data-row*="middle"]::before {
	background: var(--surface-veil);
}
.home .ct-header .menu-container .ct-menu-link {
	color: var(--text-inverse);
}
.home .ct-header .menu-container .ct-menu-link:hover {
	color: var(--blush-100);
}
.home .ct-header .menu-container li.current-menu-item > a.ct-menu-link,
.home .ct-header .menu-container li.current_page_item > a.ct-menu-link {
	color: var(--blush-200);
}
.home .ct-header .menu-container .ct-menu-link:focus-visible {
	outline-color: var(--blush-300);
}
.home .ct-header .ct-header-trigger {
	color: var(--text-inverse);
	--theme-icon-color: var(--text-inverse);
}

/* Header scroll states (D32) ---------------------------------------------
   Blocksy native sticky auto-hide drives the transform. This layer adds the
   motion: a smooth transition with anticipation (a ~1.6px wind-back before
   the header fires — tuned down from 6.4px). The transition targets the
   sticky container — that is what Blocksy's JS transforms, not .ct-header. */
[data-sticky] {
	transition: transform var(--duration-base) var(--ease-anticipate);
	will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
	[data-sticky] {
		transition: none;
	}
}

/* Homepage page header — removed entirely. The hero video carries the page
   top, flush under the transparent header (D38). Blocksy's page title band
   renders the duplicate "Homepage" H1; hiding only the title left an empty
   .hero-section still carrying `margin-bottom: 40px` (page-title.min.css,
   [data-type="type-1"]), and that margin was the stray 40px band above the
   hero. Hiding the empty section removes both the duplicate title and the
   gap. Homepage only — other pages keep their title band. */
.home .hero-section {
	display: none;
}

/* Hero content sits in the site container. The cover stays full-bleed (the
   video bleeds edge to edge), but its inner content takes the same width and
   centring as Blocksy's .ct-container — 90vw capped at the container max — so
   the tagline and CTA start on the nav's left edge and the content spans the
   container. The tagline's line break is authored (<br>), so width does not
   change the wrap. Scoped to the homepage, the only full-bleed cover.

   `.alignfull` is not decoration: WordPress's own
   `.wp-block-cover.has-custom-content-position.has-custom-content-position
   .is-position-bottom-left .wp-block-cover__inner-container { width: auto }`
   is (0,5,0), so the extra class ties it and source order lets this rule win. */
.home .entry-content > .wp-block-cover.alignfull > .wp-block-cover__inner-container {
	width: var(--theme-container-width);
	max-width: var(--theme-normal-container-max-width);
	margin-inline: auto;
}

/* Full-bleed Group: the block stays edge to edge (so a background would still
   bleed), but its content aligns to the site container. Needed because
   WordPress's wide-size preset is unset here, so a Product Collection set to
   `alignwide` has nothing to cap against and resolves to the full group
   width. Mirrors Blocksy's .ct-container geometry (90vw capped at the
   container max, centred). */
.entry-content > .wp-block-group.alignfull {
	padding-inline: calc((100% - min(var(--theme-container-width), var(--container-max))) / 2);
}

/* Shop archive — no title banner. Blocksy's page title carries a photo Cover
   block; the products should lead the page instead. (D82, revised.) */
.woocommerce-shop .hero-section {
	display: none;
}

/* The header is overlaid on non-home pages (Blocksy's transparent-header
   structure), and the page-title band does not clear it on pages without a
   photo hero — so the top of the title was being clipped (shop, about, FAQ,
   blog, single posts). Give the content the header's clearance. The homepage
   is excluded: its hero is deliberately flush beneath the header. */
body:not(.home) .site-main {
	padding-top: calc(var(--header-height) + var(--border-width-hairline));
}

/* Product cards — the design-system card spec (Tier 1 §5, D70). Applied to the
   shop archive loop and the homepage Product Collection alike so the grid
   reads identically in both: no container, title text.lg/500, price text.lg/700
   in text.brand, imagery radius.none, and the CTA as the outline primary pill
   (the browsing state — solid is reserved for the point of purchase, D29). */
.woocommerce ul.products li.product .woocommerce-loop-product__title,
.wp-block-woocommerce-product-collection .wc-block-product .wp-block-post-title {
	font-size: var(--text-lg);
	line-height: var(--lh-text-lg);
	font-weight: var(--weight-medium);
}

.woocommerce ul.products li.product .price,
.wp-block-woocommerce-product-collection .wc-block-product .price,
.wp-block-woocommerce-product-collection .wc-block-product .woocommerce-Price-amount {
	font-size: var(--text-lg);
	line-height: var(--lh-text-lg);
	font-weight: var(--weight-bold);
	color: var(--text-brand);
	font-variant-numeric: tabular-nums lining-nums;
}

.woocommerce ul.products li.product img,
.woocommerce ul.products li.product .ct-media-container,
.wp-block-woocommerce-product-collection .wc-block-product img {
	border-radius: var(--radius-none);
}

.woocommerce ul.products li.product a.button {
	background: transparent;
	border: var(--border-width-default) solid var(--action-primary);
	color: var(--action-primary);
	border-radius: var(--radius-full);
}

.woocommerce ul.products li.product a.button:hover {
	background: var(--action-primary);
	border-color: var(--action-primary);
	color: var(--action-primary-text);
}

/* Button component — type.label + the primary shape (Components Tier 1 §1).
   The design system's component classes are not ported into the theme, so
   WordPress and WooCommerce buttons are typed and shaped here: 12px tracked
   caps at weight 500, never scaling with the control, and a pill. Colour is
   set per instance — outline while browsing, solid at the point of purchase. */
.wp-block-button__link,
.woocommerce a.button,
.woocommerce button.button,
.woocommerce input.button,
.woocommerce #respond input#submit,
.woocommerce .wc-block-components-button,
.ct-button {
	font-family: var(--theme-font-family);
	font-size: var(--text-xs);
	font-weight: var(--weight-medium);
	letter-spacing: var(--tr-text-xs);
	text-transform: uppercase;
	line-height: var(--lh-text-xs);
	border-radius: var(--radius-full);
}

/* Block buttons default to the outline primary — the browsing state (D29). The
   hero and card CTAs already carry WordPress's Outline style; this catches any
   block button that does not, so a marketing CTA (e.g. "Made for good company")
   reads outline rather than a solid fill. */
.wp-block-button:not(.is-style-outline) .wp-block-button__link {
	background: transparent;
	border: var(--border-width-default) solid var(--action-primary);
	color: var(--action-primary);
}
.wp-block-button:not(.is-style-outline) .wp-block-button__link:hover {
	background: var(--action-primary);
	border-color: var(--action-primary);
	color: var(--action-primary-text);
}

/* Block outline buttons take the system border (1.5px), not WordPress's 2px
   Outline default, so the homepage "Buy" CTA matches the store loop's CTA. */
.wp-block-button.is-style-outline .wp-block-button__link {
	border-width: var(--border-width-default);
}

/* Control shapes — WooCommerce product page. Inputs and selects take
   radius.sm (Tier 1 §3); the primary action is a pill (Tier 1 §1). */
/* The quantity is WooCommerce's type-2 stepper. Blocksy rounds its input via
   `--theme-form-field-border-radius` with !important, so the shape is set on
   that variable (not a border-radius on the input) — a pill to match the
   Add to cart action. The +/- steppers inherit the same variable and become
   circles. */
.woocommerce .quantity,
.woocommerce div.product form.cart .quantity {
	--theme-form-field-border-radius: var(--radius-full);
	border-radius: var(--radius-full);
	overflow: hidden;
}
.woocommerce div.product form.cart .single_add_to_cart_button,
.woocommerce .single_add_to_cart_button.button {
	border-radius: var(--radius-full);
}

/* Chip — a selectable option (Tier 1 §4). Used for the product variation
   attributes; the native variation <select> is hidden and driven by these. */
.khomfy-native-select {
	display: none;
}
.khomfy-chips {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
}
.chip {
	display: inline-flex;
	align-items: center;
	gap: var(--space-1);
	min-height: var(--control-height);
	padding-inline: var(--space-4);
	border: var(--border-width-default) solid var(--border-on-brand);
	border-radius: var(--radius-full);
	background: var(--surface-default);
	color: var(--text-primary);
	font-size: var(--text-sm);
	line-height: var(--lh-text-sm);
	letter-spacing: var(--tr-text-sm);
	font-weight: var(--weight-medium);
	cursor: pointer;
	transition: border-color var(--transition-control), background-color var(--transition-control), color var(--transition-control);
}
/* Hover adds a fill, not only a stroke. */
.chip:hover {
	background: var(--surface-sunken);          /* Blush 100 */
	border-color: var(--action-primary);
}
/* Selection: the system's selected-state tint (Blush 100) with the brand
   action colour in the label plus weight. Supersedes Tier 1 §4's outline-only
   selected state (D79) — and its earlier solid Clay 700 fill. */
.chip[aria-pressed="true"] {
	background: var(--surface-brand-subtle);     /* Blush 100 */
	border-color: var(--action-primary);
	color: var(--action-primary);
	font-weight: var(--weight-bold);
}
/* Pressed — the tap equivalent of hover, required by F5 §6. One step deeper. */
.chip:active {
	background: var(--surface-brand);            /* Blush 200 */
	border-color: var(--action-primary);
	color: var(--action-primary);
}
.chip:disabled {
	border-color: var(--border-subtle);
	background: var(--action-disabled-bg);
	color: var(--action-disabled-text);
	opacity: 0.7;
	cursor: not-allowed;
}
.chip:focus-visible {
	outline: var(--border-width-strong) solid var(--focus-ring);
	outline-offset: var(--focus-offset);
}

/* WooCommerce "Clear" (reset variations) — a reset/destructive action, set in
   the system's dark red (F1 §2, Red 700), darkening to Red 800 on hover. */
.woocommerce .reset_variations {
	color: var(--red-700);
}
.woocommerce .reset_variations:hover {
	color: var(--red-800);
}

/* Footer — a single branded Clay 700 inverse block (D35). No dark mode,
   no theme swap. Light text and links resolve from tokens directly.
   .ct-footer.ct-footer (0,2,0) ties Blocksy's
   [data-footer*="type-1"] .ct-footer background rule and wins by source order. */
.ct-footer.ct-footer {
	background-color: var(--surface-brand-strong);
	color: var(--text-inverse);
}

.ct-footer .ct-widget a {
	color: var(--blush-200);
}

.ct-footer .ct-widget a:hover {
	color: var(--blush-100);
}

/* Column titles — type.label treatment */
.ct-footer .widget-title {
	font-size: var(--text-xs);
	font-weight: var(--weight-medium);
	letter-spacing: var(--tr-text-xs);
	text-transform: uppercase;
	color: var(--text-inverse);
}

/* Link lists — vertical rhythm, no bullets or default margins */
.ct-footer .ct-widget ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--space-stack-tight);
}

/* Copyright — text-xs, muted against the inverse ground */
.ct-footer .ct-footer-copyright {
	font-size: var(--text-xs);
	color: var(--blush-300);
}

/* Vertical padding — space-section (64 mobile / 96 desktop) */
.ct-footer [data-row="top"] {
	padding-block: var(--space-section);
}