/**
 * Newsletter banner: rounded card, headline + reasons on the left, email
 * capture on the right. Stacks to a single column below 750px.
 *
 * The card's palette is a handful of local custom properties (--nl-*)
 * rather than hard-coded colours; they track the section-frame's
 * --color-bg/--color-ink, so the card reads correctly whichever of the
 * theme's colour schemes the merchant assigns to this section, with no
 * per-scheme modifier class to keep in step.
 */
.newsletter {
  /* The card's ground now comes straight from the section-frame's colour
     scheme rather than a hand-rolled dark/brand/light switch - --nl-surface
     and --nl-ink track --color-bg/--color-ink, so the card reads correctly
     in whichever of the theme's colour schemes the merchant picks. */
  --nl-surface: var(--color-bg);
  --nl-ink: var(--color-ink);
  --nl-muted: color-mix(in srgb, var(--color-ink) 70%, transparent);
  --nl-faint: color-mix(in srgb, var(--color-ink) 50%, transparent);
  --nl-field-bg: color-mix(in srgb, var(--color-ink) 6%, transparent);
  --nl-field-border: color-mix(in srgb, var(--color-ink) 20%, transparent);
  --nl-btn-bg: var(--color-ink);
  --nl-btn-ink: var(--color-bg);
  --nl-accent: color-mix(in oklab, var(--color-brand) 35%, var(--color-ink));
  /* What sweeps in on hover, what the label becomes once covered, and the
     hairline drawn inside the swept layer. Hover inverts rather than going
     purple, and here the inversion needs no colours of its own at all: the
     fill IS the button's resting ink and the label IS its resting background,
     swapped. That makes it correct in every colour scheme by construction -
     on a dark-ground scheme the button is bg-coloured on an ink-coloured
     card, so inverting it paints an ink-coloured button on an ink-coloured
     card; on a light-ground scheme an ink button on a pale card needs no
     help either way. The hairline is the button's own resting edge colour,
     revealed by the same clip-path as the fill. The timings are :root's
     --btn-fill-*. */
  --nl-btn-fill: var(--nl-btn-ink);
  --nl-btn-fill-ink: var(--nl-btn-bg);
  --nl-btn-fill-edge: var(--nl-btn-bg);
}

/* The frame element itself stays unpainted. A scheme on this section colours
   the rounded card, not the band: at a2b24bf the outer element carried no
   background at all and the only dark thing on the page was
   .newsletter__card, floating on the page's white with its --radius-m
   corners reading against it. The generated .color-<id> rule paints
   background-color/color at single-class specificity, so this two-class
   selector beats it wherever it sits in the document; the rule's local
   --color-bg/--color-ink redefinitions survive, which is exactly what
   --nl-surface/--nl-ink read to paint the card. */
.newsletter.section-frame {
  background-color: transparent;
  color: inherit;
}

.newsletter__card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-7) var(--space-8);
  border-radius: var(--radius-m);
  background-color: var(--nl-surface);
  color: var(--nl-ink);
}

.newsletter__copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: 560px;
}

.newsletter__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-heading);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--nl-accent);
}

/* The drop list is a live feed, and the dot says so - the same breathing
   grammar as the roadmap's in-progress marker, because both mean "this is
   the thing that updates". */
.newsletter__eyebrow-dot {
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background-color: var(--nl-accent);
}

@media (prefers-reduced-motion: no-preference) {
  .newsletter__eyebrow-dot {
    animation: newsletter-signal 2.6s ease-in-out infinite;
  }

  @keyframes newsletter-signal {
    0%,
    100% {
      opacity: 1;
    }
    50% {
      opacity: 0.4;
    }
  }
}

.newsletter__heading {
  margin: 0;
}

.newsletter__text {
  color: var(--nl-muted);
}

/* ------------------------------------------------------------------ */
/* Reasons to subscribe                                                */
/* ------------------------------------------------------------------ */
/* Not a bullet list: a manifest. Each reason is a hairline-ruled ledger row
   led by an index numeral in the heading face, with the merchant's icon
   closing the line as a quiet glyph. The old icon-in-a-disc treatment made
   three identical badges compete; a numbered ledger says "here is exactly
   what you will be told about, in order" - which is the promise being made. */
.newsletter__reasons {
  display: flex;
  flex-direction: column;
  margin-top: var(--space-2);
}

.newsletter__reason {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-block: var(--space-3);
  border-top: 1px solid var(--nl-field-border);
  font-size: 14px;
  color: var(--nl-muted);
}

.newsletter__reason:last-child {
  border-bottom: 1px solid var(--nl-field-border);
}

