/* =========================================================================
   DAMSEL IN DEFENSE — brand stylesheet

   Every value here is measured from damselindefense.net, not estimated.
   Source of truth: docs/homepage-pixel-spec.md (2026-08-27).

   Breakpoints are the REFERENCE SITE'S — 750px and 990px — not Bootstrap's
   768/992. Confirmed by measuring either side of each boundary. Do not
   "correct" them to framework defaults; that is the bug, not the fix.

   This is Damsel's own stylesheet. The inherited Pomifera CSS has been removed
   from the theme entirely, so nothing here needs !important to win.
   ========================================================================= */

:root {
  /* Rendered colour — measured from the live page, not from the theme's
     colour-scheme declarations. The navy/magenta/sage scheme exists in the
     stylesheet but the homepage does not use it. */
  --dd-bg:        #FFFFFF;
  --dd-ink:       rgba(37, 37, 37, 0.75);  /* body text as rendered */
  --dd-ink-solid: #252525;                 /* headings */
  --dd-btn:       #2C332F;                 /* charcoal — the real button fill */
  --dd-btn-text:  #FFFFFF;

  /* Navy is the HEADER and FOOTER colour, and only theirs. Measured
     2026-09-02: header nav links and every footer element render in
     rgba(53,80,120,0.75). The page body stays #252525 — see --dd-ink. Do not
     unify these two; they are genuinely different in the reference. */
  --dd-navy:      #355078;
  --dd-navy-dark: #2B4162;                  /* navy button hover */
  /* The brand magenta IS in use, but only as product-card button TEXT on
     white — never as a fill. 4.67:1 on white, which passes AA at 15px.
     Measured 2026-09-02, pixel spec §14. */
  --dd-magenta:   #C63F8E;
  --dd-navy-75:   rgba(53, 80, 120, 0.75);  /* links, footer body text */
  --dd-navy-50:   rgba(53, 80, 120, 0.5);   /* small caps labels, copyright */
  --dd-rule:      rgba(53, 80, 120, 0.12);  /* footer top hairline */
  --dd-rule-ink:  rgba(37, 37, 37, 0.08);   /* bottom-band hairline */

  /* Geometry */
  --dd-container:      1000px;
  --dd-pad-desktop:    50px;
  --dd-pad-mobile:     15px;
  --dd-gap-col:        16px;   /* >=750 */
  --dd-gap-row:        20px;
  --dd-gap-col-mobile: 8px;    /* <750  */
  --dd-gap-row-mobile: 10px;
  --dd-btn-radius:     41px;   /* pill */
  --dd-btn-height:     47px;
}

/* -------------------------------------------------------------------------
   Typography — TWO families. Corrected 2026-09-02, pixel spec §17.

     Oswald      body, nav, product names, prices, buttons, strong
     Montserrat  headings only, always 400

   The previous note here said Oswald was the only face and set H2 to
   50px/75px/300. Both claims came from measuring the ONE empty <h2> on the
   reference page — an element with no text. Every heading that actually
   renders is Montserrat 400 at 24px. Corroborated by §9's own section table:
   the heading section measures 47px tall, which a 75px line-height cannot fit.
   ------------------------------------------------------------------------- */
:root {
  --dd-font-body:    'Oswald', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --dd-font-heading: 'Montserrat', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

body {
  font-family: var(--dd-font-body);
  font-weight: 300;
  background-color: var(--dd-bg);
  color: var(--dd-ink);
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--dd-font-heading);
  font-weight: 400;
  color: var(--dd-ink-solid);
}

/* Bold body copy stays in the body face, one notch heavier. */
strong, b {
  font-family: var(--dd-font-body);
  font-weight: 600;
}

/* Section headings: 24px / 31.2px / 0.6px, solid #252525. NOT 50px — see the
   note above. Montserrat is far wider than Oswald, so the old 50px would not
   merely be wrong, it would overflow the container. */
.dd-h2 {
  font-family: var(--dd-font-heading);
  font-size: 24px;
  line-height: 31.2px;
  font-weight: 400;
  letter-spacing: 0.6px;
}

/* Capitals are presentational only. The reference site types them into the
   content (text-transform: none); we do not, so screen readers read words
   rather than spelling them out and the client can un-shout the copy. */
.dd-caps { text-transform: uppercase; }

.dd-eyebrow {
  display: inline-block;
  font-size: 14px;
  font-weight: 400;
  letter-spacing: 0.18em;
  color: var(--dd-ink-solid);
}

.dd-price { font-weight: 400; letter-spacing: 0.05em; }

.gfield--type-honeypot {
    display: none;
}
/* -------------------------------------------------------------------------
   Container — 1000px max, 50px side padding at >=750, 15px below.
   Bootstrap's .container is 1320px at xl; do not use it here.
   ------------------------------------------------------------------------- */
.dd-container {
  width: 100%;
  max-width: var(--dd-container);
  margin-inline: auto;
  padding-inline: var(--dd-pad-mobile);
}

@media (min-width: 750px) {
  .dd-container { padding-inline: var(--dd-pad-desktop); }
}

/* Full-width variant — true 100%, edge to edge, no side padding, so the
   carousel inside it runs right off both edges of the viewport. The heading
   and pagination centre themselves, so they do not need the padding back. */
.dd-container--fluid {
  max-width: none;
  padding-inline: 0;
}

/* -------------------------------------------------------------------------
   Carousel pagination — prev / counter / next.
   Behaviour lives in js/damsel-carousel.js. Without the JS the buttons simply
   never appear to do anything, but the strip is still swipeable, so this is
   an enhancement rather than the mechanism.
   ------------------------------------------------------------------------- */
