/* =============================================================================
   FunkyFoliageCo Bloom — Main Stylesheet
   Tokens → Reset → Base → Layout → Header → Components → Sections → Footer
   ============================================================================= */

/* ─────────────────────────────────────────────
   1. DESIGN TOKENS

   The palette is taken from Bloomscape's own stylesheet, so the colour
   relationships match the reference rather than approximating it.
   Change a value here and it updates everywhere.
   ───────────────────────────────────────────── */

:root {
  /* ── Core palette ───────────────────────────────────────────────────────── */
  /*
   * Dark emerald, replacing the original muted forest green (#224229).
   * The whole family sits on the emerald hue (~162°) rather than the yellower
   * forest hue, so greens across the site read as one jewel tone.
   *
   * Every value here was picked against the cream ground, not by eye:
   *   --green-dark       9.25:1 with cream (both as text on cream, and as a
   *                      background carrying cream text in the footer)
   *   --green-grey       4.94:1 on cream, 4.62:1 on the peach sections
   *   --green-highlight  5.22:1 on cream
   */
  --green-dark:      #064E3B; /* Primary. Text, buttons, footer.               */
  --green-grey:      #55736A; /* Muted text, captions, meta.                   */
  --green-highlight: #047857; /* Links, focus, the default accent.             */
  --cream:           #FCF9F3; /* Page background.                              */
  --peach:           #F8F1E3; /* Tinted section background.                    */
  --banner:          #F6CFB2; /* Announcement bar, sale badges.                */
  --linen:           #EDE3D6; /* Card wells, image placeholders.               */
  --highlight:       #F2EADC; /* Hover fills.                                  */
  --white:           #FFFFFF;

  /*
   * Emerald — the value-props ticker band.
   *
   * One step lighter than --green-dark so the band separates from the footer
   * and newsletter panel rather than merging with them.
   *
   * Deliberately not a textbook emerald (#50C878) or Tailwind emerald-500.
   * Both look right in isolation but fail WCAG AA badly against the cream
   * text sitting on them (2.02:1 and 2.41:1 against a 4.5:1 requirement).
   * This is the brightest emerald that still passes: 5.22:1 with cream text
   * and 3.78:1 with the peach icons.
   */
  --emerald:         #047857;

  /* Derived transparencies — the reference site builds borders this way, which
     keeps them tinted with the brand green rather than a neutral grey.
     These are --green-dark at alpha, so they follow it when it changes. */
  --border:          rgba(6, 78, 59, 0.16);
  --border-strong:   rgba(6, 78, 59, 0.32);
  --green-light:     rgba(6, 78, 59, 0.72);

  /* ── Semantic aliases ───────────────────────────────────────────────────── */
  --bg:              var(--cream);
  --fg:              var(--green-dark);
  --fg-muted:        var(--green-grey);
  --accent:          var(--green-highlight);
  --accent-contrast: var(--cream);

  --error:           #B3261E;
  --success:         #018342;

  /* ── Vertical accents ───────────────────────────────────────────────────── */
  /*
   * Rebound per-vertical by the body / card classes further down.
   *
   * The clay and amber were darkened from #B4643C and #BE7B33. Both render as
   * small uppercase text — the product-card category eyebrow and the tile CTA
   * — where they scored 4.14:1 and 3.29:1 on cream, under the 4.5:1 minimum.
   * These variants keep the same hue and read as the same colours, at 5.49:1
   * and 4.95:1.
   */
  --accent-plants:   #047857; /* Greenhouse emerald */
  --accent-pots:     #9B5230; /* Fired clay         */
  --accent-reptiles: #9A5F22; /* Desert amber       */

  /* ── Typography ─────────────────────────────────────────────────────────── */
  /* Free stand-ins for Bloomscape's licensed Circular / Nib Pro / Raisonné.
     Swap these three values if you license the originals. */
  --font-body:    'Figtree', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --font-ui:      'Jost', system-ui, -apple-system, sans-serif;

  /* Fluid type scale — clamp() means no breakpoint jumps between sizes. */
  --text-xs:   0.75rem;
  --text-sm:   0.8125rem;
  --text-base: 1rem;
  --text-lg:   1.125rem;
  --text-xl:   clamp(1.25rem, 1.1rem + 0.5vw,  1.5rem);
  --text-2xl:  clamp(1.5rem,  1.3rem + 0.9vw,  2rem);
  --text-3xl:  clamp(1.875rem, 1.5rem + 1.6vw, 2.75rem);
  --text-4xl:  clamp(2.25rem, 1.6rem + 3vw,    4rem);

  --leading-tight: 1.12;
  --leading-snug:  1.35;
  --leading-base:  1.6;

  /* ── Spacing ────────────────────────────────────────────────────────────── */
  --space-1:  0.25rem;
  --space-2:  0.5rem;
  --space-3:  0.75rem;
  --space-4:  1rem;
  --space-5:  1.25rem;
  --space-6:  1.5rem;
  --space-8:  2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;

  /* Vertical rhythm between homepage sections — the generous whitespace is
     most of what makes the reference design feel calm. */
  --section-y: clamp(3.5rem, 2rem + 6vw, 7rem);

  /* ── Layout ─────────────────────────────────────────────────────────────── */
  --container:        1240px;
  --container-narrow: 720px;
  --gutter:           clamp(1rem, 0.5rem + 2vw, 2.5rem);

  /* ── Radii ──────────────────────────────────────────────────────────────── */
  --radius-sm:   4px;
  --radius-md:   8px;
  --radius-lg:   12px;
  --radius-xl:   20px;
  --radius-pill: 999px;

  /* ── Elevation ──────────────────────────────────────────────────────────── */
  /* Tinted with the brand green rather than pure black, so shadows read warm. */
  --shadow-sm: 0 1px 2px rgba(6, 78, 59, 0.06);
  --shadow-md: 0 4px 16px rgba(6, 78, 59, 0.08);
  --shadow-lg: 0 16px 48px rgba(6, 78, 59, 0.12);

  /* ── Motion ─────────────────────────────────────────────────────────────── */
  --ease:        cubic-bezier(0.4, 0, 0.2, 1);
  --duration:    220ms;
  --duration-lg: 400ms;

  /* ── Chrome ─────────────────────────────────────────────────────────────── */
  --header-h: 72px;
  --z-header: 100;
  --z-drawer: 200;
  --z-overlay: 150;
  --z-stickybar: 90;

  /* Minimum comfortable touch target. 44px is the figure both Apple's HIG and
     WCAG 2.2 Target Size (AA) land on; below it, mis-taps rise sharply. */
  --tap: 44px;
}

/* Phones get a shorter header — 72px of permanent sticky chrome is a lot of a
   short screen. */
