/* Design-token system + component library, ported from umbrellas-branded
   (coastal / Branded-TravisMathew family). To rebrand a new site off this
   scaffold, edit ONLY the :root custom properties below — every component
   rule references them, nothing else needs to change. See site.config.json's
   "palette" block, which documents the same tokens for reference.

   --ink-rgb / --cream-rgb: plain CSS can't derive r,g,b components from a
   hex custom property, so these are the rgba()-friendly triplets for --ink
   and --cream, kept BY HAND in sync with the hex values above -- every
   translucency/shadow effect in this file reads rgba(var(--ink-rgb),X)
   instead of baking its own copy of the number, so changing --ink here is
   the only edit a rebrand needs. If you change --ink or --cream, update
   the matching -rgb line too. */
:root {
  --ink: #101010;
  --ink-rgb: 16, 16, 16;
  --ink-soft: #3a3a3a;
  --sand: #f3f3f3;
  --sand-deep: #e6e6e6;
  --cream: #ffffff;
  --cream-rgb: 255, 255, 255;
  --paper: #ffffff;
  --fog: #b0b0b0;
  --muted: #717171;
  --line: #d2d2d2;
  --line-dim: #e8e8e8;
  --clay: #1a1a1a;
  --clay-deep: #333333;
  --tide: #40e0d0;
  --tide-deep: #14847a;
  --surf: #9fe3db;
  --ok: #2d6a4f;
  --ok-bg: #eff5f1;
  --ok-border: #c3dbcc;
  --ok-text: #1b5638;
  --footer-text: #d0d0d0;
  --footer-text-dim: #a0a0a0;
  --footer-text-faint: #808080;
  --band-text: #a0a0a0;
  /* Must name the SAME families as site.config.json's fonts.families --
     that list is what generate.py uses to build the Google Fonts <link>
     that actually downloads these font files; changing one without the
     other either loads a font this page never applies, or applies a font
     that was never downloaded. */
  --font-display: "Sora", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial,
    sans-serif;
  --font-body:
    "Atkinson Hyperlegible Next", -apple-system, BlinkMacSystemFont,
    "Helvetica Neue", Arial, sans-serif;
  --radius-s: 6px;
  --radius: 10px;
  --radius-l: 18px;
  --shadow-1:
    0 1px 2px rgba(var(--ink-rgb), 0.06), 0 4px 14px rgba(var(--ink-rgb), 0.05);
  --shadow-2:
    0 4px 18px rgba(var(--ink-rgb), 0.08),
    0 22px 60px rgba(var(--ink-rgb), 0.1);
  --container: 1240px;
  --gutter: clamp(18px, 4vw, 36px);
  --header-h: 68px;
}

* {
  box-sizing: border-box;
}

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

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--cream);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

img {
  max-width: 100%;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
  margin: 0;
}

h1 {
  font-size: clamp(34px, 4.4vw, 54px);
  text-wrap: balance;
}

h2 {
  font-size: clamp(26px, 3.4vw, 40px);
}

.wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

em.i {
  font-style: italic;
}

/* ---------- header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 60;
  background: rgba(var(--cream-rgb), 0.92);
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--line-dim);
}

.site-header__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  height: var(--header-h);
}

.brand {
  display: flex;
  align-items: center;
}

/* Header/footer brand logo (see site.config.json's logo_src/logo_src_white)
   -- height-constrained, width auto from the SVG's own intrinsic aspect
   ratio, so any replacement logo drops in without a CSS change as long as
   it's roughly wordmark-shaped rather than a tall/square mark. */
.main-logo {
  display: block;
  height: 42px;
  width: auto;
}

.nav {
  display: none;
  align-items: center;
  gap: 28px;
}

.nav a {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-soft);
  position: relative;
  transition: color 0.2s;
}

.nav a:hover {
  color: var(--ink);
}

.nav a::after {
  content: "";
  position: absolute;
  bottom: -5px;
  left: 0;
  width: 0;
  height: 1px;
  background: var(--clay);
  transition: width 0.25s ease;
}

.nav a:hover::after {
  width: 100%;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 16px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--paper);
  font: 500 13px var(--font-body);
  color: var(--ink);
  cursor: pointer;
  transition: all 0.18s;
}

.icon-btn:hover {
  border-color: var(--ink);
}

.icon-btn svg {
  width: 17px;
  height: 17px;
}

.cart-count {
  background: var(--clay);
  color: #fff;
  border-radius: 999px;
  min-width: 20px;
  height: 20px;
  display: inline-grid;
  place-items: center;
  font-size: 11px;
  font-weight: 600;
  padding: 0 6px;
}

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

.menu-btn {
  display: inline-flex;
  padding: 0 12px;
}

.mnav {
  display: none;
  flex-direction: column;
  padding: 8px var(--gutter) 16px;
  border-bottom: 1px solid var(--line-dim);
  background: var(--cream);
}

.mnav.is-open {
  display: flex;
}

.mnav a {
  padding: 11px 0;
  font-size: 15px;
  border-bottom: 1px solid var(--line-dim);
}

.mnav a:last-child {
  border: 0;
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 52px;
  padding: 0 26px;
  border-radius: 999px;
  font: 600 14px var(--font-body);
  letter-spacing: 0.01em;
  cursor: pointer;
  border: 1px solid transparent;
  transition: all 0.2s;
}

.btn svg {
  width: 17px;
  height: 17px;
}

.btn--primary {
  background: var(--ink);
  color: var(--cream);
  box-shadow: var(--shadow-1);
}