.dd-carousel-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
  margin-top: 1.5rem;
}

.dd-carousel-nav[hidden] { display: none; }

.dd-carousel-nav__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: rgb(53, 80, 120);
  cursor: pointer;
  transition: opacity 0.2s ease;
}

.dd-carousel-nav__btn svg {
  width: 1.25rem;
  height: 1.25rem;
}

.dd-carousel-nav__btn:hover:not(:disabled) { opacity: 0.6; }

.dd-carousel-nav__btn:disabled {
  opacity: 0.25;
  cursor: default;
}

.dd-carousel-nav__btn:focus-visible {
  outline: 3px solid rgb(53, 80, 120);
  outline-offset: 2px;
  border-radius: 50%;
}

.dd-carousel-nav__count {
  font-size: 14px;
  letter-spacing: 0.08em;
  color: rgb(53, 80, 120);
  font-variant-numeric: tabular-nums;  /* stops the counter jittering */
  min-width: 3.5ch;
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .dd-carousel-nav__btn { transition: none; }
}

/* Full-bleed band that ignores the container (hero image). */
.dd-fullbleed { width: 100%; }

/* In-container banner image — 80% of the container, centred. Used by the
   "Conversations That Keep Them Safe" section. height:auto keeps the 1400x742
   aspect ratio, and the width/height attributes stay on the <img> so the
   browser reserves the right space and the layout does not shift on load. */
.dd-banner-img {
  display: block;
  width: 80%;
  height: auto;
  margin-inline: auto;
}

.dd-section { padding-block: 2rem; }

@media (min-width: 750px) {
  .dd-section { padding-block: 3rem; }
}

/* -------------------------------------------------------------------------
   Grid — the reference site's gaps, at the reference site's breakpoints.
   ------------------------------------------------------------------------- */
