@import url("fonts.css");

/* ==========================================================================
   Irony vs. Satyr — bottle catalogue

   Light ground. The brand deck carries both halves: gold and pink type on a
   dark ground, and dark green type on a light one. This site takes the light
   half, and keeps dark green blocks as occasional inversions rather than as
   the whole page.

   Raw palette is declared once; everything downstream uses the semantic roles,
   so changing the accent across the site costs one line.
   ========================================================================== */

:root {
  /* Raw palette, straight from the brand deck. */
  --maroon: #260408;
  --pink: #ff95ff;
  --green: #112103;
  --gold: #d3bd8d;

  /* Paper. Very slightly green-grey rather than beige — saturation out, not
     in, so the gold stays the warmest thing on the page. */
  --paper: #f3f3ee;
  --paper-2: #eae9e2;

  /* Semantic roles. */
  --bg: var(--paper);
  --bg-alt: var(--paper-2);
  --bg-invert: var(--green);
  --text: #16210b;
  --text-soft: #3d4634;
  /* 4.5:1 on --paper. It was #6a7360, which measured 4.46 — under the AA
     floor for small text, and every muted label is small text. */
  --muted: #656e5b;
  --accent: var(--pink);
  --accent-ink: var(--maroon);
  --rule: color-mix(in srgb, var(--green) 22%, transparent);
  --rule-soft: color-mix(in srgb, var(--green) 11%, transparent);

  /* Type. Cormorant Garamond for display: narrower and sharper than a Bodoni,
     so it sits closer to the outlined Expo wordmark, and it has lining figures
     — Italiana matches the logo's proportions better still but renders
     "10 Years" as "Io Years". EB Garamond stands in for Arno Pro, which it
     descends from. */
  --display: "Cormorant Garamond", "Cormorant Fallback", "Didot", serif;
  --body: "EB Garamond", "EB Garamond Fallback", "Iowan Old Style", Georgia, serif;

  --step--1: clamp(0.82rem, 0.79rem + 0.14vw, 0.9rem);
  --step-0: clamp(1rem, 0.96rem + 0.2vw, 1.12rem);
  --step-1: clamp(1.2rem, 1.1rem + 0.5vw, 1.5rem);
  --step-2: clamp(1.5rem, 1.3rem + 1vw, 2.2rem);
  --step-3: clamp(2rem, 1.6rem + 2vw, 3.4rem);
  --step-4: clamp(2.6rem, 1.8rem + 4vw, 5.6rem);

  --measure: 62ch;
  --gutter: clamp(1.15rem, 0.8rem + 1.8vw, 3.5rem);
  --section: clamp(3.5rem, 2.2rem + 6vw, 7.5rem);
  --shell: 1400px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --header-h: 66px;
}

@media (min-width: 900px) {
  :root {
    --header-h: 82px;
  }
}

/* --------------------------------------------------------------------------
   Reset and base
   -------------------------------------------------------------------------- */

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

html {
  /* clip, not hidden — hidden silently breaks position: sticky. */
  overflow-x: clip;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--body);
  font-variant-numeric: lining-nums;
  font-size: var(--step-0);
  line-height: 1.6;
  font-feature-settings: "kern" 1, "liga" 1;
  /* Quotes and hyphens hang into the margin where supported, so the text edge
     stays optically straight rather than mathematically straight. */
  hanging-punctuation: first last;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
}

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

/* Any element given its own `display` outranks the `hidden` attribute's
   `display: none` from the UA sheet, so a filtered-out .card (display: flex)
   stayed on screen while reporting itself hidden. This makes the attribute
   mean what it says, everywhere. */
[hidden] {
  display: none !important;
}

h1,
h2,
h3,
h4 {
  font-family: var(--display);
  font-weight: 500;
  line-height: 1.03;
  letter-spacing: -0.012em;
  margin: 0;
  text-wrap: balance;
}

p {
  margin: 0 0 1em;
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration-color: var(--rule);
  text-underline-offset: 0.22em;
  text-decoration-thickness: 1px;
  transition: color 0.25s var(--ease), text-decoration-color 0.25s var(--ease);
}

:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
  border-radius: 1px;
}

::selection {
  background: var(--accent);
  color: var(--maroon);
}

[id] {
  scroll-margin-top: calc(var(--header-h) + 1.5rem);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: 50%;
  top: 0;
  transform: translate(-50%, -120%);
  z-index: 200;
  background: var(--green);
  color: var(--gold);
  padding: 0.7rem 1.4rem;
  font: 500 0.85rem/1 var(--body);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  transition: transform 0.2s var(--ease);
}

.skip-link:focus {
  transform: translate(-50%, 0);
}

/* --------------------------------------------------------------------------
   Layout primitives
   -------------------------------------------------------------------------- */

.shell {
  width: min(100% - var(--gutter) * 2, var(--shell));
  margin-inline: auto;
}

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

/* The header already supplies space above the first block; a full section of
   padding on top of it reads as a gap rather than as rhythm. */
main > .section:first-child,
main > .shell:first-child {
  padding-top: clamp(2rem, 1.2rem + 3vw, 3.5rem);
}

.section--alt {
  background: var(--bg-alt);
}

/* A divider between two sections otherwise sits in a full section's padding
   from both, which is a quarter of a screen of nothing around a hairline. */
.section--flush-bottom {
  padding-bottom: clamp(1.5rem, 1rem + 2vw, 2.75rem);
}

.section--flush-top {
  padding-top: clamp(1.5rem, 1rem + 2vw, 2.75rem);
}

/* A rare inversion, so the dark half of the brand still appears. */
.section--invert {
  background: var(--bg-invert);
  --text: var(--gold);
  --text-soft: #c4b58e;
  --muted: #8d9a74;
  --rule: color-mix(in srgb, var(--gold) 28%, transparent);
  --rule-soft: color-mix(in srgb, var(--gold) 14%, transparent);
  color: var(--text);
}

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

.eyebrow {
  font-family: var(--body);
  font-size: var(--step--1);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1.4rem;
  display: flex;
  align-items: center;
  gap: 0.9rem;
}