.btn--primary:hover {
  background: var(--tide-deep);
  box-shadow: var(--shadow-2);
}

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--line);
}

.btn--ghost:hover {
  border-color: var(--ink);
}

.btn--light {
  background: var(--cream);
  color: var(--ink);
}

.btn--light:hover {
  background: #fff;
}

.btn--clay {
  background: var(--clay);
  color: #fff;
}

.btn--clay:hover {
  background: var(--clay-deep);
}

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

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

.btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
  box-shadow: none;
}

.btn[disabled]:hover {
  background: var(--ink);
}

/* ---------- eyebrow / sections ---------- */
.eyebrow {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--tide-deep);
  display: block;
}

.eyebrow::before {
  content: "";
  display: inline-block;
  width: 28px;
  height: 1px;
  background: var(--tide);
  vertical-align: middle;
  margin-right: 14px;
  margin-bottom: 3px;
}

section {
  padding: clamp(56px, 9vh, 100px) 0;
}

.sec--sand {
  background: var(--sand);
}

.sec--paper {
  background: var(--paper);
}

.section-head {
  display: flex;
  align-items: end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 22px;
  margin-bottom: 38px;
}

.section-head h2 {
  max-width: 22ch;
}

.section-head p {
  max-width: 48ch;
  color: var(--ink-soft);
  margin: 12px 0 0;
}

/* Add this class to a .section-head wrapper that sits directly under an
   .eyebrow (see header()/section pattern in generate.py) to get the same
   14px breathing room umbrellas-branded uses between eyebrow and heading. */
.section-head--tight h2 {
  margin-top: 14px;
}

/* Centers the eyebrow/heading stack instead of the default space-between
   row -- used by the FAQ section, whose heading has no adjacent CTA to
   balance against. */
.section-head--center {
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
}

/* ---------- hero ---------- */
.hero {
  position: relative;
  overflow: hidden;
  padding: clamp(32px, 6vh, 64px) 0 clamp(36px, 7vh, 72px);
  background: var(--cream) url("../images/home-hero-bg-lg.jpg") center / cover
    no-repeat;
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(
      100deg,
      rgba(var(--cream-rgb), 0.94) 0%,
      rgba(var(--cream-rgb), 0.8) 34%,
      rgba(var(--cream-rgb), 0.25) 58%,
      rgba(var(--cream-rgb), 0) 72%
    ),
    radial-gradient(rgba(var(--ink-rgb), 0.035) 1px, transparent 1px);
  background-size:
    100% 100%,
    22px 22px;
  pointer-events: none;
}

.hero__grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
  align-items: center;
}

.hero h1 {
  margin: 18px 0 0;
}

.hero h1 em {
  font-size: 0.92em;
  font-style: italic;
  color: var(--tide-deep);
}

.hero__lede {
  color: var(--ink-soft);
  font-size: 17.5px;
  max-width: 52ch;
  margin: 20px 0 30px;
}

.hero__cta {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.hero__trust {
  display: flex;
  gap: 26px;
  flex-wrap: wrap;
  margin-top: 34px;
  padding-top: 22px;
  border-top: 1px solid var(--line-dim);
  font-size: 13.5px;
  color: var(--muted);
}

.hero__trust strong {
  color: var(--ink);
  font-weight: 600;
}

/* Single-image cycling carousel, ported from customcontigo's
   .hero-carousel/.carousel-slide (assets/hero.js does the cycling) --
   replaces the old multi-card photo collage above with one image at a
   time, specifically so the "which images" question is answered by a
   plain list (site.config.json's hero_images, or generate.py's
   hero_images() default) instead of a fixed 2-column layout that only
   ever fits 3 pictures. Framed like this scaffold's other product imagery
   (.pdp-media__main/.card__img) rather than customcontigo's bare/
   transparent version, for visual consistency with the rest of the site. */
.hero-carousel {
  position: relative;
  aspect-ratio: 1;
  overflow: hidden;
}

.carousel-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.9s ease;
}

.carousel-slide.active {
  opacity: 1;
}

.carousel-slide img {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  object-fit: contain;
}

/* ---------- brand bar (scrolling marquee) ---------- */
/* Ported from travismathew's #brand-bar -- pure CSS, no JS. The seamless
   loop comes from build_brand_bar() duplicating the term list twice in the
   DOM and animating a translateX(-50%) -- exactly half of the (doubled)
   total width, so the moment the first copy has scrolled fully offscreen
   the second copy is sitting exactly where the first one started. */
.brand-bar {
  border-block: 1px solid var(--line-dim);
  background: var(--paper);
  padding: 22px 0;
  overflow: hidden;
}

.brand-bar__inner {
  display: flex;
  align-items: center;
  gap: 48px;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 15px;
  color: var(--muted);
  white-space: nowrap;
  animation: marquee 45s linear infinite;
}

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

.brand-bar__inner span::after {
  content: "\2726";
  margin-left: 48px;
  color: var(--clay);
  font-style: normal;
}

@media (prefers-reduced-motion: reduce) {
  .brand-bar__inner {
    animation: none;
  }
}

/* ---------- shop controls (chips, no sidebar) ---------- */
.shop-controls {
  margin: 0 0 30px;
}

.filter-row {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 8px;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.filter-row::-webkit-scrollbar {
  display: none;
}

.chip {
  display: inline-flex;
  align-items: center;
  height: 40px;
  padding: 0 18px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--paper);
  font: 500 13px var(--font-body);
  color: var(--ink-soft);
  white-space: nowrap;
  cursor: pointer;
  transition: all 0.18s;
  flex: none;
}