.dd-grid {
  display: grid;
  gap: var(--dd-gap-row-mobile) var(--dd-gap-col-mobile);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 750px) {
  .dd-grid { gap: var(--dd-gap-row) var(--dd-gap-col); }
  .dd-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .dd-grid--products { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .dd-grid--collections { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 990px) {
  .dd-grid--products { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

/* -------------------------------------------------------------------------
   Carousel — CSS scroll-snap, no JavaScript library.

   The reference shows a horizontal scroller with the next card partially
   visible at mobile. Scroll-snap reproduces that behaviour natively; a
   carousel plugin would add a dependency and still not peek correctly.
   Keyboard and touch both work because it is a real scroll container.
   ------------------------------------------------------------------------- */
.dd-carousel {
  display: grid;
  grid-auto-flow: column;
  /* Pixel QA 2026-09-02: was a flat 74%, which showed 1.35 cards. The
     reference shows TWO cards plus a ~38px peek below 750 — this calc
     reproduces its measured widths exactly (329 at 749, 205 at 500). */
  grid-auto-columns: calc((100% - var(--dd-gap-col-mobile) - 38px) / 2);
  gap: var(--dd-gap-row-mobile) var(--dd-gap-col-mobile);
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  scroll-snap-type: inline mandatory;
  scroll-padding-inline-start: 0;
  -webkit-overflow-scrolling: touch;

  /* Hide the native scrollbar. The element stays fully scrollable — swipe,
     trackpad, and keyboard arrows all still work — only the bar is hidden,
     because the pagination controls are the visible affordance now. Removing
     the bar also removes the reason for the bottom padding that made room
     for it. */
  scrollbar-width: none;               /* Firefox */
  -ms-overflow-style: none;            /* legacy Edge */

  /* Stops the scroller's overflow reaching the root. Without this the
     products carousel pushed documentElement.scrollWidth to 2501 against a
     1585 viewport, and Chrome painted a full-width horizontal scrollbar on
     the page — one that could not actually be scrolled, because the overflow
     belongs to this element. overflow-x:hidden here does NOT stop it;
     paint containment does. Nothing inside escapes the box, so it is safe. */
  contain: paint;
}

.dd-carousel::-webkit-scrollbar {      /* Chrome, Safari, current Edge */
  display: none;
}

.dd-carousel > * { scroll-snap-align: start; }

/* Pixel QA 2026-09-02: the three-up grid used to start at 750, but the
   reference only goes three-up at 990. Between 750 and 989 it stays a two-up
   scroller — measured 441 at 989, 331 at 768, 322 at 750.

   The calc reproduces all three exactly. It reads oddly because the reference
   lets the pair overrun the container slightly rather than fitting it: two
   cards plus the gap come to container + 25px, which is what keeps the third
   card peeking at the right edge. Percentages get within a pixel but drift;
   this does not. */
@media (min-width: 750px) {
  .dd-carousel {
    grid-auto-columns: calc((100% - var(--dd-gap-col)) / 2 + 12.5px);
    gap: var(--dd-gap-row) var(--dd-gap-col);
  }
}

@media (min-width: 990px) {
  .dd-carousel {
    grid-auto-columns: minmax(0, 1fr);
    grid-template-columns: repeat(3, minmax(0, 1fr));
    overflow-x: visible;               /* all three fit — no scrolling needed */
    scroll-snap-type: none;
    padding-bottom: 0;
  }
}

/* Products variant — ten cards, so it stays a scroller at every width.
   Column widths are deliberately fractional so the next card is always
   part-visible: that peek is what tells a visitor there is more to the right.
   The rule order matters — this block must beat the generic >=750 rule
   above, so it repeats the breakpoints rather than relying on cascade. */
/* Widths are the reference's own formulas, read from its stylesheets and
   confirmed against the measured 251px card at desktop (pixel spec §14).
   The 30px in the two lower bands is the reference's peek allowance; the
   6-col desktop rule subtracts the gap share, 16px x 5/6.

   The reference also starts its first card 15px from the viewport edge. That
   gutter is NOT reproduced here: any leading padding shrinks the box the
   percentages resolve against, which cost 3px on every card (248 instead of
   251). Card width is what §2 and §14 measure, so it wins over a 15px lead-in.
   Recorded in §14 as an accepted difference. */
.dd-carousel--products {
  grid-auto-columns: calc(50% - var(--dd-gap-col-mobile) - 30px);
}

@media (min-width: 750px) {
  .dd-carousel--products {
    grid-template-columns: none;       /* undo the 3-column resolve */
    grid-auto-columns: calc(50% - var(--dd-gap-col) - 30px);
    overflow-x: auto;
    scroll-snap-type: inline mandatory;
  }
}

@media (min-width: 990px) {
  .dd-carousel--products {
    grid-auto-columns: calc(16.66% - 13.333px);
  }
}

/* -------------------------------------------------------------------------
   Buttons — 47px tall, 41px radius (pill), charcoal fill, white text.
   Measured; constant at every viewport.
   ------------------------------------------------------------------------- */
.dd-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--dd-btn-height);
  padding-inline: 2rem;
  border: 1px solid var(--dd-btn);
  border-radius: var(--dd-btn-radius);
  background-color: var(--dd-btn);
  color: var(--dd-btn-text);
  font-size: 15px;
  font-weight: 300;
  letter-spacing: 1px;
  text-decoration: none;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.dd-btn:hover {
  background-color: transparent;
  color: var(--dd-btn);
}

.dd-btn--outline {
  background-color: transparent;
  color: var(--dd-btn);
}

.dd-btn--outline:hover {
  background-color: var(--dd-btn);
  color: var(--dd-btn-text);
}

/* Visible keyboard focus — the reference site's is very faint. */
.dd-btn:focus-visible,
.dd-link:focus-visible {
  outline: 3px solid var(--dd-btn);
  outline-offset: 3px;
}

/* The slim band above the hero is a plain underlined text link. */
.dd-link {
  color: var(--dd-ink-solid);
  text-decoration: underline;
  text-underline-offset: 4px;
  font-size: 20px;
  letter-spacing: 0.5px;
}

/* -------------------------------------------------------------------------
   Cards — 1:1 product imagery, rounded outline.

   These values are a deliberate design choice, NOT the measured reference:
   the reference renders cards with square corners and no outline, and does
   not use rgb(53,80,120) anywhere on the homepage (docs/homepage-pixel-spec.md
   §4, §5). Do not "correct" them back to the measured palette.

   box-sizing keeps the border inside the card's track width, so it does not
   change the carousel column maths.
   ------------------------------------------------------------------------- */
.dd-card {
  background-color: transparent;
  border: 0.1rem solid rgb(53, 80, 120, 0.1);
  border-radius: 20px;
  box-sizing: border-box;
}

/* Four-value form, clockwise from top-left: both TOP corners rounded to
   20px, both bottom corners square. This matches the card's own 20px top
   corners, so the image sits flush inside the outline; the square bottom is
   where the title and price sit below it. */
.dd-card img {
  width: 100%;
  height: auto;
  /* border-radius: 0; */
  border-radius: 20px 20px 0 0px;
  display: block;
}

/* Card titles are headings, so they take the heading face. Measured on the
   reference at 13px / 16.9px / 0.6px in solid navy — identical on the safety
   sets and the product cards. The 16px and 18px that stood here came from the
   same zero-box element that produced the wrong H2; see §17. */
.dd-card__title {
  font-family: var(--dd-font-heading);
  font-size: 13px;
  line-height: 16.9px;
  font-weight: 400;
  letter-spacing: 0.6px;
  color: var(--dd-navy);
  margin-block: 0.75rem 0.25rem;
}

/* -------------------------------------------------------------------------
   Press strip — full width, fixed label, logos on a continuous marquee.

   The track holds the seven logos TWICE. Animating it to -50% moves it by
   exactly one full set, so the moment it loops, set two is sitting where set
   one started and the join is invisible. This works at ANY gap value — the
   50% is relative to the doubled track, so widening the gap keeps the seam
   invisible without retuning anything.
   ------------------------------------------------------------------------- */
/* Corrected 2026-09-03, pixel spec §21. §19 said the reference had no border
   here and removed ours. Wrong — it has TWO, and both were missed because the
   check looked at the <section>, while the reference hangs them on an inner
   band element:

     band   1px solid #EBEBEB top AND bottom, white, 70px tall
     label  1px solid #E4E4E4 on its RIGHT — a divider before the logo track

   70px = 68px of band plus the two 1px borders, so the inner row is sized
   rather than padded. That matters: the label's divider has to span the full
   68px, which it cannot do if the height comes from padding on the section.

   TWO DELIBERATE DEVIATIONS from the reference, requested 2026-09-03:

     border      all four sides, not just top and bottom. The reference
                 measures borderLeft/borderRight at 0px, so the band runs to
                 the viewport edges there; here it is a closed box.
     margin-top  25px. The reference has none — its band sits flush against
                 the hero above it (hero ends at y=945, band starts at y=945).

   Both are design choices, not fidelity fixes. Do not "correct" them back. */
.dd-press-section {
  width: 100%;
  border: 1px solid #EBEBEB;
  margin-top: 25px;
  background-color: var(--dd-bg);
  overflow: hidden;
}

/* Full-bleed, no side padding — the label's own fixed width sets where the
   logos begin. */
.dd-press {
  display: flex;
  align-items: center;
  height: 68px;
  width: 100%;
}

/* A fixed 155px panel, not a run of text: it is opaque and sits above the
   track (z-index 2), so logos slide UNDER it and disappear behind the divider
   instead of colliding with the words. That is why the reference needs no
   edge-feathering on the left. The 9px/700/2px type is unchanged. */
.dd-press__label {
  flex: 0 0 155px;
  /* The row centres its children, which would leave this box only as tall as
     its text — and the divider is its right border, so it would stop short.
     Stretching it is what makes the divider span the full 68px band. */
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  z-index: 2;
  padding: 14px 16px;
  border-right: 1px solid #E4E4E4;
  background-color: var(--dd-bg);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 2px;
  color: #B0B0B0;
  white-space: nowrap;
}

/* Clips the moving track. The edge mask that used to live here is gone: the
   reference has none, because the opaque label panel covers the left edge and
   the right simply runs off. A mask would also have faded the logos passing
   behind the label, which is not what the reference does. */
.dd-press__viewport {
  flex: 1 1 auto;
  overflow: hidden;
  min-width: 0;
}

/* 162px gap, 50s linear — both measured off the reference's own carousel. */
.dd-press__track {
  display: flex;
  align-items: center;
  gap: 162px;
  width: max-content;
  animation: dd-marquee 50s linear infinite;
}

/* Pause on hover so a viewer can actually look at a logo. */
.dd-press:hover .dd-press__track { animation-play-state: paused; }

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

/* 40x40 with object-fit: contain — the source files are 200x200, so without
   `contain` a non-square logo would be cropped rather than letterboxed.
   Opacity is 0.65, not 0.7. */
.dd-press__logo {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  max-width: 120px;
  object-fit: contain;
  filter: grayscale(100%);
  opacity: 0.65;
  transition: opacity 0.2s ease, filter 0.2s ease;
}

.dd-press__logo:hover { filter: grayscale(0); opacity: 1; }

/* -------------------------------------------------------------------------
   Reduced motion — stop the marquee entirely and let the strip be scrolled
   by hand instead. An auto-scrolling strip is exactly what this preference
   exists to switch off.
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .dd-btn, .dd-press__logo { transition: none; }
  .dd-carousel { scroll-behavior: auto; }

  .dd-press__track {
    animation: none;
    width: auto;
    gap: 3rem;              /* 162px is for the moving strip; tighten when static */
    overflow-x: auto;
  }

  .dd-press__viewport {
    overflow-x: auto;
  }

  /* The duplicate set is decorative — hide it when nothing is scrolling. */
  .dd-press__track [aria-hidden="true"] { display: none; }
}

/* =========================================================================
   SITE HEADER — LiveCanvas partial (is_header), source in content/header.html

   Measured 2026-09-02 from damselindefense.net. Header heights are fixed per
   breakpoint and the logo never scales, so the padding does the work:

     >=990   20px top + 58px row + 18px gap + 42px nav + 24px bottom = 163px
     750-989 19px + 50px logo + 19px                                =  88px
     <500    10.5px + 50px logo + 10.5px                            =  71px

   Row one is a 3-column grid measured at 292.5 / 315 / 292.5 inside the
   1000px container, which is why the middle track is a fixed 315px rather
   than auto: it is what keeps the logo optically centred.
   ========================================================================= */
.dd-header {
  background-color: var(--dd-bg);
}

.dd-header__inner {
  width: 100%;
  max-width: var(--dd-container);
  margin-inline: auto;
  padding-block: 19px;
  padding-inline: var(--dd-pad-mobile);
}

/* Pixel QA 2026-09-02: this was `min-width: 500px`, which made 500 itself an
   88px header. The reference measures 71px AT 500 (§2), so the small-phone
   band is max-width and inclusive. Off-by-one on the boundary, not the value. */
@media (max-width: 500px) {
  .dd-header__inner { padding-block: 10.5px; }
}

@media (min-width: 750px) {
  .dd-header__inner { padding-inline: var(--dd-pad-desktop); }
}

@media (min-width: 990px) {
  .dd-header__inner {
    padding-top: 20px;
    padding-bottom: 24px;
  }
}

.dd-header__bar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}