@media (max-width: 767px) {
  :root {
    --header-h: 60px;

    /*
     * 24px, not the 16px this originally used.
     *
     * The tighter value was chosen to give product cards more width, which
     * suits bounded objects like cards but is too close for running text:
     * long paragraphs in the product description and reviews read as though
     * they are falling off the left edge. Cards lose about 4px each at
     * two-up, which is not noticeable; the readability gain is.
     */
    --gutter: 1.5rem;
    --section-y: clamp(2.5rem, 1.5rem + 5vw, 4rem);
  }
}

/* Per-vertical accent rebinding. Applied to <body> by ffb_vertical_body_class()
   and to individual product cards in a mixed grid. */
.ffb-vertical-plants   { --accent: var(--accent-plants); }
.ffb-vertical-pots     { --accent: var(--accent-pots); }
.ffb-vertical-reptiles { --accent: var(--accent-reptiles); }


/* ─────────────────────────────────────────────
   2. RESET
   ───────────────────────────────────────────── */

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

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

/* Honour the OS "reduce motion" setting. Animation that cannot be turned off
   triggers nausea and migraines for some people. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-base);
  color: var(--fg);
  background-color: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

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

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

ul,
ol {
  list-style: none;
}

a {
  color: inherit;
  text-decoration-color: var(--border-strong);
  text-underline-offset: 0.2em;
}

a:hover {
  text-decoration-color: currentColor;
}

/* One visible focus style everywhere. :focus-visible means it appears for
   keyboard users without ringing every mouse click. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

::selection {
  background: var(--banner);
  color: var(--green-dark);
}


/* ─────────────────────────────────────────────
   3. TYPOGRAPHY
   ───────────────────────────────────────────── */

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: var(--leading-tight);
  letter-spacing: -0.015em;
  text-wrap: balance; /* Avoids a single orphan word on the last line. */
}

h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
h4 { font-size: var(--text-xl); }
h5, h6 {
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

p {
  text-wrap: pretty;
}

/* The small uppercase label above headings — Bloomscape uses this constantly. */
.eyebrow {
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--space-3);
}

.eyebrow a {
  text-decoration: none;
}

.screen-reader-text {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The skip link stays hidden until focused, then drops into view. */
.skip-link:focus {
  position: fixed;
  top: var(--space-3);
  left: var(--space-3);
  z-index: 999;
  width: auto;
  height: auto;
  clip: auto;
  clip-path: none;
  padding: var(--space-3) var(--space-5);
  background: var(--green-dark);
  color: var(--cream);
  border-radius: var(--radius-md);
  text-decoration: none;
}


/* ─────────────────────────────────────────────
   4. LAYOUT
   ───────────────────────────────────────────── */

.site {
  display: flex;
  flex-direction: column;

  /* 100vh on mobile means "viewport with browser chrome hidden", so it always
     overflows by the height of the address bar and creates a phantom scroll.
     100dvh tracks the visible area. vh stays as the fallback for older
     browsers, and dvh overrides it where supported. */
  min-height: 100vh;
  min-height: 100dvh;
}

/*
 * Prefixed deliberately — do not rename this back to `.container`.
 *
 * `.container` is one of the most collision-prone class names on the web.
 * Bootstrap defines it, and a large number of WordPress plugins ship Bootstrap
 * or their own `.container` rule. This selector is a single class (specificity
 * 0,1,0), the weakest there is, so any plugin stylesheet enqueued after the
 * theme's that declares `.container { max-width: 100%; padding: 0 }` wins the
 * cascade and silently removes the page gutter site-wide — text then runs to
 * the screen edge at every breakpoint.
 *
 * The `ffb-` prefix makes that collision impossible rather than relying on
 * load order, which a caching or CSS-combining plugin can reorder at will.
 */
.ffb-container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.ffb-container--narrow {
  max-width: var(--container-narrow);
}

.site-main {
  flex: 1;
  padding-block: var(--space-12) var(--space-24);
}

/* The homepage manages its own section spacing. */
.site-main--home {
  padding-block: 0;
}

.section {
  padding-block: var(--section-y);
}

.section--cream {
  background: var(--peach);
}

.section__head {
  margin-bottom: var(--space-10);
  max-width: 44ch;
}

.section__head--centred {
  max-width: none;
  text-align: center;
}

.section__head--split {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-6);
  max-width: none;
  flex-wrap: wrap;
}

.section__head--split > div {
  max-width: 44ch;
}

.section__title {
  font-size: var(--text-3xl);
}

.section__subtitle {
  margin-top: var(--space-3);
  color: var(--fg-muted);
  font-size: var(--text-lg);
}

.section__more {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  padding-bottom: 2px;
  border-bottom: 1px solid var(--border-strong);
  transition: border-color var(--duration) var(--ease), color var(--duration) var(--ease);
}

.section__more:hover {
  color: var(--accent);
  border-color: var(--accent);
}

.section__more svg {
  transition: transform var(--duration) var(--ease);
}

.section__more:hover svg {
  transform: translateX(3px);
}

/* Content + sidebar */
.content-area {
  display: grid;
  gap: var(--space-12);
}

@media (min-width: 900px) {
  .content-area:has(.content-sidebar) {
    grid-template-columns: minmax(0, 1fr) 280px;
  }
}

.page-head {
  margin-bottom: var(--space-12);
  max-width: 52ch;
}

.page-head__title {
  font-size: var(--text-3xl);
}

.page-head__description {
  margin-top: var(--space-4);
  color: var(--fg-muted);
  font-size: var(--text-lg);
}

.page-head__search {
  margin-top: var(--space-6);
  max-width: 420px;
}


/* ─────────────────────────────────────────────
   5. ANNOUNCEMENT BAR
   ───────────────────────────────────────────── */

.announcement {
  background: var(--banner);
  color: var(--green-dark);
  font-size: var(--text-sm);
  text-align: center;
}

.announcement__inner {
  padding-block: var(--space-2);
}

.announcement__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  text-decoration: none;
  font-weight: 500;
}

.announcement__link:hover {
  text-decoration: underline;
}


/* ─────────────────────────────────────────────
   6. HEADER
   ───────────────────────────────────────────── */

.header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--cream);
  border-bottom: 1px solid transparent;
  transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

.header.is-stuck {
  border-bottom-color: var(--border);
  box-shadow: var(--shadow-sm);
}

.header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  min-height: var(--header-h);
}

.header__brand {
  flex-shrink: 0;
}

.header__brand img,
.footer__brand img {
  max-height: 44px;
  width: auto;
}

.site-title {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
}

.site-title a {
  text-decoration: none;
}

/* ── Primary nav ──────────────────────────────────────────────────────────── */

.header__nav {
  flex: 1;
}

.nav-menu {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.nav-menu > li {
  position: relative;
}

.nav-menu > li > .menu-item__link {
  display: inline-flex;
  align-items: center;
  padding: var(--space-3) var(--space-3);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--duration) var(--ease);
}