.chip:hover {
  border-color: var(--ink);
  color: var(--ink);
}

.chip.is-active {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--cream);
}

.chip em {
  font-style: normal;
  opacity: 0.6;
  margin-left: 6px;
  font-weight: 400;
}

.chip.is-empty {
  opacity: 0.35;
  pointer-events: none;
}

.chip-div {
  flex: none;
  width: 1px;
  align-self: center;
  height: 22px;
  background: var(--line);
  margin: 0 8px;
}

.section-head > p {
  margin: 0;
}

/* ---------- product grid ---------- */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: clamp(16px, 2.2vw, 28px) clamp(14px, 1.8vw, 22px);
}

.card {
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--line-dim);
  transition:
    transform 0.22s ease,
    box-shadow 0.22s ease,
    border-color 0.22s ease;
  position: relative;
}

.card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-2);
  border-color: var(--line);
}

.card:focus-visible {
  outline: 2px solid var(--clay);
  outline-offset: 3px;
}

.card__img {
  position: relative;
  aspect-ratio: 1;
  background: var(--paper);
  border-bottom: 1px solid var(--line-dim);
  overflow: hidden;
}

.card__img img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 8%;
  transition: transform 0.45s ease;
  mix-blend-mode: multiply;
}

.card:hover .card__img img {
  transform: scale(1.045);
}

.card__badge {
  position: absolute;
  top: 11px;
  left: 11px;
  z-index: 2;
  background: var(--ink);
  color: var(--cream);
  font: 600 10px var(--font-body);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 5px 10px;
  border-radius: 999px;
}

.card__badge--brand {
  background: var(--clay);
}

.card__body {
  padding: 15px 16px 17px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  flex: 1;
}

.card__cat {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--muted);
}

.card__name {
  font-family: var(--font-display);
  font-size: 16.5px;
  font-weight: 600;
  line-height: 1.25;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 2.5em;
}

.card__sw {
  display: flex;
  gap: 5px;
}

.sw {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 1px solid rgba(var(--ink-rgb), 0.2);
}

.card__foot {
  margin-top: auto;
  padding-top: 11px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  border-top: 1px solid var(--line-dim);
}

.card__price {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  display: flex;
  align-items: baseline;
  gap: 5px;
}

.card__price small {
  font-family: var(--font-body);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.card__cta {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--clay);
  opacity: 0;
  transform: translateX(-4px);
  transition: all 0.22s;
}

.card:hover .card__cta,
.card:focus-visible .card__cta {
  opacity: 1;
  transform: none;
}

.empty {
  grid-column: 1/-1;
  padding: 64px 20px;
  text-align: center;
  color: var(--muted);
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background: var(--paper);
  margin-bottom: 80px;
}

.empty p {
  margin: 0 0 18px;
}

/* ---------- steps ---------- */
.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
}

.step-card {
  background: var(--paper);
  border: 1px solid var(--line-dim);
  border-radius: var(--radius);
  padding: 28px;
}

.step-card .n {
  font-family: var(--font-display);
  font-size: 34px;
  color: var(--surf);
  line-height: 1;
  margin-bottom: 14px;
}

/* Icon badge alternative to .n above -- see build_process_section()'s
   badge() in generate.py, driven by process.steps' optional per-step
   `icon` field in site.config.json (a Material Symbols Outlined glyph
   name, e.g. "local_shipping"). The glyph is a separate inner <span>
   deliberately NOT sharing .material-symbols-outlined's class here --
   Google's icon stylesheet sets its own display/font-size on that class,
   and at equal specificity would silently win over this centering/sizing
   since it loads after site.css. */
.step-card__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  margin-bottom: 14px;
  border-radius: 50%;
  background: var(--surf);
  color: var(--tide-deep);
}

.step-card__icon .material-symbols-outlined {
  font-size: 40px;
}

.step-card h3 {
  font-size: 19px;
  margin-bottom: 9px;
}

.step-card p {
  margin: 0;
  color: var(--ink-soft);
  font-size: 15px;
}

/* ---------- FAQ ---------- */
/* Ported from travismathew's #faq section -- a plain <details>/<summary>
   accordion, no JS needed. Content comes from site.config.json's faq
   array; see build_faq_section() in generate.py. */
.faq-list {
  display: flex;
  flex-direction: column;
  gap: 0;
  max-width: 820px;
  margin: 0 auto;
}

.faq {
  border-bottom: 1px solid var(--line-dim);
  padding: 22px 0;
}

.faq summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  cursor: pointer;
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 500;
  color: var(--ink);
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary::after {
  content: "+";
  flex: none;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 24px;
  color: var(--clay);
}

.faq[open] summary::after {
  content: "\2013";
}

.faq p {
  padding-top: 14px;
  color: var(--ink-soft);
  font-size: 15px;
  max-width: 70ch;
}

/* ---------- PDP ---------- */
.breadcrumb {
  font-size: 13px;
  color: var(--muted);
  padding: 20px 0;
}

.breadcrumb a:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.breadcrumb .sep {
  margin: 0 8px;
  color: var(--fog);
}

.pdp-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
  align-items: start;
  padding-bottom: 20px;
}

.pdp-grid > * {
  min-width: 0;
}

.pdp-media__main {
  background: var(--paper);
  border: 1px solid var(--line-dim);
  border-radius: var(--radius-l);
  aspect-ratio: 1;
  position: relative;
  overflow: hidden;
}