@media (min-width: 990px) {
  .dd-header__bar {
    grid-template-columns: 1fr 315px 1fr;
    min-height: 58px;
  }
}

.dd-header__side { display: flex; align-items: center; }
.dd-header__side--start  { justify-content: flex-start; }
.dd-header__side--center { justify-content: center; }
.dd-header__side--end    { justify-content: flex-end; }

.dd-header__logo { display: block; line-height: 0; }

.dd-header__logo img {
  display: block;
  width: 300px;
  height: 50px;
}

/* Below ~330px the 300px wordmark plus padding no longer fits. Let it shrink
   rather than force a horizontal scrollbar — the measured widths stop at 500
   (pixel spec 11) so this band is defensive, not measured. */
@media (max-width: 400px) {
  .dd-header__logo img {
    width: 100%;
    max-width: 300px;
    height: auto;
  }
}

/* 44px hit area around a 20px glyph — the reference's own measurement, and
   comfortably above the 24px WCAG 2.2 target-size minimum. */
.dd-header__icon,
.dd-header__burger {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--dd-navy-75);
}

/* Account and cart are real links now. Their SVGs paint with currentColor, so
   without this they inherit the theme's default link colour instead of the
   navy set on .dd-header__icon — which is why they changed colour. */
.dd-header__icon a {
  display: inline-flex;
  color: inherit;
  text-decoration: none;
}

.dd-header__icon a:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: 2px;
  border-radius: 50%;
}