.nav-menu > li > .menu-item__link:hover,
.nav-menu > li.current-menu-item > .menu-item__link {
  color: var(--accent);
}

/* Underline that grows from the centre on hover. */
.nav-menu > li > .menu-item__link span {
  position: relative;
}

.nav-menu > li > .menu-item__link span::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -4px;
  width: 0;
  height: 1.5px;
  background: currentColor;
  transform: translateX(-50%);
  transition: width var(--duration) var(--ease);
}

.nav-menu > li:hover > .menu-item__link span::after,
.nav-menu > li.current-menu-item > .menu-item__link span::after {
  width: 100%;
}

.menu-item__toggle {
  display: inline-flex;
  align-items: center;
  padding: var(--space-2);
  color: inherit;
  transition: transform var(--duration) var(--ease);
}

.menu-item__toggle svg {
  transform: rotate(90deg);
  transition: transform var(--duration) var(--ease);
}

.has-dropdown.is-open > .menu-item__toggle svg {
  transform: rotate(-90deg);
}

.nav-empty a {
  font-size: var(--text-sm);
  color: var(--fg-muted);
}

/* ── Dropdown / mega menu ─────────────────────────────────────────────────── */

.header__nav .sub-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 240px;
  padding: var(--space-4);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);

  /* Hidden by default but kept in the layout so the transition can run.
     visibility (not display) keeps it out of the tab order while closed. */
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition:
    opacity var(--duration) var(--ease),
    transform var(--duration) var(--ease),
    visibility var(--duration) var(--ease);
}

.header__nav .has-dropdown:hover > .sub-menu,
.header__nav .has-dropdown:focus-within > .sub-menu,
.header__nav .has-dropdown.is-open > .sub-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.header__nav .sub-menu .menu-item__link {
  display: block;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-base);
  text-decoration: none;
  border-radius: var(--radius-md);
  transition: background var(--duration) var(--ease), color var(--duration) var(--ease);
}

.header__nav .sub-menu .menu-item__link:hover {
  background: var(--highlight);
  color: var(--accent);
}

/* Second-level submenus fan out sideways. */
.header__nav .sub-menu .sub-menu {
  position: static;
  padding: 0 0 0 var(--space-3);
  border: 0;
  box-shadow: none;
  background: none;
  opacity: 1;
  visibility: visible;
  transform: none;
}

.header__nav .sub-menu .sub-menu .menu-item__link {
  font-size: var(--text-sm);
  color: var(--fg-muted);
}

/* ── Utility icons ────────────────────────────────────────────────────────── */

.header__utils {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin-left: auto;
}

.header__util {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: var(--radius-pill);
  color: var(--fg);
  text-decoration: none;
  transition: background var(--duration) var(--ease), color var(--duration) var(--ease);
}

.header__util:hover {
  background: var(--highlight);
  color: var(--accent);
}

.header__cart {
  position: relative;
}

.header__cart-count {
  position: absolute;
  top: 4px;
  right: 2px;
  min-width: 18px;
  height: 18px;
  padding-inline: 4px;
  display: grid;
  place-items: center;
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  color: var(--cream);
  background: var(--green-dark);
  border-radius: var(--radius-pill);
}

.header__cart-count.is-empty {
  display: none;
}

/* ── Burger ───────────────────────────────────────────────────────────────── */

.header__burger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  margin-left: calc(var(--space-2) * -1);
  border-radius: var(--radius-pill);
  color: var(--fg);
}

.header__burger-close {
  display: none;
}

body.menu-open .header__burger-open {
  display: none;
}

body.menu-open .header__burger-close {
  display: inline-flex;
}

/* ── Search panel ─────────────────────────────────────────────────────────── */

.search-panel {
  border-top: 1px solid var(--border);
  background: var(--white);
}

.search-panel__inner {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding-block: var(--space-5);
}

.search-panel__inner form {
  flex: 1;
}

.search-panel__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: var(--radius-pill);
  transition: background var(--duration) var(--ease);
}

.search-panel__close:hover {
  background: var(--highlight);
}

/* ── Mobile drawer ────────────────────────────────────────────────────────── */

.mobile-nav {
  position: fixed;

  /* --header-bottom is measured in JS from the header's real bounding box.
     A static offset was wrong in three common cases: the announcement bar
     pushes the header down when the page is unscrolled, the WordPress admin
     bar adds 32-46px for logged-in users, and the header itself is shorter on
     small screens. The fallback only applies if JS has not run yet. */
  inset: var(--header-bottom, 60px) 0 0 0;

  z-index: var(--z-drawer);

  /* Momentum scrolling, and never let a long menu rubber-band the page behind. */
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;

  /* Bottom padding clears the iOS home indicator. */
  padding: var(--space-4) var(--gutter);
  padding-bottom: calc(var(--space-16) + env(safe-area-inset-bottom, 0px));

  background: var(--cream);
  border-top: 1px solid var(--border);
}

.mobile-nav__menu > li {
  border-bottom: 1px solid var(--border);
}

.mobile-nav__menu .menu-item__link {
  display: block;
  padding: var(--space-4) 0;
  font-family: var(--font-ui);
  font-size: var(--text-lg);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
}

.mobile-nav__menu .has-dropdown {
  position: relative;
}

.mobile-nav__menu .menu-item__toggle {
  position: absolute;
  top: var(--space-2);
  right: 0;
  width: 44px;
  height: 44px;
  justify-content: center;
}

.mobile-nav__menu .sub-menu {
  display: none;
  padding-bottom: var(--space-4);
}

.mobile-nav__menu .has-dropdown.is-open > .sub-menu {
  display: block;
}

.mobile-nav__menu .sub-menu .menu-item__link {
  padding: var(--space-2) 0 var(--space-2) var(--space-4);
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--fg-muted);
}

.site-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: rgba(6, 78, 59, 0.32);
}

/* backdrop-filter forces a full-screen GPU composite every frame, which is a
   measurable scroll cost on mid-range Android. Only apply it where a pointer
   implies a device with the headroom to spare. */
@media (hover: hover) and (pointer: fine) {
  .site-overlay {
    backdrop-filter: blur(2px);
  }
}

body.menu-open {
  overflow: hidden;
}


/* ─────────────────────────────────────────────
   7. BUTTONS
   ───────────────────────────────────────────── */

.btn,
button.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-8);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
  border: 1.5px solid transparent;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition:
    background var(--duration) var(--ease),
    color var(--duration) var(--ease),
    border-color var(--duration) var(--ease),
    transform var(--duration) var(--ease);
}

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

.btn--primary {
  background: var(--green-dark);
  color: var(--cream);
  border-color: var(--green-dark);
}

.btn--primary:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--white);
}

.btn--ghost {
  background: transparent;
  color: var(--green-dark);
  border-color: var(--border-strong);
}

.btn--ghost:hover {
  background: var(--green-dark);
  border-color: var(--green-dark);
  color: var(--cream);
}