.pdp-media__main img {
  position: absolute;
  inset: 0;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 7%;
  mix-blend-mode: multiply;
}

.pdp-media__strip {
  display: flex;
  gap: 9px;
  margin-top: 12px;
  overflow-x: auto;
  padding-bottom: 4px;
  scrollbar-width: none;
}

.pdp-media__strip::-webkit-scrollbar {
  display: none;
}

.thumb {
  flex: none;
  width: 74px;
  height: 74px;
  border-radius: var(--radius-s);
  background: var(--paper);
  border: 1.5px solid var(--line-dim);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: border-color 0.18s;
}

.thumb img {
  position: absolute;
  inset: 0;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 6px;
  mix-blend-mode: multiply;
}

.thumb[aria-current="true"] {
  border-color: var(--ink);
}

.pdp-info__cat {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.pdp-info h1 {
  font-size: clamp(28px, 3.6vw, 42px);
  margin: 10px 0 14px;
}

/* Same "from $X.XX" convention as .card__price on the shop grid (same
   entry_price() value too) -- just larger, since this is the page's own
   hero context, not a compact grid card. */
.pdp-info__price {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin: 0 0 18px;
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 600;
}

.pdp-info__price small {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.pdp-info__desc {
  color: var(--ink-soft);
  font-size: 16px;
  margin: 0 0 26px;
}

/* ---------- whole-product out of stock ---------- */
/* Ported from travismathew's body.product-oos pattern (see generate.py's
   docstring): the markup is always present, hidden here by default, and
   pdp.js decides at runtime -- from colorways[].in_stock -- whether to add
   .product-oos to <body>, so a routine sync.py stock refresh is enough to
   show/hide it without a structural rebuild. */
.oos-notice {
  display: none;
}

body.product-oos .oos-notice {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  background: var(--sand);
  border: 1px solid var(--line-dim);
  border-radius: var(--radius);
  padding: 16px 18px;
  margin-bottom: 20px;
}

.oos-notice__icon {
  flex: none;
  margin-top: 1px;
  color: var(--clay);
}

.oos-notice__icon svg {
  width: 22px;
  height: 22px;
  display: block;
}

.oos-notice__text strong {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 3px;
}

.oos-notice__text p {
  font-size: 13px;
  color: var(--muted);
  margin: 0;
}

.pdp-block {
  border-top: 1px solid var(--line-dim);
  padding: 22px 0;
}

.pdp-block + .pdp-block {
  margin-top: 0px;
}

.pdp-block__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 15px;
}

.pdp-block__head h2 {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.pdp-block__head .hint {
  font-size: 12.5px;
  color: var(--fog);
}

.swatches {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.swatch {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  cursor: pointer;
  padding: 3px;
  background: var(--paper);
  border: 1.5px solid var(--line);
  position: relative;
  transition: border-color 0.18s;
}

.swatch i {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  border: 1px solid rgba(var(--ink-rgb), 0.18);
}

.swatch:hover {
  border-color: var(--ink-soft);
}

.swatch[aria-current="true"] {
  border-color: var(--ink);
}

.swatch.is-oos {
  opacity: 0.45;
}

.swatch.is-oos::after {
  content: "";
  position: absolute;
  inset: 9px;
  background: linear-gradient(
    45deg,
    transparent 45%,
    var(--muted) 45%,
    var(--muted) 55%,
    transparent 55%
  );
}

.color-selected {
  margin-top: 12px;
  font-size: 14.5px;
}

/* Size × qty matrix (apparel only -- see generate.py's module docstring)
   -- a stepper per size, not a single pick, so one "Add to quote" can
   cover a whole size run in one color at once. Ported from
   travismathew's product.css .size-matrix/.size-cell/.size-stepper
   (same --ink/--line/--paper/--sand tokens, so it dropped in close to
   verbatim) -- travismathew has no shared generator of its own, this
   pattern is individually copy-pasted per product page there; here it's
   one real code path in build_pdp()/pdp.js instead. */
.size-hint {
  margin: -6px 0 14px;
  font-size: 13px;
  color: var(--muted);
}

.size-matrix {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
  gap: 10px;
}

.size-cell {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.size-cell__label {
  font: 600 11px var(--font-body);
  letter-spacing: 0.08em;
  color: var(--ink-soft);
}

.size-cell__status {
  margin-top: -2px;
  font-size: 10px;
  color: var(--muted);
}

.size-cell.is-oos {
  opacity: 0.45;
}

.size-cell.is-oos .size-stepper {
  pointer-events: none;
}

.size-stepper {
  display: grid;
  grid-template-columns: 28px 1fr 28px;
  align-items: center;
  height: 40px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  overflow: hidden;
  transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
}

.size-stepper:focus-within {
  border-color: var(--tide);
  box-shadow: 0 0 0 3px rgba(var(--ink-rgb), 0.08);
}

.size-stepper.has-qty {
  border-color: var(--ink);
  background: var(--sand);
}

.size-stepper button {
  height: 100%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  color: var(--ink-soft);
  transition: background 0.15s, color 0.15s;
}

.size-stepper button:hover:not(:disabled) {
  background: var(--sand-deep);
  color: var(--ink);
}

.size-stepper button:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.size-stepper input {
  width: 100%;
  text-align: center;
  background: transparent;
  border: 0;
  font: 600 14px var(--font-body);
  color: var(--ink);
  -moz-appearance: textfield;
  padding: 0;
}

.size-stepper input::-webkit-outer-spin-button,
.size-stepper input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.color-selected b {
  font-weight: 600;
}

.color-selected .st {
  color: var(--ok);
  font-size: 13px;
}

.color-selected .st.no {
  color: var(--clay);
}

.tiers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 8px;
}

.tier {
  border: 1px solid var(--line-dim);
  border-radius: var(--radius-s);
  padding: 11px 12px;
  background: var(--paper);
  transition: all 0.18s;
}

.tier[data-on="true"] {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--cream);
}

.tier__qty {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.tier[data-on="true"] .tier__qty {
  color: var(--surf);
}

.tier__price {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 600;
  margin-top: 3px;
  font-variant-numeric: tabular-nums;
}

.buy {
  background: var(--sand);
  border: 1px solid var(--line-dim);
  border-radius: var(--radius);
  padding: 20px;
  margin-top: 22px;
  margin-bottom: 44px;
}

.buy__row {
  display: flex;
  gap: 16px;
  align-items: flex-end;
  flex-wrap: wrap;
}

.qty label {
  display: block;
  font: 600 10.5px var(--font-body);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 7px;
}

.qty input {
  width: 118px;
  font: 600 18px var(--font-body);
  padding: 12px 14px;
  border-radius: var(--radius-s);
  border: 1px solid var(--line);
  background: var(--paper);
  font-variant-numeric: tabular-nums;
}

.qty input:focus {
  outline: 2px solid var(--clay);
  outline-offset: -1px;
}

.buy__tot {
  margin-left: auto;
  text-align: right;
}

.buy__tot b {
  display: block;
  font-family: var(--font-display);
  font-size: 27px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.buy__tot span {
  font-size: 12.5px;
  color: var(--muted);
}

.buy .btn {
  margin-top: 16px;
}

.note {
  font-size: 13px;
  color: var(--muted);
  margin-top: 11px;
}

.warn {
  font-size: 13.5px;
  color: var(--clay);
  margin-top: 10px;
  display: none;
}

.warn.is-on {
  display: block;
}

.features {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: 14.5px;
}

.features li {
  display: flex;
  gap: 18px;
  padding: 10px 0;
  border-top: 1px solid var(--line-dim);
}

.features li:first-child {
  border: 0;
  padding-top: 0;
}

.features b {
  flex: none;
  color: var(--muted);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding-top: 3px;
}

/* ---------- prose / seo ---------- */
.seo-section {
  background: var(--sand);
  padding: clamp(28px, 4vw, 60px);
}

/* Category pages sit this section directly under #shop.sec--sand (see
   build_category() in generate.py) -- same --sand tone on both means the
   card has no visible edge against the section above it, breaking the
   sand/paper alternation build_home() already uses between its own
   adjacent sections (#shop sand -> #process paper -> #faq sand). Paper
   restores that contrast without changing the component itself. */
.seo-section--paper {
  background: var(--paper);
}

.seo-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 30px;
}

.seo-col h2 {
  font-size: 23px;
  margin-bottom: 12px;
}

.seo-col p {
  color: var(--ink-soft);
  margin: 0 0 14px;
  max-width: 66ch;
}

.seo-col p:last-child {
  margin-bottom: 0;
}

.seo-col h3 {
  font-size: 17px;
  margin: 20px 0 10px;
}

.seo-list {
  color: var(--ink-soft);
  margin: 0 0 14px;
  padding-left: 20px;
  max-width: 66ch;
}

.seo-list li {
  margin-bottom: 8px;
}

.seo-list li:last-child {
  margin-bottom: 0;
}

/* ---------- legal / policy page ---------- */
/* Ported from travismathew's main.css, same token names throughout so it
   dropped in with no new colors -- used for the generated return-policy
   page (build_return_policy() in generate.py) and any other prose-heavy
   legal content (terms, privacy) a future site adds the same way.

   travismathew's original used --tide-deep (a branded accent) for h2/
   link color and --fog for table header text/borders -- fine for
   marketing copy, but this page carries the actual policy terms (return
   windows, restocking %, quantity-variance tolerance), so it gets a
   plainer, higher-contrast treatment instead: --ink for headings/links
   (neutral, not a brand color) and --muted in place of --fog everywhere
   in the table, which measured 2.01:1 against --cream -- well under
   WCAG AA's 4.5:1 floor for text and barely visible at all for the
   table's own column headers. --muted clears 5.5:1. */
.legal-page {
  padding: clamp(28px, 5vh, 40px) 0 clamp(60px, 9vh, 100px);
}

.legal-page__inner h1 {
  margin: 14px 0 28px;
}

.legal-page__inner h2 {
  font-size: 1.2rem;
  margin: 40px 0 12px;
  color: var(--ink);
}

.legal-page__inner p {
  color: var(--ink-soft);
  margin-bottom: 14px;
  line-height: 1.7;
  max-width: 75ch;
}

.legal-page__inner a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.legal-page__inner ul,
.legal-page__inner ol {
  color: var(--ink-soft);
  line-height: 1.7;
  margin: 0 0 16px 22px;
  max-width: 75ch;
}

.legal-page__inner li {
  margin-bottom: 6px;
}

.legal-page__inner strong {
  color: var(--ink);
  font-weight: 600;
}

.legal-page__inner hr {
  border: none;
  border-top: 1px solid var(--line-dim);
  margin: 32px 0;
}

.legal-page__inner blockquote {
  border-left: 3px solid var(--line);
  padding-left: 16px;
  margin: 16px 0;
  color: var(--ink-soft);
  font-style: italic;
}

.legal-page__meta {
  color: var(--muted);
  font-size: 13px;
  margin-bottom: 8px;
}

.legal-page__intro {
  font-size: 1.02rem;
}

.table-scroll {
  overflow-x: auto;
  margin: 8px 0 28px;
}

.legal-page__inner table {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  font-size: 13.5px;
}

.legal-page__inner th,
.legal-page__inner td {
  text-align: left;
  padding: 10px 14px;
  border-bottom: 1px solid var(--muted);
  vertical-align: top;
}

.legal-page__inner th {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 2px solid var(--muted);
}

/* Below the table's min-width, drop the scrolling grid in favor of stacked
   label/value cards -- easier to read on a phone than a sideways-scrolling
   table. */
@media (max-width: 640px) {

  .table-scroll {
    overflow-x: visible;
  }

  .legal-page__inner table {
    min-width: 0;
  }

  .legal-page__inner thead {
    display: none;
  }

  .legal-page__inner table,
  .legal-page__inner tbody,
  .legal-page__inner tr,
  .legal-page__inner td {
    display: block;
    width: 100%;
  }

  .legal-page__inner tr {
    margin-bottom: 18px;
    border: 1px solid var(--muted);
    border-radius: var(--radius-s);
    overflow: hidden;
  }

  .legal-page__inner tr:last-child {
    margin-bottom: 0;
  }

  .legal-page__inner td {
    border-bottom: 1px solid var(--muted);
    padding: 10px 14px;
  }

  .legal-page__inner td:last-child {
    border-bottom: none;
  }

  .legal-page__inner td::before {
    content: attr(data-label);
    display: block;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 4px;
  }

  .legal-page__inner td:first-child {
    background: var(--sand);
    font-size: 14px;
  }

  .legal-page__inner td:first-child::before {
    content: none;
  }
}

/* ---------- cart / checkout ---------- */
.lines {
  border: 1px solid var(--line-dim);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--paper);
}

.line {
  display: grid;
  grid-template-columns: 80px 1fr auto;
  gap: 16px;
  padding: 16px;
  align-items: center;
  border-bottom: 1px solid var(--line-dim);
}

.line:last-child {
  border: 0;
}

.line__img {
  background: var(--paper);
  border: 1px solid var(--line-dim);
  border-radius: var(--radius-s);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  padding: 7px;
}

.line__img img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  mix-blend-mode: multiply;
}

.line__n {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 15.5px;
}

.line__m {
  font-size: 13px;
  color: var(--muted);
  margin-top: 3px;
}

.line__p {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.line__p b {
  display: block;
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
}

.line__p button {
  background: none;
  border: 0;
  color: var(--muted);
  font-size: 12.5px;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 5px 0 0;
}

.line__p button:hover {
  color: var(--clay);
}

.sum {
  display: flex;
  justify-content: space-between;
  padding: 18px;
  background: var(--sand);
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  border-top: 1px solid var(--line-dim);
}

.form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.field.full {
  grid-column: 1/-1;
}

.field label {
  font: 600 10.5px var(--font-body);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.field label .required {
  color: var(--clay);
}

.field-hint {
  font-size: 12px;
  color: var(--muted);
  margin-top: 4px;
}

.field input,
.field textarea,
.field select {
  font: 400 15px var(--font-body);
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-s);
  background: var(--paper);
  width: 100%;
  min-width: 0;
  color: var(--ink);
}

/* Selects get no arrow of their own -- appearance:none replaces each
   browser's native (inconsistently-spaced, edge-hugging) one with a fixed
   chevron and real breathing room from the right edge. Color is the hex
   for --muted, hardcoded: a data-URI SVG renders in its own document
   context, so var() isn't reliably available inside it. */
.field select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B6355' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 14px;
}

.field textarea {
  min-height: 106px;
  resize: vertical;
}

.field input:focus,
.field textarea:focus,
.field select:focus {
  outline: 2px solid var(--clay);
  outline-offset: -1px;
}

.ok-panel {
  background: var(--ok-bg);
  border: 1px solid var(--ok-border);
  color: var(--ok-text);
  padding: 26px;
  border-radius: var(--radius);
  max-width: 62ch;
}

.ok-panel h2 {
  font-size: 23px;
  margin-bottom: 8px;
}

.ok-panel p {
  margin: 0 0 10px;
}

.ok-panel p:last-child {
  margin: 0;
}

.hp {
  display: none;
}

.thanks {
  /* scales with screen height, same approach as .legal-page */
  padding-top: clamp(48px, 9vh, 96px);
  padding-bottom: clamp(72px, 12vh, 140px);
}

.thanks h1 {
  margin: 14px 0 14px;
}

.thanks .actions {
  margin-top: 26px;
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.error-page {
  text-align: center;
  max-width: 70ch;
}

.error-page h1 {
  margin: 16px 0 14px;
}

.error-page p {
  color: var(--ink-soft);
  margin: 0 auto 26px;
  max-width: 52ch;
}

.error-page .filter-row {
  justify-content: center;
  margin-top: 34px;
}

.checkout h1 {
  margin: 14px 0 12px;
}

.checkout > p {
  color: var(--ink-soft);
  max-width: 58ch;
  margin: 0 0 36px;
}

.checkout .btn--full {
  margin-top: 20px;
}

.cart-empty p {
  margin: 0 0 20px;
}

/* Checkout's two-column layout: form first/left (wider), order summary
   second/right (narrower, sticky at desktop) -- ported from travismathew's
   checkout-grid/summary split. Mobile-first: single column below 960px,
   same breakpoint travismathew uses for both the column split and the
   summary's sticky behavior, so there's no in-between width where the
   layout is two columns but not yet sticky. */
.two {
  display: grid;
  grid-template-columns: 1fr;
  gap: 30px;
  align-items: start;
}

@media (min-width: 960px) {
  .two {
    grid-template-columns: minmax(0, 1fr) minmax(380px, 460px);
    gap: 44px;
  }

  .summary {
    position: sticky;
    top: calc(var(--header-h) + 20px);
    max-height: calc(100vh - var(--header-h) - 40px);
    overflow-y: auto;
  }
}

.checkout-form {
  background: var(--paper);
  border: 1px solid var(--line-dim);
  border-radius: var(--radius-l);
  padding: clamp(24px, 4vw, 40px);
  margin-bottom: 80px;
}

.section + .section {
  margin-top: 36px;
}

.section__head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 18px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line-dim);
}