.eyebrow::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}

.lede {
  font-size: var(--step-1);
  font-style: italic;
  line-height: 1.45;
  max-width: var(--measure);
  color: var(--text-soft);
}

/* The brand's own horizontal rule: the flute bar through mask, hand and glass.
   It is the strongest idea in the deck, so it divides the sections here. */
.motif-rule {
  display: block;
  width: min(100%, 300px);
  margin: 0 auto;
  color: var(--rule);
}

.motif-rule .mark {
  width: 100%;
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

.header {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  /* The dark half of the brand, carried at the top of every page. Its own
     tokens, so the bar stays gold-on-green whatever the page beneath it is. */
  background: var(--green);
  --text: var(--gold);
  --muted: #9aa683;
  --accent-ink: var(--pink);
  --rule: color-mix(in srgb, var(--gold) 34%, transparent);
  --rule-soft: color-mix(in srgb, var(--gold) 16%, transparent);
  color: var(--text);
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gutter);
  width: min(100% - var(--gutter) * 2, var(--shell));
  margin-inline: auto;
}

.brand {
  display: flex;
  /* Both wordmark lines are set to the same height, so centring lines them up
     exactly as baseline did — and lets the link reach a 44px touch target. */
  align-items: center;
  min-height: 44px;
  gap: 0.42em;
  color: var(--text);
  text-decoration: none;
  flex: none;
}

.brand .mark {
  height: clamp(21px, 2.6vw, 32px);
}

.brand:hover {
  color: var(--accent-ink);
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 2.4rem);
}

.nav__link {
  font-size: var(--step--1);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--muted);
  position: relative;
  padding-block: 0.3rem;
}

.nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--accent-ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s var(--ease);
}

.nav__link:hover,
.nav__link[aria-current="page"] {
  color: var(--text);
}

.nav__link:hover::after,
.nav__link[aria-current="page"]::after {
  transform: scaleX(1);
}

.nav__link[aria-current="page"]::after {
  background: var(--rule);
}

