/* ==========================================================================
   Tall Heights — tallheights.com

   Art direction is the Neptune record's own: the 2016 cover specimen, the
   Weed & Weed logotype and circle mark, Bodoni under it, Scala Sans as the
   workhorse — the same face that is on the LP packaging.

   Two things to know before editing:

   1. The campaign palette lives in --c-* and nothing else references colour
      directly. This band re-skins hard every album cycle (five wordmarks in
      fifteen years — see docs/brand/visual-identity.md), so "make it warmer"
      or "try it darker" has to stay a small change. It does.

   2. There are no transitions or keyframes anywhere in this file, on purpose.
      Tim, 2026-09-04: "No need for animations either."
   ========================================================================== */

:root {
  /* --- Campaign palette ---
     Sampled off Tim's own Admat Draft080726a, which is where this campaign's
     colour actually lives. Note it is violet-forward rather than the
     near-black aubergine of the 2016 sleeve, and that the letterspaced sans
     on the admat is a neutral grey, not a tint of the plum. Both preserved. */
  --c-ground:  #c2c3c8;  /* Deliberately NOT the plate's grey. The cover, the
                            admat and the product renders all sit on #cecfd1;
                            the page is one step deeper so that artwork reads
                            as objects on a surface instead of dissolving into
                            it. Chosen deeper rather than warmer because a warm
                            ground puts the cream 10TH lockup at cream-on-cream
                            — see the commit that set this.

                            Everything cut out of a PSD is flattened onto this
                            exact value, which is why the flower and the
                            products have no visible edge. Change it and re-run
                            tools/build-neptune-assets.py; the script reads
                            this token rather than keeping its own copy. */
  --c-ink:     #39393a;  /* the admat's "ANNIVERSARY TOUR" — body and UI */
  --c-wordmark:#542d5e;  /* the logotype's plum */
  --c-violet:  #684072;  /* "NEPTUNE" on the admat, taken a few steps
                            deeper so it clears AA on the ground — the admat's
                            own #794e85 measures 3.68:1, and this colour is used
                            on small letterspaced caps */
  --c-plum:    #2a1020;  /* darkest ground, for inverted blocks */
  --c-amber:   #7b4d28;  /* dried petal body */
  --c-stem:    #573618;
  --c-cream:   #f9e9d6;  /* the "10" — the one bright note */

  /* --- Semantic --- */
  --bg:         var(--c-ground);
  --bg-invert:  var(--c-plum);
  --text:       var(--c-ink);
  /* 85%, not the 58% this started at. Muted text here is prices, venue
     locations, eyebrows and the footer tagline — all real content at
     --step--1, so it needs 4.5:1, and 58% delivered 2.7:1. The tonal step down
     from --c-ink is smaller than it looks on paper but still reads. */
  --text-muted: color-mix(in srgb, var(--c-ink) 85%, var(--c-ground));
  --accent:     var(--c-violet);
  --rule:       color-mix(in srgb, var(--c-ink) 28%, transparent);
  --on-invert:  var(--c-cream);

  /* --- Type ---
     bodoni-std has no bold in the kit and does not want one; it is only ever
     set large. ff-scala-sans-pro carries 400/700 and both italics. */
  --font-display: "bodoni-std", "Bodoni Moda", Didot, "Bodoni MT", Georgia, serif;
  --font-body:    "ff-scala-sans-pro", "Source Sans 3", ui-sans-serif, system-ui,
                  -apple-system, "Helvetica Neue", Arial, sans-serif;
  --font-cond:    "ff-scala-sans-pro-condensed", var(--font-body);

  /* Fluid scale. Body floor is 17px — the Wix site's 10px is the single thing
     the audit was most emphatic about fixing. */
  --step--1: clamp(0.86rem, 0.83rem + 0.14vw, 0.94rem);
  --step-0:  clamp(1.06rem, 1rem + 0.3vw, 1.19rem);
  --step-1:  clamp(1.28rem, 1.14rem + 0.68vw, 1.66rem);
  --step-2:  clamp(1.7rem, 1.4rem + 1.5vw, 2.6rem);
  --step-3:  clamp(2.3rem, 1.7rem + 3vw, 4.2rem);

  --measure: 60ch;
  --gutter:  clamp(1.25rem, 5vw, 4rem);
  --flow:    1.1em;
  --mast-h:  4.25rem;
}