.btn--accent {
  background: var(--accent);
  color: var(--white);
  border-color: var(--accent);
}

.btn--accent:hover {
  filter: brightness(0.92);
}

.btn--small {
  padding: var(--space-2) var(--space-5);
  font-size: var(--text-xs);
}

.btn--block {
  width: 100%;
}

.btn[disabled],
.btn.disabled {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}


/* ─────────────────────────────────────────────
   8. FORMS
   ───────────────────────────────────────────── */

input[type="text"],
input[type="email"],
input[type="url"],
input[type="password"],
input[type="search"],
input[type="tel"],
input[type="number"],
input[type="date"],
textarea,
select {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background: var(--white);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease);
}

input::placeholder,
textarea::placeholder {
  color: var(--fg-muted);
  opacity: 0.75;
}

input:focus,
textarea:focus,
select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(4, 120, 87, 0.14);
}

textarea {
  min-height: 140px;
  resize: vertical;
}

label {
  display: inline-block;
  margin-bottom: var(--space-2);
  font-size: var(--text-sm);
  font-weight: 500;
}

/* ── Search form ──────────────────────────────────────────────────────────── */

.search-form {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  position: relative;
}

.search-form__field {
  flex: 1;
  padding-right: var(--space-12);
}

.search-form__submit {
  position: absolute;
  right: var(--space-1);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  color: var(--fg-muted);
  transition: color var(--duration) var(--ease), background var(--duration) var(--ease);
}

.search-form__submit:hover {
  color: var(--accent);
  background: var(--highlight);
}


/* ─────────────────────────────────────────────
   9. HERO
   ───────────────────────────────────────────── */

.hero {
  position: relative;
  display: grid;
  align-items: center;
  min-height: clamp(420px, 62vh, 640px);
  background: var(--peach);
  overflow: hidden;
}

.hero__media {
  position: absolute;
  inset: 0;
}

/* <picture> is inline by default, so it would not fill the media box and the
   <img> inside would have no height to match. */
.hero__picture {
  display: block;
  width: 100%;
  height: 100%;
}

.hero__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Scrim only when there is a photo behind the text. */
.hero--has-image .hero__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(6, 78, 59, 0.55) 0%,
    rgba(6, 78, 59, 0.25) 45%,
    rgba(6, 78, 59, 0) 75%
  );
}

.hero__inner {
  position: relative;
  padding-block: var(--space-16);
}

.hero__panel {
  max-width: 34rem;
}

.hero--has-image .hero__panel {
  color: var(--cream);
}

.hero--has-image .eyebrow {
  color: var(--banner);
}

.hero__heading {
  font-size: var(--text-4xl);
}

.hero__text {
  margin-top: var(--space-5);
  font-size: var(--text-lg);
  color: var(--fg-muted);
  max-width: 44ch;
}

.hero--has-image .hero__text {
  color: rgba(252, 249, 243, 0.9);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-8);
}

.hero--has-image .btn--ghost {
  color: var(--cream);
  border-color: rgba(252, 249, 243, 0.6);
}

.hero--has-image .btn--ghost:hover {
  background: var(--cream);
  color: var(--green-dark);
  border-color: var(--cream);
}


/* ─────────────────────────────────────────────
   9b. HERO SLIDER

   Only rendered when more than one slide is filled in. A scroll-snap track
   rather than a transformed strip: swipe, momentum and keyboard scrolling all
   come for free, and with JavaScript disabled it stays a usable horizontal
   scroller instead of showing a single frozen slide.
   ───────────────────────────────────────────── */

.hero-slider {
  position: relative;
}

.hero-track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;

  /* The dots sit over the slides, so a scrollbar would only add height. */
  scrollbar-width: none;
}

.hero-track::-webkit-scrollbar {
  display: none;
}

.hero--slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always; /* Never skip two slides on one fast swipe. */
}

/* ── Arrows ───────────────────────────────────────────────────────────────── */

.hero-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;

  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);

  color: var(--green-dark);
  background: rgba(252, 249, 243, 0.9);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-sm);
  transition: background var(--duration) var(--ease), color var(--duration) var(--ease);
}

.hero-nav:hover {
  background: var(--cream);
  color: var(--accent);
}

.hero-nav--prev {
  left: var(--space-4);
}

.hero-nav--prev svg {
  transform: rotate(180deg);
}

.hero-nav--next {
  right: var(--space-4);
}

/* JS sets this at the ends of the track — the slider does not loop. */
.hero-nav[disabled] {
  opacity: 0;
  pointer-events: none;
}

/* ── Dots and pause ───────────────────────────────────────────────────────── */

.hero-controls {
  position: absolute;
  left: 50%;
  bottom: var(--space-5);
  transform: translateX(-50%);
  z-index: 2;

  display: flex;
  align-items: center;
  gap: var(--space-3);

  padding: var(--space-2) var(--space-3);
  background: rgba(252, 249, 243, 0.9);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-sm);
}

.hero-dots {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

/* The visible dot stays small; the button around it is a full touch target. */
.hero-dot {
  position: relative;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
}

.hero-dot::before {
  content: '';
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--border-strong);
  transition: background var(--duration) var(--ease), width var(--duration) var(--ease);
}

.hero-dot[aria-current="true"]::before {
  width: 22px;
  background: var(--green-dark);
}

.hero-pause {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  color: var(--green-dark);
  border-radius: var(--radius-pill);
  opacity: 0.7;
}

.hero-pause:hover,
.hero-pause:focus-visible {
  opacity: 1;
}

.hero-pause__icon--play {
  display: none;
}

.hero-pause[aria-pressed="true"] .hero-pause__icon--pause {
  display: none;
}

.hero-pause[aria-pressed="true"] .hero-pause__icon--play {
  display: grid;
}

/* Give the panel room so the controls never sit on top of a CTA. */
.hero-slider .hero__inner {
  padding-bottom: calc(var(--space-16) + var(--space-4));
}

@media (max-width: 767px) {
  /* Arrows are redundant next to a swipe, and they cover the slide. */
  .hero-nav {
    display: none;
  }

  .hero-controls {
    bottom: var(--space-4);
  }
}

/*
 * Reduced motion: no smooth scroll animation. Autoplay is disabled in
 * JavaScript for the same preference, so nothing moves without a deliberate
 * action.
 */
@media (prefers-reduced-motion: reduce) {
  .hero-track {
    scroll-behavior: auto;
  }
}


/* ─────────────────────────────────────────────
   10. VERTICAL TILES
   ───────────────────────────────────────────── */

.vertical-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-6);
}

.vertical-tile__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  overflow: hidden;
  text-decoration: none;
  transition:
    transform var(--duration) var(--ease),
    box-shadow var(--duration) var(--ease),
    border-color var(--duration) var(--ease);
}