/* Open or shut, worked out against the visitor's clock. */
.open-now {
  font-size: var(--step--1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.open-now[data-state="open"] {
  color: var(--accent);
}

.open-now[hidden] {
  display: none;
}

@media (max-width: 860px) {
  .open-now {
    order: -1;
    padding-block: 0.75rem;
    border-bottom: 1px solid var(--rule-soft);
  }
}

/* Mobile navigation ------------------------------------------------------- */

.nav-toggle {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--text);
  cursor: pointer;
  place-items: center;
}

.nav-toggle span {
  display: block;
  width: 17px;
  height: 1px;
  background: currentColor;
  position: relative;
  transition: background 0.2s var(--ease);
}

.nav-toggle span::before,
.nav-toggle span::after {
  content: "";
  position: absolute;
  left: 0;
  width: 17px;
  height: 1px;
  background: currentColor;
  transition: transform 0.3s var(--ease);
}

.nav-toggle span::before {
  top: -5px;
}

.nav-toggle span::after {
  top: 5px;
}

.nav-toggle[aria-expanded="true"] span {
  background: transparent;
}

.nav-toggle[aria-expanded="true"] span::before {
  transform: translateY(5px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] span::after {
  transform: translateY(-5px) rotate(-45deg);
}

@media (max-width: 860px) {
  .nav-toggle {
    display: grid;
  }

  .nav {
    position: fixed;
    inset: var(--header-h) 0 auto;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    /* Continues the bar rather than starting a second, paler surface. */
    background: var(--green);
    border-bottom: 1px solid var(--rule-soft);
    padding: 0.5rem var(--gutter) 1.5rem;
    transform: translateY(-101%);
    visibility: hidden;
    transition: transform 0.4s var(--ease), visibility 0.4s;
  }

  .nav[data-open="true"] {
    transform: translateY(0);
    visibility: visible;
  }

  .nav__link {
    /* Flex keeps the row height honest — display: block would collapse the
       gap and merge two labels together. */
    display: flex;
    align-items: center;
    min-height: 52px;
    font-size: var(--step-1);
    letter-spacing: 0.1em;
    border-bottom: 1px solid var(--rule-soft);
  }

  .nav__link::after {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   Masthead — the mascot, then the name

   The mark used to be 420px here, ten pixels below the same mark in the
   header: two logos stacked on each other, with the satyr stranded at the far
   edge at 139px like an afterthought. The satyr is the identity on the front
   page; the header is already carrying the wordmark, so this one can be half
   the size and the figure can be the thing you see. The flute is gone — three
   marks in one block is two too many.

   Still capped in height: the catalogue is the point of the page.
   -------------------------------------------------------------------------- */

.masthead {
  padding-block: clamp(1.5rem, 1rem + 2.5vw, 2.75rem) clamp(1.25rem, 1rem + 2vw, 2.25rem);
  border-bottom: 1px solid var(--rule-soft);
}

.masthead__inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.25rem, 3vw, 3rem);
  align-items: center;
}

@media (min-width: 760px) {
  .masthead__inner {
    grid-template-columns: auto minmax(0, 1fr);
  }
}

.masthead__inner > * {
  min-width: 0;
}

/* The mascot, at a size that reads as a drawing rather than an icon. */
.masthead__figure {
  position: relative;
  color: var(--text);
  justify-self: start;
}

/* Hold the pour button and the satyr fills from the hooves up, the way the
   bottle he is holding would. The gradient is transparent at rest, so this
   costs the page nothing and shows nothing until somebody holds the button:
   an easter egg that announces itself is just a feature nobody asked for. */
.masthead__figure .mark {
  height: clamp(190px, 24vw, 320px);
  background-image: linear-gradient(
    to top,
    var(--accent) var(--pour, 0%),
    transparent var(--pour, 0%)
  );
}

/* The reward for filling him: a dimension line, the way the rest of the site
   borrows from engineering drawings. Sits below the figure and is positioned
   out of flow, so it can never widen the masthead or push the page sideways. */
.pour {
  position: absolute;
  top: calc(100% + 0.7rem);
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
  pointer-events: none;
}

.pour__rule {
  position: relative;
  flex: 1;
  height: 1px;
  background: var(--accent);
}

/* End ticks, so it reads as a measurement and not as an underline. */
.pour__rule::before,
.pour__rule::after {
  content: "";
  position: absolute;
  top: -3px;
  width: 1px;
  height: 7px;
  background: var(--accent);
}

.pour__rule::before {
  left: 0;
}

.pour__rule::after {
  right: 0;
}

.pour__label {
  flex: none;
  color: var(--accent);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
}

.masthead__figure[data-poured="true"] .pour {
  opacity: 1;
  transform: none;
}

/* On a phone the figure is a third of the width and the caption is wider than
   it is. Anchored to its right edge it grows left into the masthead instead of
   off the screen, where overflow-x: clip was cutting it without registering as
   overflow at all. The rules go: there is no room to measure across. */
@media (max-width: 759px) {
  .pour {
    left: auto;
    right: 0;
    width: max-content;
    max-width: 62vw;
    top: calc(100% + 0.5rem);
  }

  .pour__rule {
    display: none;
  }
}

/* Pressing him repeatedly must not start selecting the masthead, and on a
   phone must not raise the callout menu. The cursor stays default on purpose:
   a pointer here would advertise what is meant to be found. */
.masthead__figure {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
}

.masthead__brand {
  min-width: 0;
}

/* A rule to the right edge, the same device the section headings use. The
   column is wider than its text; this spends the difference on purpose
   instead of leaving it blank. */
.masthead__eyebrow {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin: 0 0 0.9rem;
  font-size: var(--step--1);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.masthead__eyebrow::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}

/* The text is one flex item and the rule is the other. Leaving the words bare
   made every span and text run its own item, and the container's gap then
   opened a hole before the comma. */
.masthead__eyebrow__text {
  white-space: nowrap;
}

/* Letter-spacing applies after the last character as well, so an inline span
   still pushes the punctuation after it away. */
.masthead__eyebrow [lang] {
  margin-right: -0.22em;
}

/* Half what it was, because the header has the same mark permanently. */
.masthead__mark {
  width: clamp(170px, 19vw, 250px);
  margin: 0;
  color: var(--text);
}

.masthead__mark .mark {
  width: 100%;
}

.masthead__copy {
  margin: clamp(1rem, 2vw, 1.4rem) 0 0;
  max-width: 52ch;
  font-size: var(--step-1);
  font-style: italic;
  line-height: 1.45;
  color: var(--text-soft);
}

@media (max-width: 759px) {
  /* Beside the words, not under them. Stacked, the figure cost 150px of
     height and pushed the first bottle off the opening screen — which is the
     one thing the front page has to get right. A phone has width to spare and
     no height to spare. */
  .masthead__inner {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 1rem;
  }

  .masthead__brand {
    order: -1;
  }

  .masthead__figure .mark {
    height: 120px;
  }

  .masthead__mark {
    width: min(78%, 190px);
  }

  .masthead__copy {
    font-size: var(--step--1);
    max-width: 34ch;
  }
}

/* Under 360px the two columns leave the words nowhere to go. */
@media (max-width: 359px) {
  .masthead__inner {
    grid-template-columns: 1fr;
  }

  .masthead__figure {
    display: none;
  }
}

/* A short screen spends its height on the shelf, not on the name. The eyebrow
   goes too: the header above it already says whose shop this is, and thirty
   pixels is the difference between seeing a bottle on the opening screen and
   not. */
@media (max-height: 620px) {
  .masthead {
    padding-block: 0.75rem 0.6rem;
  }

  .masthead__figure,
  .masthead__copy,
  .masthead__eyebrow {
    display: none;
  }

  .masthead__mark {
    width: min(48%, 150px);
  }
}

/* --------------------------------------------------------------------------
   Hero (kept for any page that still wants a full one)
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  display: grid;
  align-items: center;
  overflow: clip;
  border-bottom: 1px solid var(--rule-soft);
}

.hero__inner {
  position: relative;
  z-index: 2;
  width: min(100% - var(--gutter) * 2, var(--shell));
  margin-inline: auto;
  padding-block: clamp(2.5rem, 6vw, 5rem);
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  grid-template-columns: 1fr;
}

@media (min-width: 900px) {
  .hero {
    min-height: min(84svh, 820px);
  }

  .hero__inner {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    align-items: center;
  }
}

.hero__mark {
  width: min(100%, 520px);
  color: var(--text);
}

.hero__mark .mark {
  width: 100%;
  height: auto;
}

.hero__motif {
  width: min(56%, 250px);
  margin-bottom: clamp(1.2rem, 3vw, 2rem);
  color: var(--accent-ink);
}

.hero__motif .mark {
  width: 100%;
  height: auto;
}

.hero__copy {
  margin-top: clamp(1.5rem, 4vw, 2.5rem);
  max-width: 44ch;
  font-size: var(--step-1);
  font-style: italic;
  line-height: 1.45;
  color: var(--text-soft);
}

.hero__figure {
  position: relative;
  display: grid;
  place-items: center;
}

.hero__satyr {
  width: min(100%, 400px);
  color: var(--text);
}

.hero__satyr .mark {
  width: 100%;
  height: auto;
}

@media (max-width: 899px) {
  /* Name first. The figure is capped by height, so a tall narrow illustration
     cannot take the whole screen and push the wordmark below the fold. */
  .hero__satyr {
    width: auto;
    max-height: 42svh;
  }

  .hero__satyr .mark {
    width: auto;
    height: 100%;
    max-height: 42svh;
  }
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-top: clamp(1.8rem, 4vw, 2.6rem);
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 48px;
  padding: 0 1.6rem;
  border: 1px solid var(--text);
  background: transparent;
  color: var(--text);
  font-family: var(--body);
  font-size: var(--step--1);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease);
}

.button::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--text);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.4s var(--ease);
  z-index: 0;
}

.button > * {
  position: relative;
  z-index: 1;
}

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

.button:hover::before {
  transform: scaleX(1);
  transform-origin: left;
}