/* --------------------------------------------------------- reset + base */
*, *::before, *::after { box-sizing: border-box; }
body, h1, h2, h3, p, figure, ul, ol { margin: 0; }
ul[role="list"] { list-style: none; padding: 0; }
img, picture, svg { max-width: 100%; display: block; }
/* Without this, any <img> carrying width/height attributes is stretched the
   moment max-width shrinks it: the width scales, the attribute height does
   not. It is why the Endless Autumn artwork was ~9% too tall. Keep the
   attributes — they reserve the right space while the image loads — and let
   the height follow the width. Scoped to img so inline SVG sizing is
   untouched; .goods--featured sets its own height and still wins. */
img { height: auto; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: auto; }
/* The one exception to "no animation": an anchored jump glides, so it
   reads as travel down the page rather than a cut to somewhere new.
   Tim, 2026-09-08. Off for anyone who asks the OS for less motion. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.6;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* No texture here, deliberately. An earlier version laid a CSS linen tooth
     over the page, which darkened the ground by about a value and left the
     flower JPEGs — whose ground is painted flat --c-ground — sitting in a
     visible lighter rectangle. The whole point of compositing them onto the
     page colour is that the edge disappears, so the page has to stay flat. */
}

main { flex: 1; }

:where(a) { color: inherit; text-underline-offset: .22em; }
:where(a):hover { color: var(--accent); }

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

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

.skip {
  position: absolute; inset-inline-start: -9999px; top: 0; z-index: 100;
  background: var(--bg-invert); color: var(--on-invert); padding: .75rem 1rem;
}
.skip:focus { inset-inline-start: 0; }

/* --------------------------------------------------------------- layout */
.wrap {
  width: min(72rem, 100% - var(--gutter) * 2);
  margin-inline: auto;
}

.section { padding-block: clamp(3.5rem, 9vw, 7rem); }
.section + .section { padding-block-start: 0; }

/* An anchored jump stops below the sticky masthead instead of under it. */
:target { scroll-margin-block-start: calc(var(--mast-h) + 1.5rem); }

.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem 2rem;
  flex-wrap: wrap;
  border-block-end: 1px solid var(--rule);
  padding-block-end: .9rem;
  margin-block-end: clamp(1.75rem, 4vw, 2.75rem);
}

/* Scala Sans defaults to oldstyle figures, which are lovely in running text
   and wrong in a letterspaced all-caps line — "OUT NOVEMBER 13" comes out with
   the 1 and 3 sitting below the caps. Every uppercase context below asks for
   lining figures instead. */
.eyebrow,
.nav,
.btn,
.hero__sub,
.hero__celebrating,
.show__date,
.seated-event-date-cell,
.tour .seated-event-link,
.tour .seated-event-link1,
.foot h2 { font-variant-numeric: lining-nums; }