.newsletter__reason-num {
  flex: 0 0 auto;
  font-family: var(--font-heading);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
  color: var(--nl-accent);
}

.newsletter__reason-text {
  min-width: 0;
}

.newsletter__reason-icon {
  display: inline-flex;
  flex: 0 0 auto;
  margin-left: auto;
  color: var(--nl-faint);
}

/* ------------------------------------------------------------------ */
/* Form                                                                */
/* ------------------------------------------------------------------ */
/* 400px could not hold a real email address next to a Subscribe button - the
   field clipped mid-address, which looks broken at exactly the moment you are
   asking for someone's details. Sized to fit a long address instead, and
   allowed to grow into the space the copy column leaves. */
.newsletter__form-wrapper {
  flex: 1 1 420px;
  width: 100%;
  max-width: 560px;
}

.newsletter__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* Input and submit share one pill: the border lives on the wrapper so the
   focus ring can wrap both, and the button can never be pushed onto its own
   line at an awkward width. */
.newsletter__field {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1);
  border-radius: var(--radius-pill);
  background-color: var(--nl-field-bg);
  border: 1px solid var(--nl-field-border);
}

/* The machined moment: when the field takes focus the whole pill responds -
   border sharpens to full ink and a soft ring blooms around input and button
   together, because they are one control, not two. */
.newsletter__field:focus-within {
  border-color: var(--nl-ink);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--nl-ink) 18%, transparent);
}

@media (prefers-reduced-motion: no-preference) {
  .newsletter__field {
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
  }
}

.newsletter__input {
  flex: 1 1 auto;
  min-width: 0;
  height: 48px;
  padding-inline: var(--space-4);
  border: none;
  background: none;
  color: var(--nl-ink);
  font-family: var(--font-body);
  /* 16px minimum: anything smaller makes iOS Safari zoom the page on focus. */
  font-size: 16px;
}

.newsletter__input:focus {
  outline: none;
}

.newsletter__input::placeholder {
  color: var(--nl-faint);
}

/* Chrome paints autofilled fields with its own pale background and near-black
   text, ignoring `background: none` - which on this dark panel produced a
   lavender box with unreadable text the moment a saved address was filled in.
   The background cannot be overridden directly, so it is covered with an inset
   shadow, and the text colour needs the -webkit-text-fill-color property
   rather than `color`. The absurd transition delay is the standard trick for
   the brief flash Chrome paints before the shadow applies. */
.newsletter__input:-webkit-autofill,
.newsletter__input:-webkit-autofill:hover,
.newsletter__input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--nl-ink);
  -webkit-box-shadow: inset 0 0 0 100px var(--nl-field-bg);
  caret-color: var(--nl-ink);
  transition: background-color 100000s ease-in-out 0s;
}

/* Deliberately not a .btn, though it is the site's other primary submit.
   .btn is 56px tall on --radius-m with the ink/brand palette baked in; this
   one is 48px on --radius-pill in whichever of the three panel schemes the
   merchant picked, and it shares a rounded container with the input, which is
   padded to exactly one 48px control. Wearing .btn would mean overriding its
   height, radius, background, colour and border before adding the scheme
   tokens back - a parallel implementation either way. So it keeps its own box
   and borrows the shared MECHANISM below instead: same ::before, same :root
   timings, so retuning --btn-fill-* reaches it. */
.newsletter__submit {
  flex: 0 0 auto;
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 48px;
  padding-inline: var(--space-5);
  border-radius: var(--radius-pill);
  background-color: var(--nl-btn-bg);
  color: var(--nl-btn-ink);
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

/* z-index MUST be negative, not 0: positioned boxes at z-index 0/auto paint
   above inline content, and this button's label is a bare text node, so a 0
   here would sweep the fill straight over the word. See the same note on
   .btn in base.css. */
.newsletter__submit::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background-color: var(--nl-btn-fill);
  /* On the swept layer, not on the button: the clip-path cuts the ring as
     well as the interior, so the outline is drawn in exactly as far as the
     fill has reached and there is no second transition to keep in step. */
  box-shadow: inset 0 0 0 1px var(--nl-btn-fill-edge);
  clip-path: circle(0% at var(--fill-x, 50%) var(--fill-y, 50%));
  pointer-events: none;
}

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

/* Full coverage: circle() percentages resolve against sqrt((w²+h²)/2), so
   150% reaches the farthest corner from any origin point. */
html.has-cursor-fill .newsletter__submit.is-hover-fill::before {
  clip-path: circle(150% at var(--fill-x, 50%) var(--fill-y, 50%));
}

