@charset "utf-8";

/* ============================================================
   Raw Dog Towels, credibility site (redesign)

   Direction: "sewn panels". The page is built from full-bleed
   fields taken off the product, butted together and joined by an
   overlocked stitch seam. The stock colourways change from run to
   run; the white overlocked trim does not, so it is the recurring
   device rather than any one colour.

   The hero is the one exception and carries no stitching at all. It
   is a single photograph, so the device would be competing with the
   picture instead of joining anything to it.

   Palette: two darks and one accent. The teal-black carries the bar,
   the founder band and the footer; the near-black carries the hero
   and the photograph band, because pictures want a neutral field
   rather than a coloured one; the teal is the only accent, and it is
   the same teal the towels come in. Nothing on the page is brighter
   than that on purpose.

   Shared by all five pages. Static, no build step.
   ============================================================ */

/* ---------- tokens ---------- */

:root{
  /* Every colour is taken off the product itself. */
  --tide:      #07222A;   /* deep teal-black, the teal colourway run down */
  --tide-lift: #0D3038;   /* raised surface on tide */
  --ink:       #0C0C0E;   /* near-black, the field photographs sit on */
  --ink-raised:#17171A;   /* raised surface on ink */
  --teal:      #1D6E80;   /* teal colourway, and the one accent on the site */
  --teal-lift: #268CA3;
  --laundered: #D9E1E1;   /* a towel after fifty washes */
  --laundered-deep:#C6D2D2;
  --chalk:     #FFFFFF;   /* the overlock trim */
  --grit:      #4A5B60;   /* body text, second rank, on light */
  --grit-dark: #93A8AC;   /* body text, second rank, on dark */

  --hair-light: rgba(7,34,42,.16);
  --hair-dark:  rgba(255,255,255,.18);

  /* Thread colour for the stitch device. Bands override it. */
  --stitch: rgba(7,34,42,.72);

  --display: 'Archivo', 'Archivo Black', 'Arial Black', sans-serif;
  --body: 'Instrument Sans', ui-sans-serif, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  --wrap: 1240px;
  --gutter: clamp(20px, 4.6vw, 60px);
  --bar-h: 82px;

  /* Cut fabric has no rounded corners. */
  --r: 0;
}

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

html{
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior: auto; }
}