.eyebrow {
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 400;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.display {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.04;
  letter-spacing: .005em;
  font-size: var(--step-2);
}

/* ------------------------------------------------------------- the marks
   Every one is an alpha mask painted with background-color, so a single file
   serves plum on the ground and cream on the dark blocks. See the header of
   tools/build-neptune-assets.py.

   Anything given a mask below MUST be in this selector list — a mask with no
   background-color lays out at the right size and paints nothing at all,
   which looks exactly like a missing file. */
.wordmark, .mark, .th, .ten, .star {
  display: block;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center;  mask-position: center;
  -webkit-mask-size: contain;     mask-size: contain;
}

.wordmark {
  -webkit-mask-image: url("/assets/img/wordmark-mask.png");
          mask-image: url("/assets/img/wordmark-mask.png");
  aspect-ratio: 3035 / 911;
  width: 100%;
}
.wordmark--sm { width: 11rem; }

.mark {
  -webkit-mask-image: url("/assets/img/mark-mask.png");
          mask-image: url("/assets/img/mark-mask.png");
  aspect-ratio: 1; width: 2.4rem;
}

.th {
  -webkit-mask-image: url("/assets/img/th-mask.png");
          mask-image: url("/assets/img/th-mask.png");
  aspect-ratio: 392 / 187; width: 2.6rem;
}

.ten {
  -webkit-mask-image: url("/assets/img/ten-mask.png");
          mask-image: url("/assets/img/ten-mask.png");
  aspect-ratio: 904 / 676; width: 100%;
}

/* The campaign lockup: a big "10" with "TH" set beside it, so the pair reads
   as 10TH and the TH is also the band's own initials. Tim, 2026-09-04:
   "Tall Heights starts with TH."

   Every number here is measured off the layer boxes in Admat Draft080726a,
   expressed against the width of the 10 so the whole thing scales as one
   piece:  TH is 0.434 of the 10's width, starts 0.058 past its right edge,
   and its baseline sits 0.229 of the 10's height up from the 10's bottom.
   The 10's own height is 676/904 = 0.748 of its width, hence that factor.

   Colour and size both depart from the admat, at Tim's direction (2026-09-04):
   cream to match the 10, so the pair reads as one soft mark, and successively
   larger — 0.434 on the admat, then 0.52, now 0.70 of the 10's width. Cream
   carries less weight than the admat's dark TH did, so it takes more size to
   hold the same presence. At 0.70 the TH stands 45% of the 10's height. */
.tenth {
  --ten-w: clamp(4rem, 11vw, 6.5rem);
  display: inline-flex;
  align-items: flex-end;
  gap: calc(var(--ten-w) * 0.058);
}

.tenth__ten {
  width: var(--ten-w);
  color: var(--c-cream);
}

.tenth__th {
  width: calc(var(--ten-w) * 0.70);
  margin-block-end: calc(var(--ten-w) * 0.748 * 0.229);
  color: var(--c-cream);
}

.hero__celebrating {
  margin-block-start: clamp(1.25rem, 3vw, 2rem);
  font-size: var(--step--1);
  letter-spacing: .3em; text-transform: uppercase;
  color: var(--c-violet);
}

.hero__tenth { margin-block-start: .35rem; }

.star {
  -webkit-mask-image: url("/assets/img/star-mask.png");
          mask-image: url("/assets/img/star-mask.png");
  aspect-ratio: 87 / 82; width: .7rem;
}

/* -------------------------------------------------------------- masthead */
.mast {
  position: sticky; top: 0; z-index: 30;
  background: var(--bg);
  border-block-end: 1px solid var(--rule);
}

.mast__inner {
  width: min(72rem, 100% - var(--gutter) * 2);
  margin-inline: auto;
  min-height: var(--mast-h);
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}

.mast__mark { color: var(--c-wordmark); display: block; }
.mast__mark:hover { color: var(--accent); }

.nav {
  display: flex; gap: clamp(1.1rem, 4vw, 2.5rem);
  font-size: var(--step--1);
  letter-spacing: .18em; text-transform: uppercase;
}
.nav a { text-decoration: none; }
.nav a[aria-current="page"] { text-decoration: underline; text-underline-offset: .4em; }

/* ------------------------------------------------------------------ hero
   The specimen centred, the ground running to every edge — the cover's own
   composition, which is mostly empty field. Restraint is the point; resist
   filling it. */
.hero {
  text-align: center;
  padding-block: clamp(2.5rem, 6vw, 4.5rem) clamp(3rem, 8vw, 6rem);
}

.hero__wordmark {
  color: var(--c-wordmark);
  width: min(34rem, 88%);
  margin: clamp(.5rem, 2vw, 1.25rem) auto 0;
}

.hero__sub {
  margin-block-start: 1.1rem;
  font-size: var(--step--1);
  letter-spacing: .3em; text-transform: uppercase;
  color: var(--text-muted);
}

.hero__flower {
  width: min(34rem, 92%);
  margin-inline: auto;
  height: auto;
}

/* The admat's divider — two hairlines with the circle mark centred between
   them. Tim uses it under the tour lockup; it is the one piece of ornament
   this design gets, so it is worth reusing rather than inventing another. */
.rule-mark {
  display: flex; align-items: center; gap: 1rem;
  margin-block: clamp(1.5rem, 4vw, 2.25rem);
  color: var(--c-violet);
}
.rule-mark::before, .rule-mark::after {
  content: ""; flex: 1; height: 1px; background: var(--rule);
}
.rule-mark .mark { width: 1.5rem; flex: none; }

/* --------------------------------------------------------------- buttons */
.btn-row {
  display: flex; flex-wrap: wrap; gap: .75rem;
  justify-content: center;
  margin-block-start: clamp(1.5rem, 4vw, 2.5rem);
}

.btn {
  display: inline-block;
  font-size: var(--step--1);
  letter-spacing: .18em; text-transform: uppercase;
  padding: .72rem 1.6rem;
  border: 1px solid var(--c-wordmark);
  color: var(--c-wordmark);
  text-decoration: none;
  background: transparent;
  cursor: pointer;
  font-family: inherit;
}
.btn:hover { background: var(--c-wordmark); color: var(--c-ground); }

.btn--solid { background: var(--c-wordmark); color: var(--c-ground); }
.btn--solid:hover { background: var(--c-violet); border-color: var(--c-violet); color: var(--c-cream); }

/* ----------------------------------------------------------------- store
   Kahan's homepage scrolls out of the hero straight into product, which is
   the pattern Tim asked for. Checkout stays on Shopify; this is a window. */
.goods {
  list-style: none; padding: 0; margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(13rem, 100%), 1fr));
  gap: clamp(1.25rem, 3vw, 2.25rem);
}