.button--primary {
  border-color: var(--accent-ink);
  color: var(--accent-ink);
}

.button--primary::before {
  background: var(--accent-ink);
}

.button--primary:hover {
  color: var(--paper);
}

.button--solid {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--maroon);
}

.button--solid::before {
  display: none;
}

.button--solid:hover {
  color: var(--maroon);
  filter: brightness(1.06);
}

/* A hover fill is meaningless on touch and leaves a stuck state behind. */
@media (hover: none) {
  .button::before {
    display: none;
  }

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

  .button--primary:hover {
    color: var(--accent-ink);
  }

  .button--solid:hover {
    filter: none;
  }
}

/* --------------------------------------------------------------------------
   Catalogue layout — filters beside the grid

   A sidebar rather than a bar across the top: the grid then starts directly
   under the masthead instead of below 400px of controls, and the filters stay
   in view while the list scrolls. On a phone the same panel collapses behind
   one button, so the bottles are the first thing on screen.

   Base rules first, media queries after — at equal specificity source order
   decides, and putting the overrides above made them silently inert.
   -------------------------------------------------------------------------- */

.catalogue {
  padding-bottom: var(--section);
}

.catalogue__layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.25rem, 3vw, 3rem);
  align-items: start;
}

.catalogue__layout > * {
  min-width: 0;
}

/* Filters -------------------------------------------------------------- */

.facets__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  width: 100%;
  min-height: 48px;
  padding: 0 1rem;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--text);
  font-family: var(--body);
  font-size: var(--step--1);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
}

.facets__badge {
  display: inline-grid;
  place-items: center;
  min-width: 1.5em;
  height: 1.5em;
  padding: 0 0.35em;
  border-radius: 999px;
  background: var(--accent);
  color: var(--maroon);
  font-size: 0.78em;
  font-variant-numeric: tabular-nums;
}

.facet {
  padding-block: 1.1rem;
  border-top: 1px solid var(--rule-soft);
}

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

.facet__label {
  display: block;
  margin: 0 0 0.6rem;
  font-size: var(--step--1);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

.facet__search {
  position: relative;
}

.facet__search input {
  width: 100%;
  min-height: 46px;
  padding: 0.6rem 2.6rem 0.6rem 0.9rem;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--text);
  /* 16px floor keeps iOS Safari from zooming the page on focus. */
  font: 16px/1.4 var(--body);
}

.facet__search input::placeholder {
  color: var(--muted);
  font-style: italic;
}

.facet__search input:focus,
.facet select:focus,
.results__sort select:focus {
  outline: none;
  border-color: var(--accent-ink);
}

.facet__clear {
  position: absolute;
  right: 2px;
  top: 50%;
  transform: translateY(-50%);
  width: 42px;
  height: 42px;
  display: none;
  place-items: center;
  border: 0;
  background: none;
  color: var(--muted);
  font-size: 1.15rem;
  cursor: pointer;
}

[data-search-wrap][data-filled="true"] .facet__clear {
  display: grid;
}

.facet select,
.results__sort select {
  width: 100%;
  min-height: 46px;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--text);
  font: 16px/1.4 var(--body);
  cursor: pointer;
}

/* In stock only — a switch, not another dropdown, because it is a yes or no. */
.facet--switch {
  padding-block: 1rem;
}

.switch {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  min-height: 44px;
  cursor: pointer;
  font-size: var(--step-0);
  color: var(--text);
}

.switch input {
  width: 18px;
  height: 18px;
  accent-color: var(--accent-ink);
  cursor: pointer;
}

.facet__list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.facet__option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  width: 100%;
  min-height: 44px;
  padding: 0 0.55rem;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-family: var(--body);
  font-size: var(--step-0);
  text-align: left;
  cursor: pointer;
  transition: color 0.2s var(--ease), background 0.2s var(--ease);
}

.facet__option span {
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.facet__option:hover {
  color: var(--text);
  background: var(--bg-alt);
}

.facet__option[aria-pressed="true"] {
  background: var(--accent);
  color: var(--maroon);
}

.facet__option[aria-pressed="true"] span {
  color: var(--maroon);
}

.facets__reset {
  width: 100%;
  min-height: 44px;
  margin-top: 1rem;
  border: 0;
  background: none;
  color: var(--accent-ink);
  font: var(--step--1) / 1 var(--body);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: left;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 0.3em;
}

/* Results -------------------------------------------------------------- */

.results__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  padding-bottom: 0.9rem;
  margin-bottom: 1px;
  border-bottom: 1px solid var(--rule-soft);
}

.results__count {
  margin: 0;
  font-size: var(--step--1);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Not knowing what to buy is the normal state in a bottle shop. */
.results__pick {
  min-height: 44px;
  padding: 0 1rem;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--text);
  font-family: var(--body);
  font-size: var(--step--1);
  font-style: italic;
  letter-spacing: 0.06em;
  cursor: pointer;
  transition: background 0.25s var(--ease), color 0.25s var(--ease),
    border-color 0.25s var(--ease);
}

.results__pick:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--maroon);
}

@media (hover: none) {
  .results__pick:hover {
    background: transparent;
    color: var(--text);
    border-color: var(--rule);
  }
}

.results__head {
  gap: 0.75rem 1rem;
}