.vertical-tile__link:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: var(--accent);
}

.vertical-tile__media {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  background: var(--linen);
  overflow: hidden;
}

.vertical-tile__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--duration-lg) var(--ease);
}

.vertical-tile__link:hover .vertical-tile__image {
  transform: scale(1.04);
}

.vertical-tile__placeholder {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  color: var(--accent);
  opacity: 0.4;
}

.vertical-tile__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--space-3);
  padding: var(--space-6);
}

.vertical-tile__title {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
}

.vertical-tile__text {
  color: var(--fg-muted);
  font-size: var(--text-base);
}

.vertical-tile__cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-2);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}

.vertical-tile__link:hover .vertical-tile__cta svg {
  transform: translateX(3px);
}

.vertical-tile__cta svg {
  transition: transform var(--duration) var(--ease);
}

/*
 * Phones: swipe instead of stack.
 *
 * The auto-fit grid collapses to one column below ~600px, so three tall photo
 * cards stacked vertically ran to roughly three screens of scrolling for what
 * is really just three links. Turning the row into a horizontal scroller keeps
 * the side-by-side arrangement that works on desktop and costs one card's
 * height instead of three.
 *
 * Cards are sized to about 78% of the viewport so the next one is always partly
 * visible — that peek is what tells people the row scrolls, without needing
 * arrows or dots. Pure CSS; no carousel script.
 */
@media (max-width: 767px) {
  .vertical-tiles {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 78%;
    gap: var(--space-4);

    overflow-x: auto;
    scroll-snap-type: x mandatory;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;

    /* Break out of the container gutter so cards can scroll to the screen
       edges, then re-apply it as padding so the first and last still align
       with the section heading above. */
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    padding-bottom: var(--space-2);

    /*
     * Without this the first card ends up flush against the screen edge.
     *
     * scroll-snap-align: start snaps a card to the *scrollport* edge, which
     * sits inside the padding — so the moment you swipe, the padding scrolls
     * away and the snapped card sits hard against the edge. scroll-padding
     * moves the snap position inwards by the same amount, so cards land
     * aligned with the section heading instead.
     */
    scroll-padding-inline: var(--gutter);

    /* The scrollbar would sit under the cards and add height for nothing. */
    scrollbar-width: none;
  }

  .vertical-tiles::-webkit-scrollbar {
    display: none;
  }

  .vertical-tile {
    scroll-snap-align: start;
  }

  /* A 4:3 crop makes each card nearly a full screen tall on its own. */
  .vertical-tile__media {
    aspect-ratio: 16 / 10;
  }

  .vertical-tile__body {
    gap: var(--space-2);
    padding: var(--space-4);
  }

  .vertical-tile__title {
    font-size: var(--text-xl);
  }
}


/* ─────────────────────────────────────────────
   11. VALUE PROPS
   ───────────────────────────────────────────── */

/*
 * A thin ticker rather than a four-column grid.
 *
 * The grid stacked into four tall blocks on phones and consumed most of a
 * screen for reassurance copy. As a single scrolling line it costs one row at
 * every width.
 */

.section--props {
  background: var(--emerald);
  color: var(--cream);

  /* The strip supplies its own height; the standard section rhythm would
     wrap it in far more padding than a one-line bar needs. */
  padding-block: 0;
}

/* Positioning context for the pause button, which sits outside the masked
   element so the edge fade cannot render it invisible. */
.props-strip {
  position: relative;
}

.marquee {
  /* Full-bleed: the ticker should run edge to edge, not stop at the container
     gutter, so it reads as a band rather than a boxed widget. */
  width: 100%;
  overflow: hidden;

  /* Fade both ends so items dissolve instead of being chopped by a hard edge.
     A mask affects descendants, which is why nothing interactive lives here. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%);
}

.marquee__track {
  display: flex;

  /* max-content stops the two groups being squeezed to the container width,
     which would break the -50% translate the seamless loop depends on. */
  width: max-content;

  /* Duration is set in JS from the measured track width so the scroll speed
     stays constant no matter how many items are in the list. The value here
     is only the pre-JS fallback. */
  animation: ffb-marquee var(--marquee-duration, 34s) linear infinite;

  /* Promote to its own layer once, rather than repainting each frame. */
  will-change: transform;
}

@keyframes ffb-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.marquee__group {
  display: flex;
  align-items: center;
  gap: var(--space-10);

  /* Trailing gap so the last item is not flush against the clone's first.
     Both groups carry it, keeping the two halves exactly equal in width. */
  padding-right: var(--space-10);
  margin: 0;
}

/* ── Pause ────────────────────────────────────────────────────────────────── */

/* Pointer devices pause on hover; keyboard users pause on focus. Neither is
   available on a touchscreen, which is why the explicit button exists too. */
.props-strip:hover .marquee__track,
.props-strip:focus-within .marquee__track,
.props-strip.is-paused .marquee__track {
  animation-play-state: paused;
}

.marquee__pause {
  position: absolute;
  top: 50%;
  right: var(--space-2);
  transform: translateY(-50%);
  z-index: 2;

  display: inline-grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);

  color: var(--cream);

  /* Matches the band so the control sits on it rather than floating over it. */
  background: var(--emerald);
  border: 1px solid rgba(252, 249, 243, 0.28);
  border-radius: var(--radius-pill);
  opacity: 0.7;
  transition: opacity var(--duration) var(--ease), background var(--duration) var(--ease);
}

/* Darkening on hover reads more clearly against an already-green band than
   shifting to the accent green, which is too close to the emerald to register. */
.marquee__pause:hover,
.marquee__pause:focus-visible {
  opacity: 1;
  background: var(--green-dark);
}

/* Swap the glyph to match state: pause shown while running, play while paused. */
.marquee__icon--play {
  display: none;
}

.marquee__pause[aria-pressed="true"] .marquee__icon--pause {
  display: none;
}

.marquee__pause[aria-pressed="true"] .marquee__icon--play {
  display: inline-flex;
}

/* ── Items ────────────────────────────────────────────────────────────────── */

.prop {
  display: flex;
  align-items: center;
  gap: var(--space-3);

  /* One line, always — wrapping would defeat the point of the ticker. */
  white-space: nowrap;

  padding-block: var(--space-4);
}

/* Separator diamond between promises. Decorative, so it never reaches the
   accessibility tree. */
.prop::after {
  content: '';
  width: 5px;
  height: 5px;
  margin-left: var(--space-10);
  background: var(--banner);
  transform: rotate(45deg);
  opacity: 0.6;
  flex: none;
}

.prop__icon {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: none;
  border: 1px solid rgba(252, 249, 243, 0.3);
  border-radius: var(--radius-pill);
  color: var(--banner);
}

.prop__title {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 500;
  line-height: 1.2;
  margin: 0;
}