.good a { text-decoration: none; display: block; }

.good__img {
  width: 100%; aspect-ratio: 1; object-fit: cover;
  background: color-mix(in srgb, var(--c-ink) 5%, var(--c-ground));
}

.good__name {
  margin-block-start: .8rem;
  font-size: var(--step--1);
  line-height: 1.35;
}

.good__price {
  margin-block-start: .15rem;
  font-size: var(--step--1);
  color: var(--text-muted);
}

.good--out .good__img { opacity: .5; }

/* ------------------------------------------------------------------ tour
   Seated renders the dates; these are its own class names. If Seated ever
   restyles the widget the worst case is it falls back to their default look
   and the dates still render. See docs/seated-tour-dates.md. */
.tour { min-height: 6rem; }

.seated-events-table { border-block-start: 1px solid var(--rule); }

/* Seated nests one level deeper than it looks: the row's only two children
   are .seated-event-description-cells and .seated-event-link-cells, and the
   date/venue/details sit inside the first. So the row aligns the two columns
   and the inner block lays out the cells. An earlier version put
   `align-items: baseline` on the row, which baseline-aligned the button
   against a three-line block and floated it above the date. */
.seated-event-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.5rem;
  padding-block: 1.15rem;
  border-block-end: 1px solid var(--rule);
}

.seated-event-description-cells {
  flex: 1 1 20rem;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .1rem 1.5rem;
}

.seated-event-date-cell {
  font-family: var(--font-cond);
  font-size: var(--step--1);
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-muted);
  flex: 0 0 8.5rem;
}

.seated-event-venue-cell { flex: 1 1 12rem; }
.seated-event-venue-name { font-weight: 700; font-size: var(--step-0); }
.seated-event-venue-location { font-size: var(--step-0); color: var(--text-muted); }
.seated-event-details-cell:empty { display: none; }

.seated-event-link-cells { margin-inline-start: auto; }