.dd-header__burger { cursor: pointer; }
.dd-header__burger:hover { color: var(--dd-navy); }

.dd-header__burger:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: 2px;
}

/* Search is left of the logo at desktop and in the right-hand cluster below
   it. Two elements, one hidden at each breakpoint — see content/header.html. */
.dd-header__icon--search-wide { display: none; }

@media (min-width: 990px) {
  .dd-header__burger,
  .dd-header__icon--search-narrow { display: none; }
  .dd-header__icon--search-wide { display: inline-flex; }
}

/* -------------------------------------------------------------------------
   Primary navigation — second row at >=990, collapse below.

   The .collapse rule below has to beat Bootstrap's .collapse:not(.show),
   which is (0,2,0). Scoping to .dd-header makes it (0,3,0), so the nav is
   permanently open at desktop without !important.
   ------------------------------------------------------------------------- */
@media (min-width: 990px) {
  .dd-header .dd-header__nav.collapse { display: block; }
}

.dd-nav {
  display: flex;
  flex-direction: column;
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 990px) {
  .dd-nav {
    flex-direction: row;
    justify-content: center;
    margin-top: 18px;
  }
}

.dd-nav__item { position: relative; }

/* 12px + 18px + 12px = the measured 42px item height. */
.dd-nav__link {
  display: block;
  padding: 12px;
  font-size: 14px;
  font-weight: 300;
  line-height: 18px;
  letter-spacing: 0.6px;
  color: var(--dd-navy-75);
  text-decoration: none;
}

.dd-nav__link:hover { color: var(--dd-navy); }

.dd-nav__link:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: -2px;
}

/* The reference underlines the current page rather than colouring it. */
.dd-nav__link.is-current {
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Dropdown parents measure 12px 27px 12px 12px — the extra right padding is
   the chevron's room. */
.dd-nav__item--parent .dd-nav__summary { padding-right: 27px; }

/* <summary> is a list-item by default in every engine; both of these are
   needed to lose the disclosure triangle. */
.dd-nav__summary {
  display: block;
  list-style: none;
  cursor: pointer;
}

.dd-nav__summary::-webkit-details-marker { display: none; }

.dd-nav__summary:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: -2px;
}

.dd-nav__chevron {
  position: absolute;
  top: 50%;
  right: 12px;
  transform: translateY(-50%);
  color: var(--dd-navy-75);
  pointer-events: none;
  transition: transform 0.15s ease;
}

/* Points up while the panel is open. */
.dd-nav__details[open] > .dd-nav__summary .dd-nav__chevron {
  transform: translateY(-50%) rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
  .dd-nav__chevron { transition: none; }
}

/* Below 990 the submenu is simply always open — nested toggles inside an
   already-toggled drawer are more to get wrong than they are worth. */
.dd-nav__submenu {
  list-style: none;
  margin: 0;
  padding: 0 0 0 12px;
}

/* Submenu links measure 8px 20px with 0.4px tracking — NOT the 0.6px the
   top-level nav uses. Measured 2026-09-02, pixel spec §15. */
.dd-nav__submenu a {
  display: block;
  padding: 8px 20px;
  font-size: 14px;
  font-weight: 300;
  line-height: 18px;
  letter-spacing: 0.4px;
  color: var(--dd-navy-75);
  text-decoration: none;
}

.dd-nav__submenu a:hover { color: var(--dd-navy); }

.dd-nav__submenu a:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: -2px;
}

/* Panel: 200px wide, 10px 0 padding, 6px radius, 1px navy-at-50% border,
   left-aligned with its parent. All measured 2026-09-02 — this replaces the
   220px guess that stood while §11 listed the panel as a coverage gap.

   Open/closed is now <details>' state, not a cascade trick: no opacity or
   visibility toggling, no :hover, no :focus-within. That is what makes it
   work on touch, and it is the mechanism the reference itself uses. */
@media (min-width: 990px) {
  .dd-nav__submenu {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 20;
    width: 200px;
    padding: 10px 0;
    background-color: var(--dd-bg);
    border: 1px solid var(--dd-navy-50);
    border-radius: 6px;
  }
}

/* =========================================================================
   SITE FOOTER — LiveCanvas partial (is_footer), source in content/footer.html

   Measured 2026-09-02: 448px tall at desktop. The top band is a 55/45 grid
   with a 30px gap in a 1000px container at 20px/15px padding — note the 15px
   side padding, which is NOT the 50px the page sections use.
   ========================================================================= */
.dd-footer {
  background-color: var(--dd-bg);
  color: var(--dd-navy-75);
}

.dd-footer__top { border-top: 1px solid var(--dd-rule); }

.dd-footer__inner {
  width: 100%;
  max-width: var(--dd-container);
  margin-inline: auto;
  padding: 20px 15px;
  display: grid;
  grid-template-columns: 55fr 45fr;
  gap: 30px;
  align-items: start;
}

/* The reference switches this block to one column at 768px, not at the 750px
   the rest of its own theme uses — the two-column footer was bolted on later
   with framework defaults. We collapse at 750 to stay consistent with every
   other breakpoint in this build; the 18px difference is deliberate and
   recorded in docs/homepage-pixel-spec.md 12. */
@media (max-width: 749.98px) {
  .dd-footer__inner {
    grid-template-columns: 1fr;
    gap: 20px;
    padding: 15px 10px;
  }
}

.dd-footer__label {
  margin: 0 0 7.5px;
  font-size: 11px;
  font-weight: 300;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--dd-navy-50);
}

/* Column-first fill: the reference reads DOWN the left column, then down the
   right. grid-auto-flow: column with a fixed row count is what produces that.
   11 links => 6 rows. Change this if links are added or removed. */