/* Only rendered when the ffb_props_show_text filter is enabled. */
.prop__text {
  color: rgba(252, 249, 243, 0.7);
  font-size: var(--text-sm);
  margin: 0;
}

@media (max-width: 767px) {
  .marquee__group {
    gap: var(--space-8);
    padding-right: var(--space-8);
  }

  .prop::after {
    margin-left: var(--space-8);
  }

  .prop__title {
    font-size: var(--text-sm);
  }

  .prop__icon {
    width: 30px;
    height: 30px;
  }

  .prop {
    padding-block: var(--space-3);
  }
}

/*
 * Reduced motion: stop the animation entirely and turn the strip into a
 * horizontal scroller so every promise is still reachable, by swipe or by
 * keyboard. The clone is removed because a duplicated static list is just
 * confusing.
 */
@media (prefers-reduced-motion: reduce) {
  .marquee {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
  }

  .marquee__track {
    animation: none;
    will-change: auto;
  }

  .marquee__group[aria-hidden="true"] {
    display: none;
  }

  .marquee__pause {
    display: none;
  }
}


/* ─────────────────────────────────────────────
   12. GUIDE / POST CARDS
   ───────────────────────────────────────────── */

.guide-grid,
.post-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--space-8);
}

.guide-card__link,
.post-card__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  gap: var(--space-4);
  text-decoration: none;
}

.guide-card__media,
.post-card__media {
  display: block;
  aspect-ratio: 8 / 5;
  background: var(--linen);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.guide-card__image,
.post-card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--duration-lg) var(--ease);
}

.guide-card__link:hover .guide-card__image,
.post-card__link:hover .post-card__image {
  transform: scale(1.04);
}

.guide-card__placeholder,
.post-card__placeholder {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  color: var(--green-grey);
  opacity: 0.4;
}

.guide-card__body,
.post-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.guide-card__eyebrow,
.post-card__eyebrow {
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}

.guide-card__title,
.post-card__title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  line-height: var(--leading-snug);
  transition: color var(--duration) var(--ease);
}

.guide-card__link:hover .guide-card__title,
.post-card__link:hover .post-card__title {
  color: var(--accent);
}

.guide-card__excerpt,
.post-card__excerpt {
  color: var(--fg-muted);
  font-size: var(--text-base);
}

.post-card__meta {
  font-size: var(--text-sm);
  color: var(--fg-muted);
}

.post-card__price {
  font-weight: 600;
}


/* ─────────────────────────────────────────────
   13. TESTIMONIALS
   ───────────────────────────────────────────── */

.section--testimonials {
  background: var(--peach);
}

.testimonials {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-6);
}

.testimonial figure {
  display: flex;
  flex-direction: column;
  height: 100%;
  gap: var(--space-4);
  padding: var(--space-8);
  background: var(--white);
  border-radius: var(--radius-xl);
  border: 1px solid var(--border);
}

.testimonial__stars {
  display: flex;
  gap: 2px;
  color: var(--accent);
}

.testimonial__stars svg {
  fill: currentColor;
  stroke: none;
}

.testimonial__quote {
  flex: 1;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
}

.testimonial__author {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: var(--text-sm);
}

.testimonial__name {
  font-weight: 600;
}

.testimonial__meta {
  color: var(--fg-muted);
}


/* ─────────────────────────────────────────────
   14. NEWSLETTER
   ───────────────────────────────────────────── */

.newsletter {
  display: grid;
  gap: var(--space-8);
  align-items: center;
  padding: clamp(2rem, 1rem + 4vw, 4rem);
  background: var(--green-dark);
  color: var(--cream);
  border-radius: var(--radius-xl);
}

@media (min-width: 860px) {
  .newsletter {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-16);
  }
}

.newsletter__heading {
  font-size: var(--text-3xl);
}

.newsletter__text {
  margin-top: var(--space-3);
  color: rgba(252, 249, 243, 0.75);
}

.newsletter__placeholder {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.newsletter__placeholder input[type="email"] {
  flex: 1;
  min-width: 220px;
  background: rgba(252, 249, 243, 0.08);
  border-color: rgba(252, 249, 243, 0.3);
  color: var(--cream);
  border-radius: var(--radius-pill);
  padding-inline: var(--space-5);
}

.newsletter__placeholder input[type="email"]::placeholder {
  color: rgba(252, 249, 243, 0.5);
}

.newsletter__placeholder input[type="email"]:focus {
  border-color: var(--banner);
  box-shadow: 0 0 0 3px rgba(246, 207, 178, 0.2);
}

.newsletter__placeholder .btn--primary {
  background: var(--banner);
  color: var(--green-dark);
  border-color: var(--banner);
}

.newsletter__placeholder .btn--primary:hover {
  background: var(--cream);
  border-color: var(--cream);
}

.newsletter__note {
  flex-basis: 100%;
  font-size: var(--text-sm);
  color: var(--banner);
  min-height: 1.2em;
}

.newsletter__admin-hint {
  margin-top: var(--space-4);
  font-size: var(--text-sm);
  color: rgba(252, 249, 243, 0.6);
}

.newsletter__admin-hint a {
  color: var(--banner);
}


/* ─────────────────────────────────────────────
   15. BLOG & SINGLE
   ───────────────────────────────────────────── */

.single-post__head {
  max-width: 40rem;
  margin-inline: auto;
  text-align: center;
  margin-bottom: var(--space-8);
}

.single-post__title {
  font-size: var(--text-4xl);
}

.single-post__meta {
  margin-top: var(--space-4);
  font-size: var(--text-sm);
  color: var(--fg-muted);
  display: flex;
  justify-content: center;
  gap: var(--space-2);
}

.single-post__media,
.single-page__media {
  margin-bottom: var(--space-12);
  border-radius: var(--radius-xl);
  overflow: hidden;
}

.single-post__media figcaption {
  padding-top: var(--space-3);
  font-size: var(--text-sm);
  color: var(--fg-muted);
  text-align: center;
}

.entry-content {
  max-width: 68ch;
}

.entry-content > * + * {
  margin-top: var(--space-5);
}

.entry-content h2,
.entry-content h3,
.entry-content h4 {
  margin-top: var(--space-12);
}

.entry-content ul,
.entry-content ol {
  padding-left: var(--space-6);
}

.entry-content ul {
  list-style: disc;
}

.entry-content ol {
  list-style: decimal;
}

.entry-content li + li {
  margin-top: var(--space-2);
}

.entry-content a {
  color: var(--accent);
}

.entry-content blockquote {
  padding-left: var(--space-6);
  border-left: 3px solid var(--accent);
  font-family: var(--font-display);
  font-size: var(--text-xl);
  line-height: var(--leading-snug);
}

.entry-content img,
.entry-content figure {
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.entry-content code {
  padding: 0.15em 0.4em;
  background: var(--highlight);
  border-radius: var(--radius-sm);
  font-size: 0.9em;
}

.entry-content pre {
  padding: var(--space-5);
  background: var(--green-dark);
  color: var(--cream);
  border-radius: var(--radius-lg);
  overflow-x: auto;
}

.entry-content table {
  width: 100%;
  border-collapse: collapse;
}

.entry-content th,
.entry-content td {
  padding: var(--space-3);
  border-bottom: 1px solid var(--border);
  text-align: left;
}

/* Wide/full block alignments. */
.alignwide {
  width: min(100vw - (var(--gutter) * 2), 1100px);
  max-width: none;
  margin-inline: auto;
}

.alignfull {
  width: 100vw;
  max-width: none;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}

.single-post__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-10);
}