/* Seated ships inline styles, so these need the specificity to win. Its
   markup gives every button two class names — .seated-event-link plus
   .seated-event-link1 for the first column — hence both. */
.tour .seated-event-link,
.tour .seated-event-link1 {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--step--1);
  letter-spacing: .18em; text-transform: uppercase;
  padding: .6rem 1.3rem;
  border: 1px solid var(--c-wordmark);
  border-radius: 0;
  background: transparent;
  color: var(--c-wordmark);
  text-decoration: none;
}
.tour .seated-event-link:hover,
.tour .seated-event-link1:hover { background: var(--c-wordmark); color: var(--c-ground); }

/* Seated's own "get notified" capture. Tim's whole point about the mailing
   list is that it is theirs and it is personal — routing fans into a
   ticketing vendor's list instead is the "clunky" ask he asked us to drop.
   The site makes its own invitation, twice. */
.seated-follow-box { display: none !important; }

.tour__empty { color: var(--text-muted); }

/* ------------------------------------------------------------ mailing list
   Tim, 2026-09-04: the list matters more to this band than any platform. It
   gets a block of its own on the plum, not a strip in the footer. */
.signup {
  background: var(--bg-invert);
  color: var(--on-invert);
  padding: clamp(2.5rem, 7vw, 5rem) var(--gutter);
  text-align: center;
}
.signup .eyebrow { color: color-mix(in srgb, var(--c-cream) 65%, var(--c-plum)); }
.signup__inner { max-width: 42rem; margin-inline: auto; }
.signup__star { color: var(--c-cream); margin: 0 auto .9rem; width: .9rem; }
.signup__blurb { margin-block-start: 1rem; color: color-mix(in srgb, var(--c-cream) 80%, var(--c-plum)); }

.signup__form {
  display: flex; flex-wrap: wrap; gap: .6rem; justify-content: center;
  margin-block-start: 1.75rem;
}

.signup__form input {
  flex: 1 1 17rem;
  font: inherit;
  font-size: var(--step--1);
  padding: .72rem .9rem;
  border: 1px solid color-mix(in srgb, var(--c-cream) 45%, var(--c-plum));
  background: transparent;
  color: var(--on-invert);
}
.signup__form input::placeholder { color: color-mix(in srgb, var(--c-cream) 50%, var(--c-plum)); }

.signup .btn { border-color: var(--c-cream); color: var(--c-cream); }
.signup .btn:hover { background: var(--c-cream); color: var(--c-plum); }
.signup .btn--solid { background: var(--c-cream); color: var(--c-plum); }
.signup .btn--solid:hover { background: var(--on-invert); }

/* ----------------------------------------------------------------- modal */
.modal { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; }
.modal[hidden] { display: none; }

.modal__scrim { position: absolute; inset: 0; background: rgba(42, 16, 32, .55); }

.modal__panel {
  position: relative;
  width: min(34rem, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  background: var(--bg-invert);
  color: var(--on-invert);
  padding: clamp(1.75rem, 5vw, 2.75rem);
  text-align: center;
  border: 1px solid color-mix(in srgb, var(--c-cream) 30%, var(--c-plum));
}

.modal__panel .eyebrow { color: color-mix(in srgb, var(--c-cream) 65%, var(--c-plum)); }
.modal__panel .display { margin-block-start: .6rem; }
.modal__blurb { margin-block-start: 1rem; color: color-mix(in srgb, var(--c-cream) 80%, var(--c-plum)); }

.modal__panel .signup__form { margin-block-start: 1.5rem; }
.modal__panel .signup__form input {
  border-color: color-mix(in srgb, var(--c-cream) 45%, var(--c-plum));
  color: var(--on-invert);
}
.modal__panel .btn--solid { background: var(--c-cream); color: var(--c-plum); border-color: var(--c-cream); }
.modal__panel .btn--solid:hover { background: var(--on-invert); }

.modal__x {
  position: absolute; top: .35rem; inset-inline-end: .5rem;
  background: none; border: 0; cursor: pointer;
  color: inherit; font-size: 1.6rem; line-height: 1;
  padding: .35rem .5rem;
}

.modal__decline {
  display: block; margin: 1.1rem auto 0;
  background: none; border: 0; cursor: pointer;
  font: inherit; font-size: var(--step--1);
  color: color-mix(in srgb, var(--c-cream) 60%, var(--c-plum));
  text-decoration: underline; text-underline-offset: .25em;
}
.modal__decline:hover { color: var(--c-cream); }

/* ---------------------------------------------------------------- footer */
.foot {
  border-block-start: 1px solid var(--rule);
  padding-block: clamp(2.5rem, 6vw, 4rem);
  font-size: var(--step--1);
}

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

.foot__brand .wordmark { color: var(--c-wordmark); }
.foot__tag { margin-block-start: .9rem; color: var(--text-muted); max-width: 24ch; }

.foot h2 {
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 400;
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--text-muted);
  margin-block-end: .7rem;
}