body{
  margin: 0;
  background: var(--laundered);
  color: var(--tide);
  font-family: var(--body);
  font-size: clamp(16.5px, .55rem + .45vw, 18px);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* height:auto is load-bearing. The width/height attributes on each <img>
   reserve layout space, but without this they also pin the rendered height
   to the raw pixel value and any CSS aspect-ratio is ignored. */
img{ max-width: 100%; height: auto; display: block; }

a{ color: inherit; }

::selection{ background: var(--teal); color: #fff; }

:focus-visible{
  outline: 3px solid var(--tide);
  outline-offset: 3px;
}
/* Reversed out wherever the field is dark, or the ring vanishes into it. */
.hero :focus-visible,
.bar :focus-visible,
.band--tide :focus-visible,
.band--ink :focus-visible,
.band--teal :focus-visible,
.site-foot :focus-visible,
.wa-bar :focus-visible{ outline-color: var(--chalk); }

.skip{
  position: absolute; left: -9999px; top: 0;
  background: var(--tide); color: #fff;
  padding: 12px 18px; z-index: 300; font-weight: 600;
}
.skip:focus{ left: 12px; top: 12px; }

/* ---------- type ---------- */

h1, h2, h3, h4{
  font-family: var(--display);
  font-variation-settings: 'wdth' 112, 'wght' 850;
  text-transform: uppercase;
  line-height: .94;
  letter-spacing: -.005em;
  margin: 0;
  text-wrap: balance;
}

/* The width axis is part of the design, not a fallback. Headlines run
   near-condensed on a phone so they still break where they should, and
   open out to their full expanded weight once there is room. */
@media (min-width: 760px){
  h1, h2{ font-variation-settings: 'wdth' 118, 'wght' 880; }
}

h1{ font-size: clamp(2.6rem, 1.15rem + 4.9vw, 5rem); }
h2{ font-size: clamp(2rem, 1.1rem + 3.6vw, 3.6rem); }
h3{
  font-size: clamp(1.05rem, .95rem + .5vw, 1.3rem);
  font-variation-settings: 'wdth' 106, 'wght' 780;
  letter-spacing: .005em;
  line-height: 1.12;
}
h4{
  font-size: .95rem;
  font-variation-settings: 'wdth' 104, 'wght' 760;
  letter-spacing: .02em;
}

p{ margin: 0 0 1.05em; text-wrap: pretty; }
p:last-child{ margin-bottom: 0; }

strong{ font-weight: 600; }

.deck{
  font-size: clamp(1.08rem, 1rem + .45vw, 1.3rem);
  line-height: 1.5;
  color: var(--grit);
  max-width: 46ch;
}
.band--tide .deck,
.band--ink .deck{ color: var(--grit-dark); }
.band--teal .deck{ color: rgba(255,255,255,.92); }

/* ---------- the stitch ----------
   An overlock is a run of short slanted threads. That is all this is:
   an angled repeating gradient, cheap enough to use everywhere. */

.seam{
  height: 7px;
  background: repeating-linear-gradient(74deg,
    var(--stitch) 0 2.5px, transparent 2.5px 8.5px);
}

/* A short run of stitching, used above a headline where a tracked-out
   label would otherwise go. It marks a new panel without saying so. */
.tack{
  width: 104px; height: 9px;
  margin: 0 0 clamp(20px, 2.4vw, 30px);
  background: repeating-linear-gradient(74deg,
    var(--stitch) 0 2.5px, transparent 2.5px 8.5px);
}
.band--tide .tack, .band--ink .tack, .band--teal .tack{ --stitch: rgba(255,255,255,.9); }

/* ---------- layout ---------- */

.wrap{
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.band{
  padding-block: clamp(64px, 8.5vw, 118px);
  background: var(--laundered);
}
.band--tide{ background: var(--tide); color: var(--laundered); }
/* Photographs want a neutral field, not a coloured one. The gallery band
   runs near-black so the towels are the only colour in it; the founder band
   keeps the teal-black, which is the site's own colour. */
.band--ink{ background: var(--ink); color: var(--laundered); }
.band--teal{ background: var(--teal); color: #fff; }
.band--tide h1, .band--tide h2, .band--tide h3, .band--tide h4,
.band--ink h1, .band--ink h2, .band--ink h3, .band--ink h4,
.band--teal h1, .band--teal h2, .band--teal h3, .band--teal h4{ color: var(--chalk); }
.band--tide, .band--ink{ --stitch: rgba(255,255,255,.85); }
.band--teal{ --stitch: rgba(255,255,255,.9); }

/* Anchors have to clear the sticky bar. */
[id]{ scroll-margin-top: calc(var(--bar-h) + 14px); }

.head{ max-width: 60ch; margin-bottom: clamp(38px, 4.6vw, 64px); }
.head .deck{ margin-top: 1.15rem; }
h2 + .deck{ margin-top: 1.15rem; }

@media (min-width: 1080px){
  .head{
    max-width: none;
    display: grid;
    grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr);
    column-gap: clamp(40px, 5vw, 88px);
    align-items: end;
  }
  .head .tack{ grid-column: 1 / -1; }
  .head h2{ grid-column: 1; }
  .head .deck{ grid-column: 2; margin-top: 0; max-width: 44ch; }
}

/* ---------- draft markers ----------
   Anything the founder has not confirmed is wrapped in .fill.
   Remove class="draft" from <body> to preview the page clean. */

.draft .fill{
  background: rgba(255,190,40,.22);
  box-shadow: inset 0 -2px 0 rgba(255,190,40,.95);
  padding: 0 .18em;
}
.draft .draft-flag{ display: flex; }
/* The front page now carries no unconfirmed claims, but it keeps the draft
   class so the preview build can still find it. A flag saying there are
   amber marks on a page with none is worse than no flag, so it comes off
   where there is nothing to confirm. Browsers without :has() ignore the
   whole rule and show the flag, which is the safe end of that trade. */
body.draft:not(:has(.fill)) .draft-flag{ display: none; }
.draft-flag{
  display: none;
  position: fixed; right: 14px; bottom: 14px; z-index: 150;
  align-items: center; gap: .55rem;
  background: #FFBE28; color: #221A00;
  font-family: var(--display);
  font-variation-settings: 'wdth' 100, 'wght' 700;
  font-size: .68rem; letter-spacing: .08em; text-transform: uppercase;
  padding: 9px 14px;
  box-shadow: 0 6px 22px rgba(0,0,0,.3);
}
@media (max-width: 760px){ .draft-flag{ display: none !important; } }

/* ---------- buttons ---------- */

.btn{
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  font-family: var(--body);
  font-weight: 600;
  font-size: .95rem;
  letter-spacing: .005em;
  padding: 14px 24px;
  border: 2px solid transparent;
  border-radius: var(--r);
  text-decoration: none;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.btn svg{ width: 18px; height: 18px; flex: none; }

.btn--go{ background: var(--teal); color: #fff; }
.btn--go:hover{ background: var(--teal-lift); }

/* On a dark or teal field the primary button inverts to stay primary. The
   sticky bar is deliberately left out of this list: a white button up there
   shouts louder than the mark next to it. */
.hero .btn--go,
.band--tide .btn--go,
.band--ink .btn--go,
.band--teal .btn--go,
.wa-bar .btn--go{ background: var(--chalk); color: var(--tide); }
.hero .btn--go:hover,
.band--tide .btn--go:hover,
.band--ink .btn--go:hover,
.band--teal .btn--go:hover,
.wa-bar .btn--go:hover{ background: var(--laundered); }

.btn--line{ border-color: currentColor; color: inherit; }
.btn--line:hover{ background: rgba(255,255,255,.1); }
.band--laundered .btn--line:hover{ background: rgba(7,34,42,.06); }

/* ---------- sticky bar ---------- */

.bar{
  position: sticky; top: 0; z-index: 100;
  height: var(--bar-h);
  display: flex; align-items: center;
  background: var(--tide);
  border-bottom: 1px solid var(--hair-dark);
}
.bar .wrap{
  display: flex; align-items: center; gap: 1.4rem;
}
.bar-mark{ display: flex; align-items: center; text-decoration: none; margin-right: auto; }
.bar-mark img{
  height: 39px; width: auto;   /* logo-white.png is already reversed out */
}
.bar-nav{ display: flex; gap: 1.5rem; }
.bar-nav a{
  font-size: .9rem; font-weight: 500;
  color: var(--grit-dark);
  text-decoration: none;
  padding-block: 4px;
  border-bottom: 2px solid transparent;
  transition: color .15s ease, border-color .15s ease;
}
.bar-nav a:hover{ color: var(--chalk); border-bottom-color: var(--teal-lift); }
.bar-nav a[aria-current="page"]{ color: var(--chalk); border-bottom-color: var(--teal-lift); }
.bar .btn{ padding: 9px 17px; font-size: .86rem; }

@media (max-width: 900px){
  .bar-nav{ display: none; }
}
/* On the main page a fixed WhatsApp bar owns the bottom of a phone screen,
   so the one up here is a duplicate. The policy pages have no fixed bar,
   so theirs stays and just gets smaller. */
@media (max-width: 620px){
  .bar .btn{ display: none; }
  .bar--policy .btn{ display: inline-flex; padding: 8px 13px; font-size: .78rem; }
  .bar-mark img{ height: 36px; }
}

/* ============================================================
   HERO
   One full-bleed photograph that plays once on load and then hands
   off to the page on scroll. No stitching in here on purpose: the
   seam is the page's device, and the hero is the photograph.

   Two rules keep the motion safe:
   1. Entry and departure never share an element, so they never fight
      over `transform`. Entry runs on .hero-media img, .hero-copy's
      children and .scroll-cue-in; departure runs on .hero-media,
      .hero-inner and .scroll-cue.
   2. Nothing here is needed to read the page. Reduced motion and the
      no-scroll-timeline fallback both resolve to the finished state.
   ============================================================ */

.hero{
  position: relative;
  /* The sticky bar is in normal flow above this, so a full 100svh would push
     the frame past the fold and take the scroll cue with it. */
  min-height: calc(100vh - var(--bar-h));
  min-height: calc(100svh - var(--bar-h));   /* discount mobile browser chrome */
  display: flex; align-items: center;
  background: var(--ink);
  color: #fff;
  overflow: hidden;
  isolation: isolate;
}
.hero h1{ color: var(--chalk); }

.hero-media{
  position: absolute; inset: 0;
  z-index: -2;
  will-change: transform;
}
.hero-media img{
  width: 100%; height: 100%;
  object-fit: cover;
  /* On desktop the image is width-fitted so only the Y value bites. The X
     value takes over on narrow viewports, where it holds the near seat. */
  object-position: 36% 44%;
}

/* Gradient veil so the display type holds contrast over the photograph.
   Mixed off the ink and warmed with the teal rather than a blue, so the
   hero belongs to the same family as the bands under it. */
.hero-veil{
  position: absolute; inset: 0;
  z-index: -1;
  background:
    linear-gradient(100deg, rgba(7,16,19,.95) 0%, rgba(7,16,19,.80) 42%, rgba(7,16,19,.34) 72%, rgba(7,16,19,.56) 100%),
    radial-gradient(ellipse 70% 60% at 78% 62%, rgba(29,110,128,.34), transparent 70%);
}
@media (max-width: 900px){
  .hero-veil{
    background:
      linear-gradient(180deg, rgba(7,16,19,.72) 0%, rgba(7,16,19,.55) 38%, rgba(7,16,19,.93) 88%),
      radial-gradient(ellipse 90% 45% at 60% 70%, rgba(29,110,128,.3), transparent 70%);
  }
}

.hero-inner{
  position: relative;
  padding-block: clamp(44px, 6vh, 84px) clamp(64px, 9vh, 104px);
  will-change: transform, opacity;
}

/* A px measure, not ch. `ch` here resolves against the 16px body font, not
   the display face, so it collapses the column and wraps the headline out
   to twice the lines it needs. */
.hero-copy{ max-width: 860px; }
.hero h1{
  font-size: clamp(2.4rem, 1.1rem + 4.1vw, 4.4rem);
  margin-bottom: 1.4rem;
}
.hero .deck{ color: rgba(255,255,255,.9); max-width: 46ch; }

.hero-origin{
  display: flex; align-items: center; gap: .85rem;
  font-size: .88rem; font-weight: 600;
  letter-spacing: .01em;
  color: rgba(255,255,255,.88);
  margin: 0 0 1.4rem;
}
/* A plain rule, not the overlock. The stitch device starts below the fold. */
.hero-origin::before{
  content: ""; width: 52px; height: 2px; flex: none;
  background: currentColor; opacity: .55;
}

.hero-cta{
  display: flex; flex-wrap: wrap; gap: .7rem;
  margin-top: clamp(26px, 2.8vw, 34px);
}
@media (max-width: 540px){
  .hero-cta{ flex-direction: column; align-items: stretch; }
}

.hero-price{
  display: flex; align-items: baseline; gap: .65rem; flex-wrap: wrap;
  margin-top: clamp(26px, 2.6vw, 34px);
  padding-top: 1.2rem;
  border-top: 1px solid rgba(255,255,255,.26);
  max-width: 420px;
}
.hero-price .amount{
  font-family: var(--display);
  font-variation-settings: 'wdth' 112, 'wght' 850;
  font-size: clamp(1.7rem, 1.3rem + 1.4vw, 2.2rem);
  line-height: 1;
  color: var(--chalk);
}
.hero-price .note{ font-size: .9rem; color: rgba(255,255,255,.8); }

/* A laptop window is wide and short. At the full display size the headline
   runs four lines and pushes the price and the cue past the fold, so on a
   short viewport everything under the headline closes up. */
@media (min-width: 900px) and (max-height: 880px){
  .hero h1{ font-size: clamp(2.2rem, .9rem + 2.9vw, 3.3rem); }
  .hero .deck{ font-size: 1.06rem; }
  .hero-inner{ padding-block: clamp(30px, 4vh, 52px) clamp(52px, 7vh, 76px); }
  .hero-cta{ margin-top: 22px; }
  .hero-price{ margin-top: 22px; padding-top: 1rem; }
}

/* ---------- scroll cue ----------
   Two nested elements on purpose. The outer one owns the centring
   transform and the scroll-driven fade; the inner one owns the entry
   animation. Sharing them would let settle's closing `transform: none`
   cancel the translateX(-50%) and throw the cue off centre. */

.scroll-cue{
  position: absolute; left: 50%; bottom: 22px;
  transform: translateX(-50%);
  z-index: 2;
  pointer-events: none;
}
.scroll-cue-in{
  display: flex; flex-direction: column; align-items: center; gap: .45rem;
  font-size: .68rem; letter-spacing: .22em; text-transform: uppercase;
  font-weight: 600;
  color: rgba(255,255,255,.62);
}
.scroll-cue svg{ width: 15px; height: 15px; animation: cueBob 2.1s ease-in-out infinite; }

/* The fixed WhatsApp bar owns the bottom of a phone screen, and a scroll
   hint is redundant on touch anyway. */
@media (max-width: 700px){
  .scroll-cue{ display: none; }
}

@keyframes cueBob{
  0%,100%{ transform: translateY(0); opacity: .55; }
  50%    { transform: translateY(5px); opacity: 1; }
}

/* ---------- entry, plays once on load ---------- */

@keyframes settle{
  from{ opacity: 0; transform: translateY(22px); }
  to  { opacity: 1; transform: none; }
}
@keyframes release{
  from{ transform: scale(1.12); }
  to  { transform: scale(1); }
}
.js .hero-copy > *,
.js .scroll-cue-in{
  animation: settle .9s cubic-bezier(.22,.72,.28,1) both;
  animation-delay: var(--d, 0s);
}
.js .hero-media img{
  animation: release 2.4s cubic-bezier(.16,.62,.3,1) both;
}

/* ---------- departure, scrubbed by scroll position ----------
   scroll() runs on the compositor, so this costs nothing per frame.
   Older browsers without it get the same effect from a rAF-throttled
   passive listener in site.js. */

@keyframes heroDepart{
  to{ opacity: 0; transform: translateY(-7%) scale(.955); }
}
@keyframes mediaDepart{
  to{ transform: scale(1.16); }
}
@keyframes cueFade{
  to{ opacity: 0; transform: translateX(-50%) translateY(14px); }
}

@supports (animation-timeline: scroll()){
  .hero-inner{
    animation: heroDepart linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 88vh;
  }
  .hero-media{
    animation: mediaDepart linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 88vh;
  }
  .scroll-cue{
    animation: cueFade linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 26vh;
  }
}

@media (prefers-reduced-motion: reduce){
  .js .hero-copy > *,
  .js .scroll-cue-in,
  .js .hero-media img{ animation: none; }
  .scroll-cue svg{ animation: none; }
  @supports (animation-timeline: scroll()){
    .hero-inner, .hero-media, .scroll-cue{ animation: none; }
  }
}

/* ============================================================
   FACTS STRIP
   Four things a stranger needs before they will message you.
   ============================================================ */

.facts{ background: var(--chalk); }
.facts ul{
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: 1fr;
}
.facts li{
  padding: 20px 0;
  border-bottom: 1px solid var(--hair-light);
}
.facts li:last-child{ border-bottom: 0; }
.facts b{
  display: block;
  font-family: var(--display);
  font-variation-settings: 'wdth' 104, 'wght' 760;
  text-transform: uppercase;
  font-size: .92rem;
  letter-spacing: .01em;
  margin-bottom: .2rem;
}
.facts span{ display: block; font-size: .9rem; color: var(--grit); line-height: 1.4; }

@media (min-width: 700px){
  .facts ul{ grid-template-columns: repeat(2, 1fr); column-gap: clamp(24px, 4vw, 56px); }
}
@media (min-width: 1040px){
  .facts ul{ grid-template-columns: repeat(4, 1fr); }
  .facts li{
    padding: clamp(26px, 3vw, 38px) clamp(20px, 2.4vw, 34px) clamp(26px, 3vw, 38px) 0;
    border-bottom: 0;
    border-right: 1px solid var(--hair-light);
  }
  .facts li:last-child{ border-right: 0; padding-right: 0; }
}

/* ============================================================
   WHAT IT IS
   Three parallel properties, not a sequence, so no numbering.
   Each one is a panel with a stitched top edge.
   ============================================================ */

.props{
  display: grid; gap: clamp(28px, 3.4vw, 46px);
  grid-template-columns: 1fr;
}
@media (min-width: 820px){
  .props{ grid-template-columns: repeat(3, 1fr); }
}
/* Six of them run two-up before they run three-up. Three columns at the
   820px breakpoint would leave each one about 30 characters wide, which is
   narrower than the sentence inside it wants to be. */
@media (min-width: 560px) and (max-width: 819px){
  .props--six{ grid-template-columns: repeat(2, 1fr); }
}
.prop{ padding-top: 22px; border-top: 2px solid var(--tide); position: relative; }
.prop::before{
  content: ""; position: absolute; top: 8px; left: 0; width: 100%; height: 7px;
  background: repeating-linear-gradient(74deg,
    var(--stitch) 0 2.5px, transparent 2.5px 8.5px);
  opacity: .5;
}
.prop h3{ margin-bottom: .7rem; padding-top: 12px; }
.prop p{ color: var(--grit); font-size: .97rem; }

/* A sewn-on patch pointing at the detail page. Same construction as the
   care label it links to, at a quarter of the size, so the link looks like
   the thing on the other end of it. */

.jump{
  --stitch: rgba(7,34,42,.5);
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(16px, 2vw, 26px);
  align-items: center;
  margin-top: clamp(40px, 4.6vw, 64px);
  padding: clamp(22px, 2.6vw, 32px);
  background: var(--chalk);
  color: var(--tide);
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease;
}
.jump::before{
  content: ""; position: absolute; inset: 8px; pointer-events: none;
  border: 7px solid transparent;
  background: repeating-linear-gradient(74deg,
    var(--stitch) 0 2.5px, transparent 2.5px 8.5px) border-box;
  -webkit-mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}
.jump:hover{ --stitch: rgba(255,255,255,.9); background: var(--teal); color: #fff; }
.jump-in{ position: relative; }
.jump-title{
  display: block;
  font-family: var(--display);
  font-variation-settings: 'wdth' 106, 'wght' 780;
  text-transform: uppercase;
  font-size: clamp(1.05rem, .95rem + .5vw, 1.3rem);
  line-height: 1.12;
  margin-bottom: .5rem;
}
.jump-note{ display: block; font-size: .94rem; line-height: 1.5; color: var(--grit); max-width: 52ch; }
.jump:hover .jump-note{ color: rgba(255,255,255,.88); }
.jump-go{
  position: relative;
  justify-self: start;
  font-weight: 600; font-size: .95rem;
  padding: 13px 22px;
  border: 2px solid var(--tide);
  white-space: nowrap;
  transition: border-color .15s ease;
}
.jump:hover .jump-go{ border-color: #fff; }

@media (min-width: 780px){
  .jump{ grid-template-columns: minmax(0, 1fr) auto; gap: clamp(24px, 3vw, 48px); }
}

/* A row of actions outside the hero. */
.actions{ display: flex; flex-wrap: wrap; gap: .7rem; }
@media (max-width: 540px){
  .actions{ flex-direction: column; align-items: stretch; }
}

/* ============================================================
   STEPS
   Ordering is the only sequence left on the site, so it is the only
   thing numbered. The product properties above it are parallel, not
   ordered, and are deliberately left unnumbered.
   ============================================================ */

.steps{ counter-reset: step; display: grid; gap: 0; }
.step{
  counter-increment: step;
  display: grid;
  grid-template-columns: 62px minmax(0, 1fr);
  gap: 0 clamp(16px, 2vw, 28px);
  padding-block: clamp(24px, 2.8vw, 34px);
  border-top: 1px solid var(--hair-dark);
  align-items: start;
}
.step:last-child{ border-bottom: 1px solid var(--hair-dark); }
.step::before{
  content: counter(step, decimal-leading-zero);
  font-family: var(--display);
  font-variation-settings: 'wdth' 118, 'wght' 880;
  font-size: clamp(1.9rem, 1.4rem + 1.6vw, 2.7rem);
  line-height: .85;
  color: var(--teal-lift);
  grid-row: span 2;
}
.step h3{ margin-bottom: .45rem; }
.step p{ color: var(--grit-dark); font-size: .97rem; max-width: 54ch; }

.band--laundered .step{ border-color: var(--hair-light); }
.band--laundered .step p{ color: var(--grit); }
.band--laundered .step::before{ color: var(--teal); }


/* ============================================================
   GALLERY
   Deliberately uneven. Four equal tiles would look like stock. Two tall
   columns carry the full-length shots and two shorter ones hang from the
   bottom edge between them, so the row reads as a rhythm.
   ============================================================ */

.gallery{ display: grid; gap: 10px; grid-template-columns: 1fr; }
.gallery figure{
  margin: 0; position: relative; overflow: hidden;
  background: var(--tide);
  aspect-ratio: 4 / 5;
}
.band--ink .gallery figure{ background: var(--ink-raised); }
/* The picture is taken out of flow, the way the hero does it. Left in flow,
   `height:100%` against an auto-height tile resolves to auto, the photograph
   falls back to its intrinsic height, and that becomes the tile's
   min-content height. On the widescreen grid below that is what makes the
   rows taller than the two stacked squares, so the stacked column stops
   short of the bottom edge. Out of flow, every tile's height comes from the
   aspect-ratio or the grid, and nothing else. */
.gallery picture{ position: absolute; inset: 0; display: block; }
.gallery img{ width: 100%; height: 100%; object-fit: cover; object-position: var(--pos, 50% 45%); }

/* Every photograph here was shot in portrait, so 4:5 is the house ratio and
   the tiles line up in rows without gaps under the shorter one. The .tall
   and .short classes carry no ratio of their own; they only drive the
   desktop row spans further down. */

/* The kitbag shot is the exception: made-for-social, with type set on it. On
   a phone there is one tile per row and nothing to line up with, so it keeps
   1:1 and is not cropped at all. */
.gallery figure.square{ aspect-ratio: 1; }

/* Two up before four up. Four columns on a tablet leaves each photograph
   about 180px wide, which is smaller than the detail in them. From here the
   square joins the house ratio: losing about a fifth of its width keeps the
   type intact and matters less than a ragged row. */
@media (min-width: 620px) and (max-width: 1019px){
  .gallery{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gallery figure.square{ aspect-ratio: 4 / 5; }
}

@media (min-width: 1020px){
  /* A plain gallery, which is what the specifications page uses, is three
     portraits across. */
  .gallery{ grid-template-columns: repeat(3, minmax(0, 1fr)); }

  /* The main page's four photographs are the exception. The two full-length
     shots run side by side at full height, and the other two stack into a
     third column that comes to exactly the same height, so the block reads
     as one clean rectangle rather than two tall tiles and two short ones.

     No fixed row heights anywhere. The stacked pair are squares, so they
     take their height from the column width, and the tall pair stretch to
     whatever those two rows add up to. The whole block scales on its own.

     minmax(0, ...) rather than a plain fr: a plain fr floors at the
     photograph's min-content width, and the tall pair would then bully the
     stacked column down to a fraction of its share.

     The stacked column is the narrower one at .85fr, which is what keeps the
     tall pair near the 4:7 they were shot at. Squares in a full-width third
     column would push the other two columns taller than their photographs
     want to be. */
  .gallery--feature{
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, .85fr);
  }
  /* .square is named as well as .short because the kitbag tile carries both
     classes and the two-column rule above sets it to 4:5. Same specificity,
     so this only wins by coming later. */
  .gallery--feature figure.short,
  .gallery--feature figure.square{ aspect-ratio: 1; }
  /* Named individually: .gallery figure.tall is more specific than
     .gallery figure, so a bare reset would lose to it and these would keep
     their 4:5 instead of stretching across both rows. */
  .gallery--feature figure.tall{ aspect-ratio: auto; grid-row: 1 / 3; }

  /* Source order is seat, pink, dog, kitbag, which is the order the phone
     wants and must not change. Columns are therefore assigned rather than
     left to auto-placement: the two tall ones take the left columns, the
     two short ones stack on the right. */
  .gallery--feature figure:nth-child(1){ grid-column: 1; }
  .gallery--feature figure:nth-child(3){ grid-column: 2; }
  .gallery--feature figure:nth-child(2){ grid-column: 3; grid-row: 1; }
  .gallery--feature figure:nth-child(4){ grid-column: 3; grid-row: 2; }
}

/* ============================================================
   USES
   A row of chips under the gallery headline. The shortest way to
   say the product is not about one activity.
   ============================================================ */

.uses{
  list-style: none; padding: 0;
  margin: clamp(24px, 2.8vw, 34px) 0 clamp(26px, 3vw, 40px);
  display: flex; flex-wrap: wrap; gap: 8px;
}
.uses li{
  border: 1px solid rgba(255,255,255,.42);
  padding: 7px 13px;
  font-size: .87rem; font-weight: 500;
}

/* ============================================================
   CARE LABEL
   The specifications set the way they arrive on the product: as a
   label sewn into the seam. This is the one loud idea on the page.
   ============================================================ */

.label{
  background: var(--chalk);
  color: var(--tide);
  padding: clamp(22px, 2.8vw, 38px);
  max-width: 880px;
  position: relative;
}
/* Stitching set in from the edge, the way a bound label is sewn. */
.label::before{
  content: ""; position: absolute; inset: 9px; pointer-events: none;
  border: 7px solid transparent;
  background: repeating-linear-gradient(74deg,
    rgba(7,34,42,.5) 0 2.5px, transparent 2.5px 8.5px) border-box;
  -webkit-mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}
.label-in{ position: relative; padding: clamp(10px, 1.4vw, 20px); }

.label-mark{
  font-family: var(--display);
  font-variation-settings: 'wdth' 110, 'wght' 880;
  text-transform: uppercase;
  font-size: clamp(1rem, .9rem + .5vw, 1.25rem);
  letter-spacing: .01em;
  line-height: 1;
  padding-bottom: 1rem;
  border-bottom: 2px solid var(--tide);
}
.label dl{ margin: 0; }
.label div.row{
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px clamp(16px, 2.4vw, 34px);
  padding-block: clamp(13px, 1.5vw, 17px);
  border-bottom: 1px solid var(--hair-light);
}
.label dt{
  font-family: var(--display);
  font-variation-settings: 'wdth' 100, 'wght' 720;
  text-transform: uppercase;
  font-size: .76rem;
  letter-spacing: .07em;
  color: var(--grit);
  line-height: 1.4;
}
.label dd{
  margin: 0;
  font-size: .95rem;
  line-height: 1.55;
}
@media (min-width: 660px){
  .label div.row{ grid-template-columns: 138px minmax(0, 1fr); }
  .label dt{ padding-top: .16rem; }
}
.label-foot{
  padding-top: clamp(14px, 1.8vw, 20px);
  font-family: var(--display);
  font-variation-settings: 'wdth' 100, 'wght' 720;
  text-transform: uppercase;
  font-size: .72rem; letter-spacing: .1em;
  color: var(--grit);
}

/* ============================================================
   FOUNDER
   ============================================================ */

.founder{
  display: grid; gap: clamp(30px, 4vw, 62px);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 880px){
  .founder{ grid-template-columns: minmax(0, .82fr) minmax(0, 1fr); }
}
.founder-shot{ position: relative; background: var(--tide-lift); }
.founder-shot img{ width: 100%; }
.founder-shot::after{
  content: ""; position: absolute; inset: 10px; pointer-events: none;
  border: 7px solid transparent;
  background: repeating-linear-gradient(74deg,
    rgba(255,255,255,.85) 0 2.5px, transparent 2.5px 8.5px) border-box;
  -webkit-mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}
.founder-text p{ color: var(--grit-dark); }
/* The opening paragraph runs straight off the headline, so it carries a
   little more weight than the rest without turning into a bold slab. */
.founder-text p:first-child{ color: var(--chalk); font-size: 1.12rem; line-height: 1.5; }
.founder blockquote{
  margin: clamp(26px, 3vw, 38px) 0 0;
  padding: 1.1rem 0 0;
  border-top: 2px solid var(--teal-lift);
  font-family: var(--display);
  font-variation-settings: 'wdth' 108, 'wght' 800;
  text-transform: uppercase;
  font-size: clamp(1.15rem, 1rem + .9vw, 1.7rem);
  line-height: 1.06;
  color: var(--chalk);
  max-width: 22ch;
}

/* Pepper sits inside the founder column, at a size that keeps her a
   footnote. Giving her a band of her own is exactly what would pull the
   page back to being about dogs. */
.pepper{
  display: grid;
  grid-template-columns: clamp(92px, 21vw, 128px) minmax(0, 1fr);
  gap: clamp(16px, 2.2vw, 26px);
  align-items: center;
  margin-top: clamp(26px, 3vw, 38px);
  padding-top: clamp(22px, 2.6vw, 30px);
  border-top: 1px solid var(--hair-dark);
}
.pepper-shot{ position: relative; aspect-ratio: 1; background: var(--tide-lift); }
.pepper-shot picture{ position: absolute; inset: 0; display: block; }
.pepper-shot img{
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: var(--pos, 50% 45%);
}
.pepper-shot::after{
  content: ""; position: absolute; inset: 6px; pointer-events: none;
  border: 5px solid transparent;
  background: repeating-linear-gradient(74deg,
    rgba(255,255,255,.85) 0 2.5px, transparent 2.5px 8.5px) border-box;
  -webkit-mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) padding-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}
.pepper h3{ margin-bottom: .4rem; }
.pepper p{ margin: 0; font-size: .95rem; }

/* ============================================================
   ORDER
   ============================================================ */

.order{
  display: grid; gap: clamp(34px, 4vw, 60px);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 940px){
  .order{ grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); }
}
.band--teal .step{ border-color: rgba(255,255,255,.32); }
.band--teal .step::before{ color: rgba(7,34,42,.58); }
.band--teal .step p{ color: rgba(255,255,255,.86); }

.ticket{
  background: var(--chalk);
  color: var(--tide);
  padding: clamp(26px, 3vw, 38px);
}
.band--teal .ticket h3{ color: var(--tide); }
.ticket h3{ margin-bottom: 1.3rem; line-height: 1.05; }
/* The ticket is a chalk card sitting on the teal band, so its button has to
   come back off the band's invert rule and be filled again. */
.ticket .btn--go{ background: var(--teal); color: #fff; }
.ticket .btn--go:hover{ background: var(--teal-lift); }
.ticket ul{ list-style: none; margin: 0 0 clamp(24px, 2.8vw, 32px); padding: 0; }
.ticket li{
  display: grid; grid-template-columns: 20px 1fr; gap: .7rem;
  padding-block: .55rem;
  border-top: 1px solid var(--hair-light);
  font-size: .94rem; line-height: 1.45;
}
.ticket li svg{ width: 18px; height: 18px; margin-top: 3px; color: var(--teal); }
.ticket .btn{ width: 100%; }

/* ============================================================
   FAQ
   ============================================================ */

.faq{ border-top: 1px solid var(--hair-light); max-width: 900px; }
.faq details{ border-bottom: 1px solid var(--hair-light); }
.faq summary{
  list-style: none;
  cursor: pointer;
  display: grid; grid-template-columns: 1fr 22px; gap: 1rem; align-items: center;
  padding-block: clamp(17px, 2vw, 23px);
  font-family: var(--display);
  font-variation-settings: 'wdth' 106, 'wght' 780;
  text-transform: uppercase;
  font-size: clamp(1rem, .93rem + .35vw, 1.18rem);
  line-height: 1.14;
}
.faq summary::-webkit-details-marker{ display: none; }
.faq summary::after{
  content: ""; width: 15px; height: 15px; justify-self: end;
  background:
    linear-gradient(var(--tide) 0 0) center/100% 2px no-repeat,
    linear-gradient(var(--tide) 0 0) center/2px 100% no-repeat;
  transition: background-size .18s ease;
}
.faq details[open] summary::after{ background-size: 100% 2px, 2px 0; }
@media (prefers-reduced-motion: reduce){ .faq summary::after{ transition: none; } }
.faq summary:hover{ color: var(--teal); }
.faq details > p{
  margin: 0 0 clamp(18px, 2vw, 24px);
  max-width: 68ch;
  color: var(--grit);
  font-size: .97rem;
}
.faq a{ color: var(--teal); text-decoration: underline; text-underline-offset: 2px; }

/* ============================================================
   FOOTER
   ============================================================ */

.site-foot{
  background: var(--tide);
  color: var(--grit-dark);
  font-size: .93rem;
  --stitch: rgba(255,255,255,.85);
}
.site-foot .wrap{ padding-block: clamp(46px, 5vw, 68px) 0; }
.foot-grid{
  display: grid; gap: clamp(30px, 3.4vw, 52px);
  grid-template-columns: 1fr;
}
@media (min-width: 760px){
  .foot-grid{ grid-template-columns: 1.4fr 1fr 1fr; }
}
.foot-grid img.mark{
  height: 32px; width: auto;
  margin-bottom: 1.2rem;
}
.foot-grid h4{ color: var(--chalk); margin-bottom: 1rem; }
.site-foot ul{ list-style: none; margin: 0; padding: 0; }
.site-foot li{ margin-bottom: .55rem; }
.site-foot a{ text-decoration: none; transition: color .15s ease; }
.site-foot a:hover{ color: var(--chalk); }

/* Footer links are around 20px tall, fine for a mouse and poor for a thumb.
   Coarse pointers get a taller hit area without loosening the desktop footer. */
@media (pointer: coarse){
  .site-foot li a, .foot-links a{ display: inline-block; padding-block: 8px; }
  .site-foot li{ margin-bottom: .1rem; }
}

.foot-base{
  margin-top: clamp(38px, 4vw, 56px);
  border-top: 1px solid var(--hair-dark);
  padding-block: 24px;
  display: flex; flex-wrap: wrap; gap: .8rem 1.4rem;
  justify-content: space-between;
  font-size: .82rem;
}
.foot-base a{ text-decoration: none; }
.foot-links{ display: flex; flex-wrap: wrap; gap: 1.3rem; }

/* ---------- fixed WhatsApp bar, phones only ---------- */

.wa-bar{
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 120;
  background: var(--tide);
  padding: 10px var(--gutter) calc(10px + env(safe-area-inset-bottom));
  display: none;
}
.wa-bar::before{
  content: ""; position: absolute; left: 0; right: 0; top: -7px; height: 7px;
  background: repeating-linear-gradient(74deg,
    rgba(255,255,255,.9) 0 2.5px, transparent 2.5px 8.5px);
}
.wa-bar .btn{ width: 100%; }

/* The hero carries its own WhatsApp button, so at first paint on a phone the
   fixed bar would sit a couple of hundred pixels below an identical copy of
   itself. It stays down until the hero button has scrolled away, then takes
   over. Without JS it is simply always up, which is the safe end of the
   trade: a duplicated button beats a missing one. */
.js .wa-bar{
  transform: translateY(115%);
  transition: transform .28s cubic-bezier(.22,.72,.28,1);
}
.js .wa-bar.is-up{ transform: none; }
@media (prefers-reduced-motion: reduce){
  .js .wa-bar{ transition: none; }
}
@media (max-width: 760px){
  .wa-bar{ display: block; }
  /* Clear the fixed bar from inside the footer, not on <body>, so page
     backgrounds still run to the bottom edge. */
  .foot-base{ padding-bottom: 118px; }
}

/* ============================================================
   POLICY PAGES
   Same site, different job: long statutory text that has to be
   navigable. Numbering here is real, the clauses are numbered.
   ============================================================ */

.page-head{
  background: var(--tide);
  color: var(--chalk);
  padding-block: clamp(44px, 5.4vw, 78px) clamp(30px, 3.4vw, 44px);
  --stitch: rgba(255,255,255,.85);
}
.page-head .meta{
  font-size: .84rem; font-weight: 500;
  color: var(--grit-dark);
  margin: 0 0 .9rem;
}
.page-head h1{
  font-size: clamp(2.1rem, 1.2rem + 3.8vw, 4rem);
  margin-bottom: 1.1rem;
}
.page-head .deck{ color: var(--grit-dark); max-width: 54ch; margin: 0; }

/* The four policies read as one set, so they carry each other. */
.policy-nav{
  background: var(--tide);
  border-top: 1px solid var(--hair-dark);
}
.policy-nav ul{
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0 clamp(18px, 2.6vw, 34px);
}
.policy-nav a{
  display: block;
  padding-block: 14px;
  font-family: var(--display);
  font-variation-settings: 'wdth' 100, 'wght' 720;
  text-transform: uppercase;
  font-size: .8rem; letter-spacing: .05em;
  color: var(--grit-dark);
  text-decoration: none;
  border-bottom: 3px solid transparent;
  transition: color .15s ease, border-color .15s ease;
}
.policy-nav a:hover{ color: var(--chalk); }
.policy-nav a[aria-current="page"]{ color: var(--chalk); border-bottom-color: var(--teal-lift); }

.policy-body{ padding-block: clamp(44px, 5vw, 76px); }
.policy-layout{
  display: grid; gap: clamp(32px, 4vw, 56px);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 1000px){
  .policy-layout{ grid-template-columns: 220px minmax(0, 1fr); }
  .toc{ position: sticky; top: calc(var(--bar-h) + 28px); }
}

.toc h2{
  font-family: var(--body);
  font-size: .84rem;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  line-height: 1.3;
  color: var(--grit);
  margin-bottom: .9rem;
}
.toc ol{
  list-style: none; margin: 0; padding: 0;
  counter-reset: toc;
  border-top: 1px solid var(--hair-light);
}
.toc li{ counter-increment: toc; border-bottom: 1px solid var(--hair-light); }
.toc a{
  display: grid; grid-template-columns: 26px 1fr; gap: .4rem;
  padding-block: 9px;
  font-size: .88rem; line-height: 1.35;
  color: var(--grit); text-decoration: none;
  transition: color .15s ease;
}
.toc a::before{ content: counter(toc); font-weight: 600; color: var(--teal); }
.toc a:hover{ color: var(--tide); }
/* Set by the scroll-spy in site.js. Without JS no clause is marked and
   the list still works as a plain set of links. */
.toc a[aria-current="true"]{ color: var(--tide); font-weight: 600; }
.toc a[aria-current="true"]::before{ color: var(--tide); }
@media (max-width: 999px){
  .toc{ display: none; }
}

.prose{ max-width: 68ch; }
.prose h2{
  font-size: clamp(1.1rem, 1rem + .55vw, 1.42rem);
  font-variation-settings: 'wdth' 106, 'wght' 800;
  line-height: 1.14;
  margin: clamp(36px, 4vw, 54px) 0 .8rem;
  padding-top: clamp(20px, 2.4vw, 28px);
  border-top: 1px solid var(--hair-light);
}
.prose > :first-child{ margin-top: 0; padding-top: 0; border-top: 0; }
.prose p{ margin: 0 0 1rem; }
.prose ul{ margin: 0 0 1rem; padding-left: 1.1rem; }
.prose li{ margin-bottom: .45rem; }
.prose li::marker{ color: var(--teal); }
.prose a{ color: var(--teal); text-decoration: underline; text-underline-offset: 2px; }
.prose a:hover{ color: var(--tide); }

.prose .note{
  background: var(--chalk);
  border-left: 4px solid var(--teal);
  padding: clamp(16px, 2vw, 22px);
  margin: 0 0 1.2rem;
}
.prose .note p:last-child{ margin-bottom: 0; }

.back-link{
  display: inline-flex; align-items: center; gap: .5rem;
  margin-top: clamp(32px, 3.6vw, 48px);
  padding-top: clamp(24px, 2.8vw, 32px);
  border-top: 1px solid var(--hair-light);
  font-weight: 600; font-size: .93rem;
  text-decoration: none; color: var(--grit);
  transition: color .15s ease;
}
.back-link:hover{ color: var(--teal); }
.back-link svg{ width: 16px; height: 16px; }