.tag-pill {
  display: inline-block;
  padding: var(--space-1) var(--space-4);
  font-size: var(--text-sm);
  background: var(--highlight);
  border-radius: var(--radius-pill);
  text-decoration: none;
  transition: background var(--duration) var(--ease), color var(--duration) var(--ease);
}

.tag-pill:hover {
  background: var(--green-dark);
  color: var(--cream);
}

/* Post navigation */
.nav-post {
  margin-top: var(--space-12);
  padding-top: var(--space-8);
  border-top: 1px solid var(--border);
}

.nav-post .nav-links {
  display: flex;
  justify-content: space-between;
  gap: var(--space-8);
  flex-wrap: wrap;
}

.nav-post a {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  text-decoration: none;
  max-width: 22rem;
}

.nav-post .nav-next a {
  text-align: right;
  margin-left: auto;
}

.nav-post__label {
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.nav-post__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
}

.nav-post a:hover .nav-post__title {
  color: var(--accent);
}

/* Pagination */
.pagination {
  margin-top: var(--space-16);
}

.pagination .nav-links {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.pagination .page-numbers {
  display: inline-grid;
  place-items: center;
  min-width: 42px;
  height: 42px;
  padding-inline: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  text-decoration: none;
  font-size: var(--text-sm);
  transition: background var(--duration) var(--ease), color var(--duration) var(--ease), border-color var(--duration) var(--ease);
}

.pagination .page-numbers:hover,
.pagination .page-numbers.current {
  background: var(--green-dark);
  border-color: var(--green-dark);
  color: var(--cream);
}

.pagination .page-numbers.dots {
  border-color: transparent;
}


/* ─────────────────────────────────────────────
   16. WIDGETS & SIDEBAR
   ───────────────────────────────────────────── */

.content-sidebar {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

.widget__title {
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border);
}

.widget ul {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.widget a {
  text-decoration: none;
  color: var(--fg-muted);
  transition: color var(--duration) var(--ease);
}

.widget a:hover {
  color: var(--accent);
}


/* ─────────────────────────────────────────────
   17. COMMENTS
   ───────────────────────────────────────────── */

.comments {
  margin-top: var(--space-16);
  padding-top: var(--space-12);
  border-top: 1px solid var(--border);
}

.comments__title {
  font-size: var(--text-2xl);
  margin-bottom: var(--space-8);
}

.comments__list,
.comments__list .children {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

.comments__list .children {
  margin-top: var(--space-8);
  padding-left: var(--space-8);
  border-left: 1px solid var(--border);
}

.comment-body {
  display: grid;
  gap: var(--space-2);
}

.comment-author {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-weight: 600;
}

.comment-author img {
  border-radius: var(--radius-pill);
}

.comment-metadata {
  font-size: var(--text-sm);
  color: var(--fg-muted);
}

.comment-metadata a {
  text-decoration: none;
}

.comment-form {
  margin-top: var(--space-10);
  display: grid;
  gap: var(--space-4);
}

.comment-form .comment-form-cookies-consent {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.comment-form input[type="checkbox"] {
  width: auto;
}


/* ─────────────────────────────────────────────
   18. EMPTY STATES & 404
   ───────────────────────────────────────────── */

.no-results,
.error-404 {
  padding-block: var(--space-16);
  text-align: center;
  max-width: 46ch;
  margin-inline: auto;
}

.no-results__title,
.error-404__title {
  font-size: var(--text-3xl);
  margin-bottom: var(--space-4);
}

.no-results__text,
.error-404__text {
  color: var(--fg-muted);
  font-size: var(--text-lg);
}

.no-results__search,
.error-404__search {
  margin-block: var(--space-8);
}

.error-404__actions {
  display: flex;
  gap: var(--space-3);
  justify-content: center;
  flex-wrap: wrap;
}


/* ─────────────────────────────────────────────
   19. FOOTER
   ───────────────────────────────────────────── */

.footer {
  margin-top: auto;
  padding-block: var(--space-16) var(--space-8);
  background: var(--green-dark);
  color: var(--cream);
}

.footer__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-10) var(--space-8);
}

.footer__brand {
  grid-column: 1 / -1;
  max-width: 22rem;
}

@media (min-width: 760px) {
  .footer__grid {
    grid-template-columns: 1.6fr repeat(3, 1fr);
  }

  .footer__brand {
    grid-column: auto;
  }
}

.footer__logo {
  font-family: var(--font-display);
  font-size: 1.5rem;
}

.footer__logo a {
  text-decoration: none;
}

.footer__tagline {
  margin-top: var(--space-3);
  color: rgba(252, 249, 243, 0.7);
  font-size: var(--text-base);
}

.footer__social {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-6);
}

.footer__social a {
  display: inline-grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid rgba(252, 249, 243, 0.25);
  border-radius: var(--radius-pill);
  transition: background var(--duration) var(--ease), color var(--duration) var(--ease), border-color var(--duration) var(--ease);
}

.footer__social a:hover {
  background: var(--banner);
  border-color: var(--banner);
  color: var(--green-dark);
}

.footer__heading {
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--banner);
  margin-bottom: var(--space-4);
}

.footer__menu {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.footer__menu a {
  color: rgba(252, 249, 243, 0.8);
  text-decoration: none;
  font-size: var(--text-base);
  transition: color var(--duration) var(--ease);
}

.footer__menu a:hover {
  color: var(--cream);
  text-decoration: underline;
}

.footer__bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-16);
  padding-top: var(--space-6);
  border-top: 1px solid rgba(252, 249, 243, 0.15);
  font-size: var(--text-sm);
  color: rgba(252, 249, 243, 0.6);
}

.footer__legal-menu {
  display: flex;
  gap: var(--space-5);
  flex-wrap: wrap;
}

.footer__legal-menu a {
  color: inherit;
  text-decoration: none;
}

.footer__legal-menu a:hover {
  color: var(--cream);
  text-decoration: underline;
}


/* ─────────────────────────────────────────────
   20. RESPONSIVE
   ───────────────────────────────────────────── */

/* Below this width the horizontal nav cannot fit, so swap to the drawer. */
@media (max-width: 1023px) {
  .header__nav {
    display: none;
  }

  .header__burger {
    display: inline-flex;
  }

  .header__brand {
    margin-right: auto;
  }
}