/* Entry slower than exit, on the shared tokens: the sweep is meant to be
   watched, un-sweeping stays quick. The transition that runs is whichever
   rule matches the DESTINATION state, so removing .is-hover-fill falls back
   to the quicker one. */
@media (prefers-reduced-motion: no-preference) {
  .newsletter__submit::before {
    transition: clip-path var(--btn-fill-out) var(--btn-fill-out-ease);
  }

  html.has-cursor-fill .newsletter__submit.is-hover-fill::before {
    transition: clip-path var(--btn-fill-in) var(--btn-fill-in-ease);
  }
}

/* The label has to invert or it sits ink-on-ink once the fill covers it, and
   it must do so on the fill's own duration AND easing in both directions -
   duration alone still desyncs, because the fill's exit is ease-in (barely
   moves, then accelerates) while a default curve is already well underway. */
html.has-cursor-fill .newsletter__submit:hover {
  color: var(--nl-btn-fill-ink);
}

@media (prefers-reduced-motion: no-preference) {
  .newsletter__submit {
    transition: opacity 0.15s ease, color 0.15s ease;
  }

  html.has-cursor-fill .newsletter__submit {
    transition-duration: var(--btn-fill-out);
    transition-timing-function: var(--btn-fill-out-ease);
  }

  html.has-cursor-fill .newsletter__submit:hover {
    transition-duration: var(--btn-fill-in);
    transition-timing-function: var(--btn-fill-in-ease);
  }
}

/* Without JS driving the sweep (touch, reduced motion, or before motion.js
   runs) the button still needs a hover state, so the previous dim stays as
   the fallback. Scoped to :not(.has-cursor-fill) so it cannot dim the button
   ahead of the sweep. */
html:not(.has-cursor-fill) .newsletter__submit:hover {
  opacity: 0.85;
}

.newsletter__reassurance {
  color: var(--nl-faint);
}

/* ------------------------------------------------------------------ */
/* Posted states                                                       */
/* ------------------------------------------------------------------ */
.newsletter__message {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-m);
  font-size: 14px;
  text-align: left;
}

.newsletter__message svg {
  flex-shrink: 0;
  margin-top: 2px;
}

.newsletter__message--success {
  background-color: color-mix(in oklab, var(--color-success) 18%, transparent);
  border: 1px solid color-mix(in oklab, var(--color-success) 55%, transparent);
  color: var(--nl-ink);
}

/* The danger token is a mid-red: legible standalone on a light ground, but
   too dark against a dark one, so the text is mixed toward the card's own
   --nl-ink rather than pinned to either extreme - this adapts automatically
   whichever colour scheme the section carries, and the panel tint below
   stays pure danger. */
.newsletter__message--error {
  background-color: color-mix(in oklab, var(--color-danger) 18%, transparent);
  border: 1px solid color-mix(in oklab, var(--color-danger) 55%, transparent);
  color: color-mix(in oklab, var(--color-danger) 30%, var(--nl-ink));
}

.newsletter__error-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

@media screen and (max-width: 749px) {
  .newsletter__card {
    flex-direction: column;
    align-items: stretch;
    padding: var(--space-6) var(--space-5);
  }

  .newsletter__copy {
    max-width: none;
  }

  .newsletter__form-wrapper {
    max-width: none;
  }

  /* At the narrowest widths an inline submit leaves the input too short to
     show a whole email address, so the pill unwraps into two stacked
     controls rather than shrinking further. */
  .newsletter__field {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
    padding: var(--space-2);
    border-radius: var(--radius-m);
  }

  .newsletter__submit {
    width: 100%;
  }
}


/* Interests: what to be told about, as chips above the email field. A
   chosen chip adds a customer tag on submit. */
.newsletter__interests {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-3);
  padding: 0;
  border: 0;
}

.newsletter__interests-legend {
  width: 100%;
  margin-bottom: var(--space-2);
  padding: 0;
  color: var(--color-muted);
}

.newsletter__interest { position: relative; }
.newsletter__interest input { position: absolute; inset: 0; opacity: 0; }

.newsletter__interest span {
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 0 var(--space-3);
  border: 1px solid var(--color-line);
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease;
}

.newsletter__interest input:checked + span {
  border-color: var(--color-brand);
  background-color: color-mix(in srgb, var(--color-brand) 14%, transparent);
}

.newsletter__interest input:focus-visible + span {
  outline: 2px solid var(--color-brand);
  outline-offset: 2px;
}

/* Phones: the section's bottom padding plus the footer's own top padding
   stacked into a tall empty band under the card. The footer's spacing is
   enough on its own. */
@media screen and (max-width: 749px) {
  .newsletter.section-frame {
    padding-bottom: 0;
  }
}