.foot ul { display: grid; gap: .4rem; }

/* Contact rows are three lines and no links: role, who, address. The
   address is plain text so it gets copied instead of firing a mail client. */
.foot__contact { gap: 1.1rem; }
.foot__contact > li { display: grid; gap: .1rem; }
.foot__role { color: var(--text-muted); }
.foot__who { display: block; }
.foot__co { color: var(--text-muted); }
.foot__mail { color: var(--text-muted); overflow-wrap: break-word; }
.foot a { text-decoration: none; }
.foot a:hover { text-decoration: underline; }

.foot__base {
  margin-block-start: clamp(2rem, 5vw, 3rem);
  padding-block-start: 1.25rem;
  border-block-start: 1px solid var(--rule);
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  color: var(--text-muted);
}

/* The wormhole — findable, not advertised. */
.foot__wormhole { text-decoration: none; color: var(--rule); font-size: 1.1em; }
.foot__wormhole:hover { color: var(--accent); }

/* ------------------------------------------------------------- art by us
   Tim's watercolours run portrait and landscape both, and they are the
   content — so nothing is cropped. CSS columns lets each keep its own
   shape and still fill the page. */
.art-grid { columns: 3 15rem; column-gap: clamp(.75rem, 2vw, 1.25rem); margin-block-start: 3rem; }
.art-grid img {
  width: 100%; height: auto;
  break-inside: avoid;
  margin-block-end: clamp(.75rem, 2vw, 1.25rem);
}

/* ------------------------------------------------------------------ misc */
.prose { max-width: var(--measure); }
.prose > * + * { margin-block-start: var(--flow); }

/* 580px is Seated's own phone breakpoint. Its stylesheet loads after ours
   and, below that width, turns the row into a column and centres everything.
   Our `flex: 1 1 20rem` on the description block then reads as a 20rem
   *height*, and Seated's space-between drops the button to the bottom — each
   date came out a screen tall. So hold the row direction ourselves, with
   the .tour prefix for specificity, and stack date / venue / button on the
   left like the rest of the site. */
@media (max-width: 36.25rem) {
  .tour .seated-event-row { flex-flow: row wrap; }
  .tour .seated-event-description-cells { text-align: start; }
  .tour .seated-event-venue-cell { align-items: flex-start; }
  .seated-event-date-cell { flex: 0 0 100%; }
  .tour .seated-event-link-cells { margin: 0; }
}

/* ---------------------------------------------------------------- row lists
   A label / detail / figure line. Built for the discography, which is gone;
   the Art By Us price list uses it now. The tour rows are Seated's own
   markup and are styled above. */
.shows { list-style: none; padding: 0; margin: 0; border-block-start: 1px solid var(--rule); }

.show {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem 1.5rem;
  padding-block: 1.15rem;
  border-block-end: 1px solid var(--rule);
}

.show__date {
  font-family: var(--font-cond);
  font-size: var(--step--1);
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-muted);
  flex: 0 0 6rem;
}