.dd-footer__linkgrid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(6, auto);
  grid-auto-flow: column;
  gap: 5px 15px;
}

.dd-footer__linkgrid a {
  font-size: 13px;
  line-height: 23px;
  color: var(--dd-navy-75);
  text-decoration: none;
}

.dd-footer__linkgrid a:hover { color: var(--dd-navy); }

.dd-footer__linkgrid a:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: 2px;
}

/* Newsletter — these radii (4px / 7px) and sizes are the live Klaviyo embed's
   own, NOT the brand's 41px pill. Measured rather than harmonised, because
   whatever email platform replaces it will bring its own styling anyway. */
.dd-footer__form {
  display: grid;
  gap: 8px;
  margin-top: 12px;
}

.dd-footer__field {
  width: 100%;
  height: 30px;
  padding: 0 10px;
  font-family: inherit;
  font-size: 18px;
  color: var(--dd-navy);
  background-color: var(--dd-bg);
  border: 1px solid var(--dd-navy-50);
  border-radius: 4px;
}

.dd-footer__field:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: 1px;
}

.dd-footer__submit {
  height: 34px;
  border: 0;
  border-radius: 7px;
  background-color: var(--dd-navy);
  color: #FFFFFF;
  font-family: inherit;
  font-size: 17px;
  font-weight: 300;
  letter-spacing: 0.5px;
  cursor: pointer;
}

.dd-footer__submit:hover { background-color: var(--dd-navy-dark); }

/* ---- Bottom band: social, payment, copyright ---- */
.dd-footer__bottom { border-top: 1px solid var(--dd-rule-ink); }

.dd-footer__inner--stack {
  display: block;
  padding-top: 30px;
}

/* 3 items x (20px glyph + 22px padding) = the measured 126px width. */
.dd-footer__social {
  display: flex;
  justify-content: center;
  list-style: none;
  margin: 0;
  padding: 0;
}

.dd-footer__social a {
  display: flex;
  align-items: center;
  padding: 11px;
  color: var(--dd-navy-75);
}

.dd-footer__social a:hover { color: var(--dd-navy); }

.dd-footer__social a:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: -2px;
}

/* Real card marks, 38x24 with 10px gaps — the reference's measured 230px row.
   The placeholder chips these replaced needed a border and a text style; the
   artwork carries its own, so both are gone.

   Each <svg> fills its 38x24 slot and `preserveAspectRatio` (the default
   xMidYMid meet) centres the artwork inside it. That only produces equal
   heights if every viewBox is TIGHT to its artwork — four of these shipped
   with square viewBoxes and vertical padding baked in, which made them fit
   against the 24px height and render 24x15 while Visa rendered a full 38x24.
   The viewBoxes in content/footer.html are now the measured bounding boxes.
   See pixel spec §22 before editing any of them. */
.dd-footer__payment {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 10px;
  list-style: none;
  margin: 15px 0 0;
  padding: 0;
}

.dd-footer__payment li {
  width: 38px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.dd-footer__payment svg {
  display: block;
  width: 100%;
  height: 100%;
}

.dd-footer__copyright {
  margin-top: 15px;
  text-align: center;
}

@media (min-width: 750px) {
  .dd-footer__copyright { text-align: left; }
}

/* Font size here was not captured on the reference — 12px is a choice. */
.dd-footer__copyright small {
  font-size: 12px;
  color: var(--dd-navy-50);
}

/* =========================================================================
   PRODUCT CARDS — measured 2026-09-02, pixel spec §14

   The product card is NOT the safety-set card. Reference measurements:

     card    251 x 487, white, 1px rgba(53,80,120,.1), radius 20px
     media   249 x 311  ->  4:5 PORTRAIT, object-fit: cover
     info    padding 17px 10px, centred
     title   18px / 400 / 23.4 line-height / 0.6px tracking, solid navy
     price   16px / 300 / 1px tracking, solid navy
     button  203 x 47, 41px pill, WHITE fill with MAGENTA text

   The safety-set card keeps its 1:1 media and existing title styling — that
   one was measured correctly the first time. Only these override.
   ========================================================================= */
.dd-card--product {
  display: flex;
  flex-direction: column;
  background-color: var(--dd-bg);
}

/* 4:5 portrait, cropped. The safety sets are 1:1; conflating the two is what
   §10 of the spec originally got wrong. */
.dd-card--product img {
  aspect-ratio: 4 / 5;
  height: auto;
  object-fit: cover;
}

/* The body fills whatever height is left, so `margin-top: auto` on the button
   parks it at the bottom of every card. Without this, a card with a one-line
   title sits its button higher than its two-line neighbours and the row of
   buttons reads as ragged. */
.dd-card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 17px 10px;
}

/* Whatever ends the body sits at the bottom. This has to live on the LAST
   CHILD rather than on .dd-btn--card: once the button is wrapped in a link,
   the anchor is the flex item and `margin-top: auto` on the button inside it
   does nothing. Same restore, same cause as the stacked images above. */
.dd-card__body > :last-child {
  margin-top: auto;
}

/* Product titles differ from the safety sets only in their margins — the type
   itself is identical, and comes from .dd-card__title above. */
.dd-card--product .dd-card__title {
  margin-block: 0 0.5rem;
}

.dd-card--product .dd-price {
  margin-bottom: 12px;
  font-size: 16px;
  font-weight: 300;
  letter-spacing: 1px;
  color: var(--dd-navy);
}

/* The card button — the one place the brand magenta appears. White fill,
   magenta text and border, 41px pill.

   The 1px border width is the reference's `--buttons-border-width` token
   (§3) rather than a direct measurement of this button. */