.section__head h2 {
  font-size: 1.4rem;
  font-weight: 500;
}

.step-num {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 1.15rem;
  color: var(--clay);
  font-weight: 400;
}

/* ---------- logo upload ---------- */
.drop {
  position: relative;
  border: 1.5px dashed var(--line);
  border-radius: var(--radius);
  background: var(--paper);
  padding: 22px 18px;
  text-align: center;
  cursor: pointer;
  transition:
    border-color 0.18s,
    background 0.18s;
}

.drop:hover,
.drop.is-over {
  border-color: var(--clay);
  background: var(--sand);
}

.drop input[type="file"] {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
  width: 100%;
  height: 100%;
}

.drop__ico {
  width: 26px;
  height: 26px;
  margin: 0 auto 8px;
  color: var(--muted);
}

.drop__ico svg {
  width: 100%;
  height: 100%;
}

.drop__main {
  font-size: 14.5px;
  font-weight: 600;
}

.drop__main u {
  text-decoration: underline;
  text-underline-offset: 3px;
  color: var(--clay);
}

.drop__hint {
  font-size: 12px;
  color: var(--muted);
  margin-top: 5px;
}

.drop.has-file {
  border-style: solid;
  border-color: var(--tide);
  background: var(--paper);
  text-align: left;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
}