.results__sort {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.results__sort > span {
  font-size: var(--step--1);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.results__sort select {
  width: auto;
  min-width: 11rem;
}

/* Wide: a real sidebar, staying put while the list scrolls. ------------- */

@media (min-width: 900px) {
  .catalogue__layout {
    grid-template-columns: minmax(200px, 250px) minmax(0, 1fr);
  }

  .facets {
    position: sticky;
    top: calc(var(--header-h) + 1.5rem);
  }

  .facets__toggle {
    display: none;
  }

  .facets__panel {
    display: block !important;
  }
}

/* Narrow: one button, and the bottles start immediately. --------------- */

@media (max-width: 899px) {
  .facets {
    border: 0;
  }

  .facets__panel {
    display: none;
    padding: 1.1rem 0 0.25rem;
  }

  .facets[data-open="true"] .facets__panel {
    display: block;
  }

  .facets[data-open="true"] .facets__toggle {
    border-color: var(--accent-ink);
  }

  .results__head {
    margin-top: 1.25rem;
  }
}

/* --------------------------------------------------------------------------
   Catalogue grid and card
   -------------------------------------------------------------------------- */

.product-grid {
  display: grid;
  /* auto-fit, not auto-fill: empty tracks collapse instead of being drawn. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
  gap: 0;
  border-top: 1px solid var(--rule-soft);
  border-left: 1px solid var(--rule-soft);
  list-style: none;
  padding: 0;
  margin: 0;
}

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

/* Rows that always hold exactly four cards need column counts that divide
   four, or the last row is left short. */
.product-grid--four {
  grid-template-columns: 1fr;
}

@media (min-width: 520px) {
  .product-grid--four {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1040px) {
  .product-grid--four {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  /* Hairlines sit on the card, not in the grid's gaps — a grid background
     showing through a gap paints a whole empty cell as a panel. */
  border-right: 1px solid var(--rule-soft);
  border-bottom: 1px solid var(--rule-soft);
  background: var(--bg);
  padding: clamp(1.5rem, 2.6vw, 2.25rem);
  transition: background 0.35s var(--ease);
}

.card:hover {
  background: var(--bg-alt);
}

.card__link {
  text-decoration: none;
  color: inherit;
}

.card__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.card__media {
  aspect-ratio: 1 / 1;
  display: grid;
  place-items: center;
  margin-bottom: 1.3rem;
  background: color-mix(in srgb, var(--green) 4%, transparent);
  overflow: hidden;
}

.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  animation: photo-in 0.5s var(--ease) both;
}

@keyframes photo-in {
  from {
    opacity: 0;
  }
}

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

/* Waiting for a photograph. Kept very quiet — a strong mark repeated down the
   page is what made the grid look like twenty failed images. */
.card__media--mark {
  color: color-mix(in srgb, var(--green) 16%, transparent);
  transition: color 0.4s var(--ease);
}

.card__media--mark .mark {
  width: 46%;
}

.card:hover .card__media--mark {
  color: color-mix(in srgb, var(--maroon) 34%, transparent);
}

.card__category {
  font-size: var(--step--1);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.7rem;
}

.card__name {
  font-size: var(--step-2);
  line-height: 1.04;
  margin-bottom: 0.7rem;
  text-wrap: balance;
  transition: color 0.3s var(--ease);
}

.card:hover .card__name {
  color: var(--accent-ink);
}

/* The tasting note is the card's content. Without it the card was a name and
   an empty frame, which is what made twenty of them look like a template. */
.card__note {
  font-size: var(--step-0);
  font-style: italic;
  line-height: 1.5;
  text-wrap: pretty;
  color: var(--text-soft);
  margin: 0 0 1.5rem;
  max-width: 34ch;
}

.card__foot {
  margin-top: auto;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 1.1rem;
  position: relative;
}

/* A hairline that draws itself on hover, rather than sitting there. */
.card__foot::before,
.card__foot::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  height: 1px;
}

.card__foot::before {
  right: 0;
  background: var(--rule-soft);
}

.card__foot::after {
  width: 100%;
  background: var(--accent-ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.55s var(--ease);
}

.card:hover .card__foot::after {
  transform: scaleX(1);
}

.price {
  font-family: var(--display);
  font-size: var(--step-2);
  font-weight: 500;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--text);
  white-space: nowrap;
  line-height: 1;
}

.price small {
  font-family: var(--body);
  font-size: 0.42em;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.card__spec {
  font-size: var(--step--1);
  font-style: italic;
  color: var(--muted);
  white-space: nowrap;
}

/* Only present when it says something, so it can afford to be loud. */
.card__flag {
  align-self: flex-start;
  margin-top: 0.9rem;
  font-size: var(--step--1);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-ink);
}

.card__flag[data-out="true"] {
  color: var(--muted);
}

/* New on the shelf. Deliberately a small pink tick rather than a loud label —
   four of twenty carry it, and it should reward noticing. */
.card__new {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
  padding: 0.35rem 0.7rem;
  background: var(--accent);
  color: var(--maroon);
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* A long grid costs layout even where it is not on screen. */
.product-grid > * {
  content-visibility: auto;
  contain-intrinsic-size: auto 480px;
}

.badge {
  position: absolute;
  top: 0;
  right: 0;
  padding: 0.3rem 0.7rem;
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  border-left: 1px solid var(--rule-soft);
  border-bottom: 1px solid var(--rule-soft);
}

/* Small-screen card. Must come after the base rules above: same specificity,
   so source order decides, and placing it earlier made every one of these
   declarations inert while still looking correct in the diff. */
@media (max-width: 759px) {
  .product-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .card {
    padding: 0.85rem 0.85rem 1rem;
  }

  .card__media {
    margin-bottom: 0.9rem;
  }

  .card__category {
    font-size: 0.68rem;
    letter-spacing: 0.14em;
    margin-bottom: 0.4rem;
  }

  .card__name {
    font-size: 1.05rem;
    line-height: 1.12;
  }

  /* In a 160px column the note runs to five lines and every card in the row
     grows to match the longest. Three lines keeps the grid even; the whole
     note is on the bottle's own page. */
  .card__note {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
    font-size: var(--step--1);
    margin-bottom: 1.1rem;
  }

  .card__meta {
    margin-bottom: 0.7rem;
  }

  .card__foot {
    /* Price and stock stack rather than squeezing onto one narrow line. */
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
    padding-top: 0.75rem;
  }

  .badge {
    padding: 0.2rem 0.45rem;
    font-size: 0.6rem;
  }
}

/* 320px still holds two columns once the card is this compact; one column
   there meant thirteen thousand pixels of scrolling for twenty bottles. */
@media (max-width: 359px) {
  .card {
    padding: 0.7rem 0.7rem 0.85rem;
  }

  .card__name {
    font-size: 0.98rem;
  }
}


/* Cards that have just come back into the results ease in. Only entering is
   animated — animating the exit would hold space for something already gone
   and make the grid reflow twice. */
@keyframes card-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

.card.is-entering {
  animation: card-in 0.42s var(--ease) both;
}

/* First paint only: the shelf fills in rather than appearing at once. JS marks
   the grid settled afterwards so filtering is not slowed by the stagger. */
.product-grid:not([data-settled]) .card {
  animation: card-in 0.6s var(--ease) both;
  animation-delay: calc(var(--n, 0) * 45ms);
}

@media (prefers-reduced-motion: reduce) {
  .card.is-entering,
  .product-grid:not([data-settled]) .card {
    animation: none;
  }
}

/* What you were looking at last time. Only appears once there is more than
   one, since a list of one is not a history. */
.recent {
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule-soft);
}

.recent[hidden] {
  display: none;
}

.recent__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  list-style: none;
  padding: 0;
  margin: 0;
}

.recent__list a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-family: var(--display);
  font-size: var(--step-1);
  text-decoration: none;
}

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

/* The map is a card, not an embed: nothing is fetched from a map provider
   until somebody chooses to open one. */
.mapcard {
  margin-top: clamp(2.5rem, 5vw, 4rem);
  border: 1px solid var(--rule-soft);
  background: var(--bg-alt);
}

.mapcard__inner {
  padding: clamp(1.5rem, 3vw, 2.5rem);
  max-width: 52ch;
}

.no-results,
.empty-state {
  padding-block: clamp(3rem, 8vw, 5rem);
  text-align: center;
}

/* Centre everything the block contains, including the eyebrow whose flex rule
   would otherwise stretch to the left edge. */
.empty-state .eyebrow {
  justify-content: center;
}

.empty-state .eyebrow::after {
  display: none;
}

.empty-state .lede {
  margin-inline: auto;
}

.no-results[hidden] {
  display: none;
}

.no-results .mark {
  width: min(100%, 170px);
  margin: 0 auto 1.8rem;
  color: var(--rule);
}

/* --------------------------------------------------------------------------
   Product page
   -------------------------------------------------------------------------- */

.product {
  display: grid;
  gap: clamp(2rem, 6vw, 5rem);
  grid-template-columns: 1fr;
  padding-block: clamp(1.5rem, 1rem + 3vw, 3rem)
    clamp(2rem, 1.2rem + 3vw, 3.5rem);
}

@media (min-width: 900px) {
  .product {
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
    align-items: start;
  }

  /* With a photograph the text sits beside it, so the lead and the detail
     stack in the one column. Without one they take a column each, which uses
     the width instead of leaving half the page empty. */
  .product:has(.product__media) .product__lead,
  .product:has(.product__media) .product__detail {
    grid-column: 2;
  }

  .product:not(:has(.product__media)) {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  }

  /* No cap on the lead: capping it inside a proportional column only opens a
     trough between the two. The column width is the measure. */
  .product:not(:has(.product__media)) {
    gap: clamp(2rem, 5vw, 4.5rem);
    grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  }
}

.product > * {
  min-width: 0;
}

.product__media {
  /* Until there are photographs this panel is a large empty field, so it is
     kept square: tall ratios ran it well past the end of the text beside it
     and made the grey the loudest thing on the page. */
  aspect-ratio: 1 / 1;
  display: grid;
  place-items: center;
  background: var(--bg-alt);
  border: 1px solid var(--rule-soft);
  position: sticky;
  top: calc(var(--header-h) + 2rem);
}

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

.product__media .mark {
  width: 55%;
  color: color-mix(in srgb, var(--green) 24%, transparent);
}

@media (max-width: 899px) {
  .product__media {
    position: static;
    aspect-ratio: 4 / 3;
  }
}

.product__title {
  font-size: var(--step-3);
  margin-bottom: 0.6rem;
  text-wrap: balance;
}

.product__lead .lede {
  text-wrap: pretty;
}

.product__detail .spec {
  margin-top: 0;
}

.product__price {
  font-family: var(--display);
  font-size: var(--step-2);
  color: var(--text);
  font-weight: 500;
  font-variant-numeric: lining-nums tabular-nums;
  margin-block: 1.4rem;
}

.product__share {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: -0.5rem;
}

.link-share {
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font: var(--step--1) / 1 var(--body);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 0.3em;
}

.link-share:hover {
  color: var(--accent-ink);
}

.link-share__said {
  font-size: var(--step--1);
  font-style: italic;
  color: var(--accent-ink);
}

.link-share__said[hidden] {
  display: none;
}

/* A bottle that has left the shelf says so, rather than looking current. */
.notice {
  margin: 0 0 1.5rem;
  padding: 0.9rem 1.1rem;
  border-left: 2px solid var(--accent-ink);
  background: var(--bg-alt);
  font-size: var(--step--1);
  font-style: italic;
  color: var(--text-soft);
}

.price__rate {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--body);
  font-size: 0.72rem;
  font-style: italic;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
}