.show__date--wide { flex: 0 0 auto; max-width: 100%; }
.show__where { flex: 1 1 14rem; }
.show__city  { font-size: var(--step-0); }
.show__venue { font-size: var(--step--1); color: var(--text-muted); }
.show__cta   { margin-inline-start: auto; }

/* A price is a figure, not a button — it sits where the button would. */
.price { font-size: var(--step-0); color: var(--c-wordmark); }
.price__note {
  margin-block-start: 1.1rem;
  font-size: var(--step--1);
  color: var(--text-muted);
  max-width: 42ch;
}

@media (max-width: 34rem) {
  .show__date { flex: 0 0 100%; }
  .show__cta { margin-inline-start: 0; margin-block-start: .6rem; }
}

/* ------------------------------------------------------ prose and figures */
.wrap--narrow { width: min(46rem, 100% - var(--gutter) * 2); margin-inline: auto; }

.flow > * + * { margin-block-start: var(--flow); }

.figure { margin: 0; }
.figure figcaption {
  margin-block-start: .7rem;
  font-size: var(--step--1);
  color: var(--text-muted);
}

.portrait { width: 100%; height: auto; }

.split {
  display: grid;
  gap: clamp(1.75rem, 5vw, 3.5rem);
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
  align-items: center;
}

/* --------------------------------------------------------- social icons */
.social {
  list-style: none; padding: 0; margin: 0;
  display: flex; gap: 1rem; align-items: center;
}
.social svg { width: 1.15rem; height: 1.15rem; fill: currentColor; }
.social a { color: var(--text-muted); display: block; }
.social a:hover { color: var(--accent); }

/* ------------------------------------------------- featured store tiles
   The curated row shows products, not boxes. Tim, 2026-09-04. The renders are
   cut out against the page ground, so there is deliberately no frame, no
   border and no panel behind them — each product simply sits on the page, the
   way the flower does in the hero. Putting a box back would undo the point of
   cutting them out. */
.goods--featured { grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); }

.good__frame { position: relative; aspect-ratio: 1; }

.goods--featured .good__img {
  width: 100%; height: 100%;
  object-fit: contain;
  background: none;
}

.good__badge {
  position: absolute; inset-block-start: 0; inset-inline-start: 0;
  background: var(--c-wordmark);
  color: var(--c-cream);
  font-size: var(--step--1);
  letter-spacing: .16em; text-transform: uppercase;
  padding: .3rem .6rem;
}

/* ------------------------------------------------------ the anniversary note
   Type is inverted here at Tim's direction: Scala Sans for the header, Bodoni
   for the prose. Everywhere else it is the other way round.

   Bodoni is a didone, so its hairlines thin out badly at body size — this is
   set a step up with looser leading and a shorter measure to carry it. Do not
   drop it to --step-0. */
.note__head {
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 400;
  letter-spacing: .3em;
  text-transform: uppercase;
  text-align: center;
  color: var(--c-violet);
  font-variant-numeric: lining-nums;
  margin-block-end: clamp(2rem, 5vw, 3rem);
}
.note__head sup { font-size: .6em; letter-spacing: .18em; }

/* Portrait beside the prose rather than interrupting it — the note is five
   paragraphs and a full-width image in the middle would cut it in half. The
   photo column is fixed and the text takes the rest, which lands the measure
   around 65 characters at the widest — long, but Bodoni is narrow and the
   leading is loose enough to carry it. Below 52rem it stacks, photo first, so
   it reads as a lead-in. */
.note__grid {
  display: grid;
  grid-template-columns: 22rem minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}

.note__figure { margin: 0; }
.note__figure img { width: 100%; height: auto; }

.note__body {
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.62;
}

@media (max-width: 52rem) {
  .note__grid { grid-template-columns: 1fr; }
  .note__figure { max-width: 22rem; margin-inline: auto; }
}

.note__body > p + p { margin-block-start: 1.1em; }