.drop.has-file .drop__ico {
  margin: 0;
  color: var(--tide-deep);
}

.file-name {
  font-size: 14px;
  font-weight: 600;
  word-break: break-all;
}

.file-size {
  font-size: 12px;
  color: var(--muted);
}

.file-clear {
  margin-left: auto;
  background: none;
  border: 0;
  color: var(--muted);
  font-size: 12.5px;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  flex: none;
  z-index: 2;
  position: relative;
}

.file-clear:hover {
  color: var(--clay);
}

.file-err {
  font-size: 13px;
  color: var(--clay);
  margin-top: 8px;
  display: none;
}

.file-err.is-on {
  display: block;
}

/* ---------- quote drawer (TravisMathew pattern) ---------- */
.overlay {
  position: fixed;
  inset: 0;
  background: rgba(var(--ink-rgb), 0.5);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s;
  z-index: 90;
}

.overlay.is-open {
  opacity: 1;
  pointer-events: auto;
}

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  height: 100%;
  width: 100%;
  max-width: 440px;
  background: var(--cream);
  transform: translateX(100%);
  transition: transform 0.32s cubic-bezier(0.2, 0.8, 0.2, 1);
  z-index: 100;
  display: flex;
  flex-direction: column;
}

/* box-shadow only while open: it's on the drawer's own box, so a
   translateX(100%) closed state still renders (and moves with) the
   shadow's blur -- with a leftward, 60px-blur shadow that bleeds back in
   past the drawer's off-screen edge as a stray sliver at the container's
   right edge. Fixed the same way travismathew's cart-shadow fix did:
   scope the shadow to .is-open so it doesn't exist at all while closed. */