.dd-btn--card {
  display: block;
  width: 100%;
  max-width: 203px;
  height: 47px;
  margin-top: auto;              /* pins every button to the card's bottom */
  margin-inline: auto;
  padding: 8px;
  border: 1px solid var(--dd-magenta);
  border-radius: var(--dd-btn-radius);
  background-color: var(--dd-bg);
  color: var(--dd-magenta);
  font-family: inherit;
  font-size: 15px;
  font-weight: 300;
  letter-spacing: 1px;
  cursor: pointer;
  transition: box-shadow 0.2s ease;
}

/* Hover: thicker border and a drop shadow — measured 2026-09-03, §18.

   The reference thickens its border by drawing a ring with box-shadow on a
   ::after pseudo-element rather than changing border-width, because changing
   the width would shift the layout by a pixel on every hover. Same trick here,
   minus the pseudo-element: the first shadow is the ring (the reference's own
   --border-offset of 1.3px), the second is the drop shadow, whose 0 4px 5px
   geometry is measured from the reference's button ::before.

   The shadow's ALPHA is a choice — the reference keeps its resting shadow at
   zero alpha and the token that raises it on hover could not be read. */
.dd-btn--card:hover {
  box-shadow:
    0 0 0 1.3px var(--dd-magenta),
    0 4px 5px rgba(53, 80, 120, 0.3);
}

.dd-btn--card:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .dd-btn--card { transition: none; }
}

/* =========================================================================
   CARD HOVER STATES — measured 2026-09-02, pixel spec §16

   Values are the reference's own, from base.css and component-card.css. The
   reference body carries `animate--hover-3d-lift`, and its durations resolve
   to --duration-long: 500ms and --duration-extended: 3s.

   Three separate effects, all gated on a device that actually has hover:

     media   the image scales to 1.03 inside a clipped box
     card    a shadow fades in over 500ms, plus a 1deg rotation over 3s
     title   underlines

   Everything is inside (hover: hover) so touch devices — where :hover latches
   on tap and then sticks — get none of it, and inside no-preference so the
   whole block is skipped under reduced motion. That mirrors how the reference
   gates it, and it is why none of this needs a separate reduced-motion undo.
   ========================================================================= */
.dd-card__media {
  position: relative;            /* the containing block for a stacked second image */
  overflow: hidden;              /* this is what makes the zoom crop rather than spill */
  border-radius: 20px 20px 0 0;  /* matches the card's own top corners */
}

.dd-card__media img {
  display: block;
  width: 100%;
}

/* Cards link out to Shopify, so an <a> may wrap the image, the title, the
   price and the button. Anchors are inline by default, which would leave
   line-height gaps under the images and stop the body's flex layout working —
   so make every anchor inside a card behave as a block. */
/* Every anchor inside a card — product cards wrap the media, title, price and
   button; collection tiles wrap the media and the title directly, with no body
   element between. Matching on .dd-card covers both shapes. */
.dd-card a {
  display: block;
  /* The card is a link, but it should not LOOK like a run of link text: the
     reference underlines the title on hover only, and never the price or the
     button. Without this the anchors underline everything they wrap. */
  text-decoration: none;
  color: inherit;
}

/* A SECOND image overlays the first instead of stacking under it.
   Without this, two block-level images sit one above the other and the media
   box doubles in height. The first child still defines the box height; the
   second is taken out of flow and stretched over it.

   Targets the second CHILD, not `img + img`. The images are no longer adjacent
   siblings once each one is wrapped in its own link — that selector silently
   stopped matching after the 2026-09-04 restore and every product card broke.
   This form works whether the child is a bare <img> or an <a><img>.

   opacity: 0 lives HERE, not in the hover block below, so the second image is
   hidden on touch devices and under reduced motion too. Inside the hover query
   it would default to visible wherever hover does not exist, and the second
   image would permanently cover the first. */
.dd-card__media > :nth-child(2) {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.dd-card__media > :nth-child(2) img {
  height: 100%;
  object-fit: cover;
}

@media (prefers-reduced-motion: no-preference) and (hover: hover) {

  /* ---- Image zoom ----
     The reference transitions opacity at 0.4s cubic-bezier and transform at
     500ms ease. The LAST image in the box is the one that scales, so this
     works whether a card has one image or two: with one it simply zooms, and
     the moment a second <img> is added it becomes the swap-and-zoom the
     reference does on its product cards. */
  .dd-card__media img {
    transition: opacity 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94),
                transform 500ms ease;
  }

  .dd-card:hover .dd-card__media img:last-child {
    transform: scale(1.03);
  }

  /* Second image, when there is one: revealed on hover. Its resting opacity: 0
     is set outside this query — see the note on .dd-card__media > :nth-child(2). */
  .dd-card:hover .dd-card__media > :nth-child(2) { opacity: 1; }

  /* ---- Card lift ----
     Four shadows, copied from the reference: two faint 0.05 alpha shadows
     top-left and bottom-right, one transparent white spacer that exists only
     to hold a slot in the list, and the real one — 0.5 alpha, 2rem down,
     3.5rem blur, pulled back 2rem so it reads as a soft ground shadow.

     THE 1deg ROTATION WAS REMOVED. The reference declares
     `transform: rotate(1deg)` over a 3s transition, and reproducing it caused
     a visible flash as the card finished rotating: a rotated layer forces the
     browser to re-rasterise the card and its images, and the repaint lands as
     a flicker. It was near-imperceptible motion with a very perceptible
     artifact, so the shadow now carries the effect alone. Do not reinstate the
     transform without checking for that flash again. */
  .dd-card {
    transition: box-shadow 500ms ease;
  }

  .dd-card:hover {
    box-shadow:
      rgba(0, 0, 0, 0.05) -1rem -1rem 1rem -1rem,
      rgba(0, 0, 0, 0.05)  1rem  1rem 1rem -1rem,
      rgba(255, 255, 255, 0) 0 0 0.5rem 0,
      rgba(0, 0, 0, 0.5) 0 2rem 3.5rem -2rem;
  }
}