.spec {
  width: 100%;
  border-collapse: collapse;
  margin-block: 2rem;
  font-size: var(--step--1);
}

.spec th,
.spec td {
  text-align: left;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--rule-soft);
  vertical-align: baseline;
}

.spec th {
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  width: 42%;
}

.spec td {
  font-style: italic;
  color: var(--text-soft);
}

.note {
  font-size: var(--step--1);
  font-style: italic;
  line-height: 1.5;
  color: var(--muted);
  margin-top: 1.2rem;
}

/* Somewhere to go from a bottle other than back. */
.pager {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  border-top: 1px solid var(--rule-soft);
  border-left: 1px solid var(--rule-soft);
}

@media (min-width: 620px) {
  .pager {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.pager__link {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-height: 88px;
  justify-content: center;
  padding: 1.25rem clamp(1rem, 2vw, 1.75rem);
  border-right: 1px solid var(--rule-soft);
  border-bottom: 1px solid var(--rule-soft);
  text-decoration: none;
  transition: background 0.3s var(--ease);
}

.pager__link:hover {
  background: var(--bg-alt);
}

.pager__link--next {
  text-align: right;
  align-items: flex-end;
}

.pager__dir {
  font-size: var(--step--1);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

.pager__name {
  font-family: var(--display);
  font-size: var(--step-1);
  font-weight: 500;
  color: var(--text);
  transition: color 0.25s var(--ease);
}

.pager__link:hover .pager__name {
  color: var(--accent-ink);
}

/* --------------------------------------------------------------------------
   Editorial blocks
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  gap: clamp(2rem, 5vw, 4.5rem);
  grid-template-columns: 1fr;
  align-items: center;
}

/* Columns of very different heights should share a top edge, not float
   against each other's middles. */
.split--top {
  align-items: start;
}

@media (min-width: 860px) {
  .split {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.split > * {
  min-width: 0;
}

.prose {
  max-width: var(--measure);
}

.prose h2 {
  font-size: var(--step-2);
  margin-bottom: 1.2rem;
}

.prose h3 {
  font-size: var(--step-1);
  margin: 2.5rem 0 0.8rem;
}

.display-xl {
  font-size: var(--step-4);
  line-height: 0.96;
}

.category-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  border-top: 1px solid var(--rule-soft);
  border-left: 1px solid var(--rule-soft);
  list-style: none;
  padding: 0;
  margin: 0;
}

.category-list > * {
  min-width: 0;
}

@media (min-width: 620px) {
  .category-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1000px) {
  /* Three across, so six categories fill two rows exactly rather than leaving
     one card alone against a band of empty background. */
  .category-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.category-card {
  display: block;
  border-right: 1px solid var(--rule-soft);
  border-bottom: 1px solid var(--rule-soft);
  background: var(--bg);
  padding: clamp(1.6rem, 3vw, 2.4rem);
  text-decoration: none;
  color: inherit;
  transition: background 0.35s var(--ease);
}

.category-card:hover {
  background: var(--bg-alt);
}

.category-card h3 {
  font-size: var(--step-2);
  margin-bottom: 0.7rem;
}

.category-card p {
  font-style: italic;
  color: var(--muted);
  font-size: var(--step--1);
  margin: 0;
}

.category-card__count {
  display: block;
  margin-top: 1.4rem;
  font-size: var(--step--1);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}

.category-card:hover .category-card__count {
  color: var(--accent-ink);
}

.info-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr));
  gap: clamp(1.8rem, 4vw, 3rem);
}

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

.info-grid h3 {
  font-size: var(--step--1);
  font-family: var(--body);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1rem;
}

.hours {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: var(--step-0);
}

.hours li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 0.5rem;
  border-bottom: 1px solid var(--rule-soft);
}

.hours span:last-child {
  font-variant-numeric: tabular-nums;
  font-style: italic;
  color: var(--text-soft);
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.footer {
  background: var(--bg-invert);
  --text: var(--gold);
  --muted: #8d9a74;
  --rule-soft: color-mix(in srgb, var(--gold) 14%, transparent);
  color: var(--text);
  padding-block: clamp(3rem, 6vw, 5rem) 2rem;
}

.footer__top {
  display: grid;
  gap: clamp(2rem, 4vw, 3rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  padding-bottom: clamp(2.5rem, 5vw, 4rem);
}

.footer__top > * {
  min-width: 0;
}

.footer__mark {
  width: min(100%, 200px);
  color: var(--gold);
}

.footer h3 {
  font-family: var(--body);
  font-size: var(--step--1);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 1.1rem;
}

.footer ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.footer li {
  margin-bottom: 0.6rem;
}

.footer a {
  text-decoration: none;
  color: var(--gold);
  display: inline-flex;
  align-items: center;
  min-height: 32px;
}

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

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  justify-content: space-between;
  align-items: center;
  padding-top: 2rem;
  border-top: 1px solid var(--rule-soft);
  font-size: var(--step--1);
  color: var(--muted);
}

.footer__legal {
  font-style: italic;
  max-width: 52ch;
}

/* Only shown once an answer is actually stored — there is nothing to reset
   before that. */
.footer__reset {
  display: inline;
  margin-left: 0.5em;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

.footer__reset:hover {
  color: var(--pink);
}

/* A pointer can hit a 32px link; a finger wants 44. Scoped to touch so the
   footer does not go slack on a desktop. */
@media (hover: none) {
  .footer a,
  .nav__link {
    min-height: 44px;
  }

  /* Added with the rest of the footer links, and it needs the same reach. */
  .footer__reset {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* --------------------------------------------------------------------------
   Age gate
   -------------------------------------------------------------------------- */

.age-gate {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: grid;
  place-items: center;
  padding: var(--gutter);
  background: var(--paper);
  text-align: center;
}

.age-gate[hidden] {
  display: none;
}

.age-gate__inner {
  max-width: 40ch;
  animation: rise 0.7s var(--ease) both;
}

.age-gate__satyr .mark {
  height: min(42vh, 260px);
  margin-inline: auto;
}

.age-gate__satyr {
  width: min(42vw, 140px);
  margin: 0 auto 2rem;
  color: var(--text);
}

.age-gate h1 {
  font-size: var(--step-2);
  margin-bottom: 1rem;
}

.age-gate p {
  font-style: italic;
  color: var(--muted);
  margin-bottom: 2rem;
}

.age-gate__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  justify-content: center;
}

.age-gate__deny {
  display: none;
  margin-top: 1.5rem;
  font-style: italic;
  color: var(--muted);
}

.age-gate[data-denied="true"] .age-gate__deny {
  display: block;
}

.age-gate[data-denied="true"] .age-gate__actions {
  display: none;
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Set in the head before paint, so the shop is never shown to someone who has
   not answered and the gate never flashes for someone who has. */
.is-gated body > *:not(.age-gate) {
  visibility: hidden;
}

.is-gated .age-gate {
  display: grid;
}

/* --------------------------------------------------------------------------
   Reveal on scroll
   -------------------------------------------------------------------------- */

[data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}

[data-reveal][data-revealed="true"] {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1;
    transform: none;
  }
}

/* Same-origin navigation cross-fades where the browser supports it; elsewhere
   this rule is simply ignored. */
@view-transition {
  navigation: auto;
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

/* Six screens of shelf deserve a way back. Appears once you are well down,
   and is a plain link to #main so it works without JavaScript. */
.to-top {
  position: fixed;
  right: clamp(1rem, 3vw, 2.5rem);
  bottom: clamp(1rem, 3vw, 2.5rem);
  z-index: 60;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--text);
  text-decoration: none;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease),
    background 0.2s var(--ease), color 0.2s var(--ease);
}

.to-top[hidden] {
  display: none;
}

.to-top[data-shown="true"] {
  opacity: 1;
  transform: none;
}

.to-top:hover {
  background: var(--accent-ink);
  color: var(--paper);
  border-color: var(--accent-ink);
}

.to-top__arrow {
  font-size: 1.1rem;
  line-height: 1;
}

@media (max-width: 359px), (max-height: 600px) {
  .presets {
    display: none;
  }
}

/* A short screen — a 320x568 phone, or a landscape one — has to spend its
   height on the shelf rather than on the name of the shop. The wordmark
   shrinks and the line under it goes; the brand is still the first thing,
   just not the only thing. */
@media (max-height: 620px) {
  .masthead {
    padding-block: 0.9rem 0.7rem;
  }

  .masthead__mark {
    width: min(62%, 190px);
  }

  .masthead__copy {
    display: none;
  }
}

/* Presets, because "something under a thousand" is how a present is chosen. */
.presets {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 1.25rem;
  margin: 0 0 1.5rem;
  font-size: var(--step--1);
}

.presets > span {
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.presets a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-style: italic;
  font-size: var(--step-0);
  text-decoration-color: var(--rule);
}

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

/* 11. Someone asking their browser to save data should not be sent 336 KB of
   webfonts for a shelf list. */
@media (prefers-reduced-data: reduce) {
  :root {
    --display: Georgia, "Times New Roman", serif;
    --body: Georgia, "Times New Roman", serif;
  }

  .card__media--mark,
  .masthead__figure,
  .masthead__motif,
  .motif-rule {
    display: none;
  }

  [data-reveal],
  .card,
  .card.is-entering {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* --------------------------------------------------------------------------
   Print — a shelf list someone can carry
   -------------------------------------------------------------------------- */

@media print {
  :root {
    --bg: #fff;
    --bg-alt: #fff;
    --text: #000;
    --text-soft: #222;
    --muted: #444;
    --rule: #999;
    --rule-soft: #ccc;
  }

  .header,
  .footer,
  .facets,
  .results__sort,
  .skip-link,
  .age-gate,
  .masthead__figure,
  .masthead__motif {
    display: none !important;
  }

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

  .section,
  .catalogue,
  .product {
    padding-block: 0 1rem;
  }

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

  .product-grid {
    grid-template-columns: repeat(3, 1fr);
  }

  .card__media,
  .product__media {
    display: none;
  }

  .card,
  .category-card {
    break-inside: avoid;
  }

  /* A printed link is useless without its address. The same pseudo-element
     is the card's click overlay, so it has to come out of absolute
     positioning first or the address prints across the card's top corner. */
  .card__link::after {
    content: " (" attr(href) ")";
    position: static;
    display: block;
    inset: auto;
    margin-top: 0.3em;
    font-size: 0.68em;
    font-style: italic;
    color: #666;
    word-break: break-all;
  }

  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* The night palette, applied by the system preference — but only when the
   config asks for it. See site.json: appearance.follow_system_dark. */
@media (prefers-color-scheme: dark) {
  body[data-follow-system] {
    --bg: var(--green);
    --bg-alt: #172b05;
    --bg-invert: var(--maroon);
    --text: var(--gold);
    --text-soft: #c4b58e;
    --muted: #8d9a74;
    --accent: var(--pink);
    --accent-ink: var(--pink);
    --rule: color-mix(in srgb, var(--gold) 26%, transparent);
    --rule-soft: color-mix(in srgb, var(--gold) 12%, transparent);
  }

  body[data-follow-system] .header,
  body[data-follow-system] .nav,
  body[data-follow-system] .age-gate {
    background: var(--green);
  }

  body[data-follow-system] .filters,
  body[data-follow-system] .facet__search input,
  body[data-follow-system] .facet select,
  body[data-follow-system] .results__sort select {
    background: transparent;
    color: var(--gold);
  }
}

/* --------------------------------------------------------------------------
   After hours. Sought, not stumbled on — the dark half of the brand.
   -------------------------------------------------------------------------- */

body[data-colourway="satyr"] {
  --bg: var(--green);
  --bg-alt: #172b05;
  --bg-invert: var(--maroon);
  --text: var(--gold);
  --text-soft: #c4b58e;
  --muted: #8d9a74;
  --accent: var(--pink);
  --accent-ink: var(--pink);
  --rule: color-mix(in srgb, var(--gold) 26%, transparent);
  --rule-soft: color-mix(in srgb, var(--gold) 12%, transparent);
  transition: background 0.8s var(--ease), color 0.8s var(--ease);
}

body[data-colourway="satyr"] .facet__option[aria-pressed="true"],
body[data-colourway="satyr"] .facets__badge {
  color: var(--maroon);
}

body[data-colourway="satyr"] .header,
body[data-colourway="satyr"] .nav {
  background: var(--maroon);
}

body[data-colourway="satyr"] .age-gate {
  background: var(--green);
}

body[data-colourway="satyr"] .facet__search input,
body[data-colourway="satyr"] .facet select,
body[data-colourway="satyr"] .results__sort select {
  background: transparent;
  color: var(--gold);
}

body[data-colourway="satyr"] .card__media--mark {
  color: color-mix(in srgb, var(--gold) 30%, transparent);
}

body[data-colourway="satyr"] .card:hover .card__media--mark {
  color: color-mix(in srgb, var(--pink) 55%, transparent);
}

body[data-colourway="satyr"] .button--primary:hover {
  color: var(--maroon);
}