.drawer.is-open {
  transform: translateX(0);
  box-shadow: -20px 0 60px rgba(0, 0, 0, 0.18);
}

.drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 22px 24px;
  border-bottom: 1px solid var(--line-dim);
}

.drawer__head h3 {
  font-family: var(--font-display);
  font-size: 1.35rem;
}

.drawer__body {
  flex: 1;
  overflow-y: auto;
  padding: 22px 24px;
  -webkit-overflow-scrolling: touch;
}

.drawer__foot {
  padding: 22px 24px;
  border-top: 1px solid var(--line-dim);
  background: var(--paper);
}

.drawer__foot .note {
  text-align: center;
}

.close-btn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--ink);
  transition: background 0.2s;
}

.close-btn:hover {
  background: var(--sand);
}

.close-btn svg {
  width: 18px;
  height: 18px;
}

.cart-item {
  display: grid;
  grid-template-columns: 72px 1fr auto;
  gap: 14px;
  padding: 16px 0;
  border-bottom: 1px solid var(--line-dim);
  align-items: start;
}

.cart-item:last-child {
  border-bottom: 0;
}

.cart-item__img {
  width: 72px;
  height: 72px;
  background: var(--paper);
  border: 1px solid var(--line-dim);
  border-radius: var(--radius-s);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.cart-item__img img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 6px;
  mix-blend-mode: multiply;
}

.cart-item__info h5 {
  font-family: var(--font-display);
  font-size: 0.98rem;
  font-weight: 600;
  margin: 0 0 2px;
  line-height: 1.25;
}

.cart-item__meta {
  font-size: 12px;
  color: var(--muted);
  margin-bottom: 8px;
}