@media (min-width: 1024px) {
  .mobile-nav {
    display: none;
  }
}

@media (max-width: 640px) {
  .header__util--account {
    display: none; /* Account lives in the drawer on small screens. */
  }

  .section__head--split {
    align-items: flex-start;
    flex-direction: column;
  }

  .single-post__meta {
    flex-direction: column;
    gap: 0;
  }

  .single-post__meta span[aria-hidden] {
    display: none;
  }

  .nav-post .nav-links {
    flex-direction: column;
    gap: var(--space-6);
  }

  .nav-post .nav-next a {
    text-align: left;
    margin-left: 0;
  }
}


/* ─────────────────────────────────────────────
   21. TOUCH & MOBILE

   Most of this shop's traffic is phones. These rules are grouped rather than
   scattered so the mobile behaviour is auditable in one place.
   ───────────────────────────────────────────── */

/* ── Touch targets ────────────────────────────────────────────────────────── */

/* Every icon-only control gets a 44px hit area. Where the visual circle should
   stay smaller than the target, the element keeps its size and gains an
   invisible expanded hit area via a pseudo-element rather than growing. */
.header__util,
.header__burger,
.search-panel__close {
  width: var(--tap);
  height: var(--tap);
}

.footer__social a {
  width: var(--tap);
  height: var(--tap);
}

.pagination .page-numbers {
  min-width: var(--tap);
  height: var(--tap);
}

/* Menu chevrons: the visible glyph stays small, the tappable box does not. */
.menu-item__toggle {
  position: relative;
  min-width: var(--tap);
  min-height: var(--tap);
  justify-content: center;
}

/* ── Touch feedback ───────────────────────────────────────────────────────── */

/* Suppress the grey flash Android/iOS paint on tap, then supply a deliberate
   :active state instead — removing the flash without replacing it makes the
   whole UI feel unresponsive. */
a,
button,
.btn,
[role="button"] {
  -webkit-tap-highlight-color: transparent;
}

@media (hover: none) {
  .btn:active,
  .header__util:active,
  .product-card__media:active {
    opacity: 0.72;
  }

  .vertical-tile__link:active,
  .guide-card__link:active,
  .post-card__link:active {
    opacity: 0.8;
  }
}

/* ── Hover effects on touch devices ───────────────────────────────────────── */

/*
 * On a touchscreen there is no hover, so :hover fires on tap and then *sticks*
 * until the next tap elsewhere — a card stays lifted and zoomed after you have
 * navigated back to it. The transform-based effects also force a repaint on a
 * composited layer mid-scroll.
 *
 * Colour changes on hover are harmless and stay. Only motion is neutralised.
 */
@media (hover: none) {
  .vertical-tile__link:hover {
    transform: none;
    box-shadow: none;
    border-color: var(--border);
  }

  .vertical-tile__link:hover .vertical-tile__image,
  .guide-card__link:hover .guide-card__image,
  .post-card__link:hover .post-card__image {
    transform: none;
  }

  .section__more:hover svg,
  .vertical-tile__link:hover .vertical-tile__cta svg {
    transform: none;
  }
}

/* ── Safe areas (notch / home indicator) ──────────────────────────────────── */

.ffb-container {
  padding-left: max(var(--gutter), env(safe-area-inset-left, 0px));
  padding-right: max(var(--gutter), env(safe-area-inset-right, 0px));
}

.footer {
  padding-bottom: calc(var(--space-8) + env(safe-area-inset-bottom, 0px));
}

/* ── Scrolling ────────────────────────────────────────────────────────────── */

/* Anchor jumps and :target must not land underneath the sticky header. */
:target,
[id] {
  scroll-margin-top: calc(var(--header-h) + var(--space-4));
}

/* Never let a wide table or code block scroll the whole page sideways. */
.entry-content table,
.entry-content pre {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* ── Typography on small screens ──────────────────────────────────────────── */

@media (max-width: 767px) {
  /* The display face is set tight for desktop; at phone sizes that tightness
     reads as cramped, so relax tracking and leading slightly. */
  h1, h2, h3 {
    letter-spacing: -0.01em;
    line-height: 1.16;
  }

  .hero {
    /* svh = smallest viewport height, i.e. with browser chrome *shown*. This
       guarantees the CTA is reachable without scrolling even before the
       address bar collapses. */
    min-height: auto;
    min-height: min(78svh, 560px);
  }

  .hero__inner {
    padding-block: var(--space-12);
  }

  .hero__panel {
    max-width: none;
  }

  .hero__actions .btn {
    flex: 1;
    min-width: 0;
    padding-inline: var(--space-4);
  }

  /* Announcement bars eat three lines on a phone if the copy is long. */
  .announcement {
    font-size: var(--text-xs);
  }

  .announcement__inner {
    padding-block: var(--space-2);
  }

  .site-main {
    padding-block: var(--space-8) var(--space-16);
  }

  .page-head {
    margin-bottom: var(--space-8);
  }

  .section__head {
    margin-bottom: var(--space-6);
  }

  /* Single-column everything that was a two-up. */
  .newsletter {
    padding: var(--space-6);
  }

  .newsletter__placeholder {
    flex-direction: column;
  }

  .newsletter__placeholder input[type="email"],
  .newsletter__placeholder .btn {
    width: 100%;
    min-width: 0;
  }

  .testimonial figure {
    padding: var(--space-5);
  }

  .guide-grid,
  .post-grid {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }

  .footer__grid {
    gap: var(--space-8);
  }

  .footer__bar {
    margin-top: var(--space-10);
    flex-direction: column;
    align-items: flex-start;
  }
}

/* ── Form fields ──────────────────────────────────────────────────────────── */

/*
 * iOS Safari zooms the viewport when a focused input's font-size is below 16px,
 * and does not zoom back out. The base font is 16px and inputs inherit it, but
 * this pins it explicitly so a future type-scale change cannot reintroduce the
 * behaviour.
 */
@media (max-width: 767px) {
  input[type="text"],
  input[type="email"],
  input[type="url"],
  input[type="password"],
  input[type="search"],
  input[type="tel"],
  input[type="number"],
  input[type="date"],
  textarea,
  select {
    font-size: 16px;
    padding-block: var(--space-3);
  }

  .search-form__submit {
    width: var(--tap);
    height: var(--tap);
  }

  .search-form__field {
    padding-right: calc(var(--tap) + var(--space-2));
  }
}


/* ─────────────────────────────────────────────
   22. PRINT
   ───────────────────────────────────────────── */

@media print {
  .header,
  .footer,
  .announcement,
  .mobile-nav,
  .site-overlay,
  .search-panel,
  .nav-post,
  .comments {
    display: none !important;
  }

  body {
    background: #fff;
    color: #000;
  }
}