/* ---- Title underline ----
   Outside the motion query: it is a state change, not an animation, and it is
   the clearest signal that the card is a link. Confirmed live on the
   reference — hovering a product card underlines its title. */
.dd-card:hover .dd-card__title {
  text-decoration: underline;
}

/* =========================================================================
   BANNER LINK HOVER — measured 2026-09-03, pixel spec §18

   The "Shop the Guide" and "Join The Mission" banners are clickable images.
   Their hover is NOT a colour overlay, which is the obvious guess: the
   reference simply fades the image to 92% opacity over 0.2s.

       .clickable-banner-link:hover .clickable-banner-image { opacity: 0.92 }

   Against the white page that reads as a slight lightening, which is easy to
   mistake for a pale wash laid over the top. There is no overlay element, no
   background colour and no filter involved.

   Applied to every full-bleed image link, which covers both banners and the
   hero. The reference's hero is not a link at all, so it has no hover there —
   ours is, and a clickable image with no hover response is worse than a
   faithful one.
   ========================================================================= */
.dd-fullbleed a img {
  transition: opacity 0.2s ease;
}

.dd-fullbleed a:hover img {
  opacity: 0.92;
}

.dd-fullbleed a:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: 3px;
}

/* -------------------------------------------------------------------------
   Lifestyle collection cards — content padding and larger label.

   NOT a fidelity change. On the reference these labels do not exist as text
   at all: "EQUIP YOUR car" and the rest are baked into the artwork, and the
   card's <h3> is a zero-box element for screen readers only (which is also
   why §17's zero-box warning applies when measuring them).

   Ours renders the label as real text under the image, so it needs spacing
   the reference never had to provide. 16px and the 17px/10px padding are
   requested values, not measured ones — the padding matches the product
   card's info block so the two sections stay consistent.
   ------------------------------------------------------------------------- */
.dd-grid--collections .dd-card__title {
  margin-block: 0;
  padding: 17px 10px;
  font-size: 16px;
  line-height: 20.8px;
}

/* =========================================================================
   FOOTER NEWSLETTER — Gravity Forms skin

   The hand-built form was replaced with [gravityform id="1"]. Gravity ships
   its own styling — 38px fields, 3px radii, a blue submit — none of which is
   the measured design. These rules bring it back to the §12 values:

     field   30px tall, 4px radius, 18px, navy-50 border
     submit  full width, 34px tall, 7px radius, navy fill, white text, 17px

   Everything is scoped to .dd-footer__news so other Gravity forms elsewhere
   on the site keep their own appearance.
   ========================================================================= */

/* The form's own heading duplicates the .dd-footer__label above it. Cleaner
   still is title="false" description="false" on the shortcode — this hides it
   either way. */
.dd-footer__news .gform_heading {
  display: none;
}

.dd-footer__news .gform_wrapper {
  margin: 12px 0 0;
}

.dd-footer__news .gform_fields {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}

.dd-footer__news .gfield {
  margin: 0;
  padding: 0;
  border: 0;
}

/* The reference used placeholders with no visible labels. Hide them the
   accessible way — clipped, not display:none — so screen readers still get
   them. Better still, set "Field Label Visibility: Hidden" per field in the
   Gravity Forms editor; this covers it until then. */
.dd-footer__news .gfield_label,
.dd-footer__news .ginput_complex label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.dd-footer__news .ginput_container,
.dd-footer__news .ginput_complex,
.dd-footer__news .ginput_complex span {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
}

.dd-footer__news input[type="text"],
.dd-footer__news input[type="email"] {
  width: 100%;
  height: 30px;
  padding: 0 10px;
  font-family: inherit;
  font-size: 18px;
  color: var(--dd-navy);
  background-color: var(--dd-bg);
  border: 1px solid var(--dd-navy-50);
  border-radius: 4px;
}

.dd-footer__news input[type="text"]:focus-visible,
.dd-footer__news input[type="email"]:focus-visible {
  outline: 2px solid var(--dd-navy);
  outline-offset: 1px;
}

.dd-footer__news .gform_footer {
  margin: 8px 0 0;
  padding: 0;
}

/* Gravity's default submit is a 120px blue pill. Full width, navy, 7px — the
   same treatment the hand-built button had. */
.dd-footer__news .gform_footer input[type="submit"],
.dd-footer__news .gform_footer button {
  width: 100%;
  height: 34px;
  padding: 0;
  border: 0;
  border-radius: 7px;
  background-color: var(--dd-navy);
  color: var(--dd-btn-text);
  font-family: inherit;
  font-size: 17px;
  font-weight: 300;
  letter-spacing: 0.5px;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.dd-footer__news .gform_footer input[type="submit"]:hover,
.dd-footer__news .gform_footer button:hover {
  background-color: var(--dd-navy-dark);
}

/* Validation and confirmation messages, kept in the footer's own type. */
.dd-footer__news .gform_validation_errors,
.dd-footer__news .validation_message,
.dd-footer__news .gform_confirmation_message {
  margin-top: 8px;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  font-size: 13px;
  color: var(--dd-navy-75);
}

@media (prefers-reduced-motion: reduce) {
  .dd-footer__news .gform_footer input[type="submit"] { transition: none; }
}