.cart-item__right {
  text-align: right;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-end;
}

.cart-item__price {
  font-size: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.cart-item__remove {
  font-size: 11px;
  color: var(--muted);
  text-decoration: underline;
  text-underline-offset: 3px;
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0;
}

.cart-item__remove:hover {
  color: var(--clay);
}

.drawer__sum {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 14px;
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 600;
}

.drawer__sum small {
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.drawer__empty {
  text-align: center;
  color: var(--muted);
  padding: 48px 10px;
}

.drawer__empty p {
  margin: 0 0 18px;
}

body.no-scroll {
  overflow: hidden;
}

/* ---------- contact band ---------- */
/* Closing homepage CTA, ported from travismathew's #contact section --
   a plain mailto contact option that bypasses the quote cart entirely.
   See build_contact_band() in generate.py and site.config.json's
   contact_band block. */
.band {
  background: var(--ink);
  color: var(--cream);
  position: relative;
  overflow: hidden;
  padding: clamp(60px, 9vh, 100px) 0;
}

.band::before,
.band::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  opacity: 0.6;
  pointer-events: none;
}

.band::before {
  width: 420px;
  height: 420px;
  background: var(--tide);
  left: -120px;
  top: -100px;
}

.band::after {
  width: 520px;
  height: 520px;
  background: var(--clay);
  right: -160px;
  bottom: -200px;
  opacity: 0.25;
}

.band .eyebrow {
  color: var(--surf);
}

.band .eyebrow::before {
  background: var(--surf);
}

.band__inner {
  position: relative;
  z-index: 1;
  text-align: center;
}

.band__inner h2 {
  margin: 18px 0 16px;
  color: var(--cream);
}

.band__inner h2 em {
  font-style: italic;
  color: var(--surf);
}

.band__inner p {
  margin: 0 auto 28px;
  max-width: 55ch;
  color: var(--band-text);
}

.band__cta {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: center;
}

.band__cta .btn--ghost {
  color: var(--cream);
  border-color: var(--cream);
}

.band__cta .btn--ghost:hover {
  background: var(--cream);
  color: var(--ink);
}

/* .btn--clay's own background (var(--clay)) is a near-black neutral here,
   nearly indistinguishable from .band's own var(--ink) background -- clay
   is also used elsewhere as plain text/border color, so it's overridden
   just for this button rather than changed at the token level. */
.band__cta .btn--clay {
  background: var(--tide);
  color: var(--ink);
}

.band__cta .btn--clay:hover {
  background: var(--tide-deep);
  color: var(--cream);
}

/* ---------- footer ---------- */
.site-footer {
  background: var(--ink);
  color: var(--footer-text);
  padding: 56px 0 32px;
  font-size: 14px;
}

.footer-blurb {
  max-width: 44ch;
  margin: 16px 0 0;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
}

.site-footer h4 {
  color: var(--cream);
  font-family: var(--font-body);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin-bottom: 14px;
}

.site-footer a {
  display: block;
  padding: 4px 0;
  color: var(--footer-text);
}

.site-footer a:hover {
  color: var(--cream);
}

.site-footer .fine {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  margin-top: 34px;
  padding-top: 22px;
  font-size: 12.5px;
  color: var(--footer-text-faint);
}

@media (min-width: 760px) {

  .hero__grid {
    grid-template-columns: 1.15fr 1fr;
    gap: 56px;
  }

  .seo-grid {
    grid-template-columns: 1fr 1fr;
    gap: 44px;
  }

  .footer-grid {
    grid-template-columns: 1.3fr 1fr 1fr 1fr;
  }
}

@media (min-width: 960px) {

  .nav {
    display: flex;
  }

  .menu-btn {
    display: none;
  }

  .pdp-grid {
    grid-template-columns: 1.05fr 0.95fr;
    gap: 56px;
  }

  /* Sticky product image, ported from travismathew's product.css: the media
     column pins below the sticky header while you scroll the info column
     (specs, related products) beside it. Pure CSS -- position:sticky is
     scoped to how tall .pdp-grid itself is, so it un-sticks on its own once
     you scroll past the grid, no JS needed. Left at the default `static`
     below this breakpoint, where the columns stack and pinning would just
     trap the image mid-page. */
  .pdp-media {
    position: sticky;
    top: calc(var(--header-h) + 20px);
  }
}

/* Header must never overflow: logo + Quote button is easy to clip on a
   375px row if a replacement logo image runs wide -- test this on every
   new site's logo_src, not just the placeholder this was tuned for. */
@media (max-width: 640px) {

  .main-logo {
    height: 40px;
  }

  .icon-btn {
    padding: 0 13px;
    gap: 6px;
  }

  .site-header__row {
    gap: 10px;
  }
}

@media (max-width: 400px) {

  .icon-btn span:not(.cart-count) {
    display: none;
  }

  .menu-btn {
    padding: 0 10px;
  }
}

@media (max-width: 759px) {

  .steps {
    grid-template-columns: 1fr;
  }

  .form {
    grid-template-columns: 1fr;
  }

  .grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .card__body {
    padding: 12px 12px 14px;
  }

  .card__name {
    font-size: 14.5px;
  }

  .card__cta {
    display: none;
  }

  .line {
    grid-template-columns: 60px 1fr;
    row-gap: 10px;
  }

  .line__p {
    grid-column: 2;
    text-align: left;
  }

  .buy__tot {
    margin-left: 0;
    text-align: left;
    width: 100%;
  }
}
