/* ============================================================================
   Kreiso /specials — gen-z "hybrid" theme
   ============================================================================
   A route-scoped mirror of design/tokens.json + design/app/ui-kit.html
   ("Brat bones + Patch Kid fun"). Everything lives under `.specials`, so the
   legacy lilac landing theme in app/globals.css is completely untouched.

   WHY A PLAIN CSS FILE IN /public RATHER THAN A TAILWIND @theme OR A CSS MODULE
   The /specials surface is rendered TWO ways and both must look identical:
     1. /specials and /specials/{slug}  → HTML from the mvp_specials Cloud
        Function (so events publish with no rebuild + get per-event OG tags)
     2. /specials/enroll and /thanks    → static Next/React pages
   A Next-bundled stylesheet gets a hashed filename the Python function can't
   link, and Tailwind v4's `@theme` must be top-level (it would leak tokens
   into the global site). One stable-path stylesheet is the only thing both
   surfaces can share — so the design lives here, once.

   CACHE NOTE: edit this file in place and ship it. The filename is NOT
   versioned and must not become versioned. firebase.json serves every other
   *.css with `max-age=31536000, immutable`, which is right for Next's
   content-hashed chunks and wrong for a hand-named file — so this one path has
   its own rule, placed after that glob so it wins:

       "/specials-theme.css"  →  "public, max-age=300"

   A change is therefore live in five minutes, and nothing else needs touching.
   `max-age`, not `no-cache`, on purpose: Firebase Hosting honours If-None-Match
   only on CACHEABLE objects, so `no-cache` here would re-download the whole
   file (~10.9 KB brotli) on every page load of /specials, /links and
   /email-verification, forever. See landing/CLAUDE.md for the measurements.

   RENAMING this file is a CROSS-DEPLOY change: Hosting serves it, but
   specials_html.py only emits the <link>, and the two deploy separately.
   Publish the new name first, repoint second, or every /specials page renders
   unstyled until landing catches up.

   MIRROR CONTRACT: design/tokens.json is canonical (see design/README.md).
   Update this file by hand when tokens change; never import across projects.
   ========================================================================= */

/* Fonts — SELF-HOSTED, deliberately.
   These are the production faces named in tokens.json (Archivo Black stands in
   for "Archivo Expanded Black", Baloo 2 for Clash Display, which isn't on
   Google Fonts). They are served from our own origin rather than @import'ed
   from Google's font CDN for two reasons:

     1. Privacy/legal. Loading them from Google discloses every visitor's IP to
        a third party. This is a German-market site, and the rest of the app
        already self-hosts via next/font — /specials must not be the one page
        that leaks.
     2. Speed. An @import is render-blocking and chains an extra DNS + TLS +
        CSS round trip before a font can even start downloading — and this is
        the paid conversion path.

   Inter, Baloo 2 and JetBrains Mono are VARIABLE fonts, so each is a single
   file per subset spanning its whole weight range rather than one per weight.
   `unicode-range` keeps latin-ext from being fetched at all unless a page
   actually contains those glyphs, so a typical visitor pulls only the latin
   files. Regenerate by re-fetching the Google Fonts css2 API with a browser
   User-Agent and copying the woff2 files into public/fonts/. */

/* Archivo Black — latin-ext */
@font-face {
  font-family: "Archivo Black";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/archivo-black-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Archivo Black — latin */
@font-face {
  font-family: "Archivo Black";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/archivo-black-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Baloo 2 — latin-ext */
@font-face {
  font-family: "Baloo 2";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/fonts/baloo-2-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Baloo 2 — latin */
@font-face {
  font-family: "Baloo 2";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/fonts/baloo-2-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Inter — latin-ext */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Inter — latin */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* JetBrains Mono — latin-ext */
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* JetBrains Mono — latin */
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("/fonts/jetbrains-mono-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

.specials {
  /* ── palette ── */
  --ink: #0e0e0e;
  --ink70: rgba(14, 14, 14, 0.7);
  --ink55: rgba(14, 14, 14, 0.55);
  --ink40: rgba(14, 14, 14, 0.4);
  --ink14: rgba(14, 14, 14, 0.14);
  --ink08: rgba(14, 14, 14, 0.08);
  --lime: #beff0a;
  --lilac: #d8c4ff;
  /* Same colour as --lilac, as a bare triple, so gradient stops can fade it
     out with rgba() without hardcoding the hue. Keep the two in step. */
  --lilac-rgb: 216, 196, 255;
  --lilac2: #c6acff;
  --violet: #46299b;
  --paper: #f4f2ec;
  --cream: #fbf9f2;
  --pink: #ff54a6;
  --cobalt: #2f2ded;
  --err: #d32f2f;

  /* ── type ── */
  --display: "Archivo Black", "Helvetica Neue", Arial, sans-serif;
  --round: "Baloo 2", "Arial Rounded MT Bold", "Helvetica Neue", sans-serif;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* ── radii ── */
  --r-field: 14px;
  --r-btn: 15px;
  --r-card: 18px;
  --r-chip: 11px;

  /* The funnel register: lilac dot-grid. `.specials .sp-payoff` flips to lime. */
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  background-color: var(--lilac);
  background-image: radial-gradient(circle at 1px 1px, rgba(20, 20, 20, 0.13) 1px, transparent 0);
  background-size: 13px 13px;
  min-height: 100dvh;
}

/* Celebration ground — the /thanks payoff screen flips lilac → lime. Applied
   to the page's own section (not the shared layout wrapper) so a single route
   can opt in without the layout having to know which route is rendering.

   The wrapper has to follow, because SpecialsFooter is a sibling AFTER
   {children} in app/specials/layout.tsx: with only the section flipped, the
   lime payoff filled the viewport and scrolling down crossed a hard lime→lilac
   seam before reaching the ink footer — on the one screen designed as the
   celebration, immediately after a card hold succeeds. */
.specials:has(.sp-payoff) {
  background-color: var(--lime);
  background-image: radial-gradient(circle at 1px 1px, rgba(14, 14, 14, 0.16) 1px, transparent 0);
}

.specials .sp-payoff {
  position: relative;
  background-color: var(--lime);
  background-image: radial-gradient(circle at 1px 1px, rgba(14, 14, 14, 0.16) 1px, transparent 0);
  background-size: 13px 13px;
  min-height: 100dvh;
  /* Anchors the corner sunburst and contains it so its tilt can't nudge the
     page into horizontal scroll. */
  overflow: hidden;
}

/* The sunburst seal, pulled OUT of the headline column and slapped into the
   bottom-right corner, tilted off-axis so it reads as hand-placed rather than
   as a centred badge stacked under the h1. Same conic-gradient circle as
   before — just repositioned, rotated, and given the sticker language's hard
   ink shadow. Decorative (the h1/sub carry the message), hence aria-hidden. */
.specials .sp-payoff .sunburst {
  position: absolute;
  right: 22px;
  bottom: 26px;
  width: 108px;
  height: 108px;
  font-size: 13px;
  transform: rotate(-8deg);
  box-shadow: 4px 4px 0 var(--ink);
  pointer-events: none;
}

@media (max-width: 640px) {
  .specials .sp-payoff .sunburst {
    right: 14px;
    bottom: 16px;
    width: 92px;
    height: 92px;
    font-size: 12px;
  }
}

@media (prefers-reduced-motion: no-preference) {
  /* Lands like a stamp being pressed on — scales in, keeping its tilt. */
  .specials .sp-payoff .sunburst {
    animation: sp-stamp-in 440ms cubic-bezier(0.2, 0.9, 0.3, 1.3) both;
  }
  @keyframes sp-stamp-in {
    0% { transform: rotate(-8deg) scale(0.55); opacity: 0; }
    100% { transform: rotate(-8deg) scale(1); opacity: 1; }
  }
}

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

.specials ::selection {
  background: var(--lime);
  color: var(--ink);
}

/* ── layout ─────────────────────────────────────────────────────────────── */

.specials .sp-wrap {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 22px 96px;
}

.specials .sp-wrap.narrow {
  max-width: 620px;
}

/* Page chrome — deliberately NOT the legacy StandaloneNav; this surface owns
   its own header so the two visual systems never sit side by side. */
.specials .sp-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 22px 0 30px;
}

.specials .sp-mark {
  font-family: var(--round);
  font-weight: 800;
  font-size: 21px;
  letter-spacing: -0.02em;
  text-transform: lowercase;
  color: var(--ink);
  text-decoration: none;
}

.specials .sp-back {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--violet);
  text-decoration: none;
}

.specials .sp-back:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.specials .sp-hero {
  position: relative;
  padding-bottom: 34px;
}

.specials .sp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 22px;
}

.specials .sp-detail {
  display: grid;
  grid-template-columns: 1.25fr 0.75fr;
  gap: 26px;
  align-items: start;
}

@media (max-width: 860px) {
  .specials .sp-detail {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .specials .sp-wrap {
    padding: 0 16px 72px;
  }
}

/* ── type ───────────────────────────────────────────────────────────────── */

.specials .eyebrow {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--violet);
  margin: 0;
}

.specials .h1 {
  font-family: var(--display);
  font-weight: 400; /* Archivo Black is a single-weight face */
  letter-spacing: -0.045em;
  text-transform: lowercase;
  line-height: 0.9;
  font-size: clamp(36px, 6.4vw, 68px);
  margin: 12px 0 0;
  text-wrap: balance;
}

.specials .h2 {
  font-family: var(--display);
  font-weight: 400;
  letter-spacing: -0.035em;
  text-transform: lowercase;
  line-height: 0.96;
  font-size: clamp(24px, 3.2vw, 34px);
  margin: 0;
}

.specials .sub {
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink70);
  margin: 14px 0 0;
  max-width: 56ch;
}

/* ── rendered markdown ──────────────────────────────────────────────────────
   `description` and `whatToExpect` come from the Firebase console and are
   written as prose with paragraphs and lists. They used to be escaped into a
   single <p>, which collapsed every blank line — a formatted description
   arrived as one grey wall. `render_markdown` in lib/specials_html.py now
   renders them; these rules give the output the same voice `.sub` had, plus
   the block elements that only exist now.

   Kept tight on purpose: this is event copy, not an article, so headings stay
   close to body size rather than competing with the page's own h1/h2. */
.specials .md {
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink70);
  margin: 14px 0 0;
  max-width: 56ch;
}

.specials .md > *:first-child {
  margin-top: 0;
}

.specials .md > *:last-child {
  margin-bottom: 0;
}

.specials .md p {
  margin: 0 0 12px;
}

.specials .md h1,
.specials .md h2,
.specials .md h3,
.specials .md h4 {
  font-family: var(--round);
  font-weight: 800;
  font-size: 17px;
  line-height: 1.25;
  color: var(--ink);
  margin: 18px 0 8px;
}

.specials .md ul,
.specials .md ol {
  margin: 0 0 12px;
  padding-left: 20px;
}

.specials .md li {
  margin-bottom: 4px;
}

.specials .md strong {
  font-weight: 700;
  color: var(--ink);
}

.specials .md em {
  font-style: italic;
}

.specials .md a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--lilac2);
  text-underline-offset: 2px;
  /* A pasted URL must not push the column wider than the card. */
  overflow-wrap: anywhere;
}

.specials .md a:hover {
  text-decoration-color: var(--ink);
}

.specials .md blockquote {
  margin: 0 0 12px;
  padding: 2px 0 2px 12px;
  border-left: 2.5px solid var(--lilac2);
  color: var(--ink55);
}

.specials .md code {
  font-family: var(--mono);
  font-size: 0.88em;
  background: var(--ink08);
  border-radius: 4px;
  padding: 1px 5px;
}

.specials .md hr {
  height: 1.5px;
  border: 0;
  background: var(--ink14);
  margin: 16px 0;
}

.specials .md img {
  max-width: 100%;
  height: auto;
  border-radius: 10px;
}

.specials .mini {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--ink40);
  margin: 10px 0 0;
}

.specials .chrome {
  font-family: var(--round);
  font-weight: 800;
  letter-spacing: -0.02em;
  background: linear-gradient(180deg, #fff 8%, var(--lilac) 42%, var(--cobalt) 99%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* Kit-exact. `.chrome` is "logo moments only" per the UI kit and is NOT the
     nav or footer wordmark — the nav mark is solid ink, the footer mark solid
     lime. Kept here for the contexts the kit does reserve it for. */
  -webkit-text-stroke: 2px var(--ink);
  paint-order: stroke fill;
}

/* ── buttons ────────────────────────────────────────────────────────────── */

.specials .k-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-family: var(--display);
  font-weight: 400;
  text-transform: lowercase;
  letter-spacing: -0.01em;
  border-radius: var(--r-btn);
  border: 2.5px solid var(--ink);
  color: var(--ink);
  background: var(--cream);
  padding: 13px 24px;
  font-size: 17px;
  text-decoration: none;
  cursor: pointer;
  transition:
    transform 120ms ease,
    box-shadow 120ms ease,
    background-color 160ms ease;
}

.specials .k-btn.primary {
  background: var(--lime);
  box-shadow: 4px 4px 0 var(--ink);
}

.specials .k-btn.secondary {
  background: var(--ink);
  color: var(--cream);
  box-shadow: 4px 4px 0 var(--cobalt);
}

.specials .k-btn.outline {
  background: var(--cream);
  box-shadow: 3px 3px 0 rgba(14, 14, 14, 0.16);
}

.specials .k-btn.lg {
  width: 100%;
  padding: 16px 26px;
  font-size: 19px;
}

.specials .k-btn.sm {
  padding: 9px 16px;
  font-size: 13px;
  border-width: 2px;
  border-radius: 12px;
}

.specials .k-btn.ghost {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
  color: var(--ink55);
  font-family: var(--sans);
  font-weight: 600;
  text-transform: none;
  font-size: 14px;
  letter-spacing: 0;
}

/* The press interaction IS the design language: the offset shadow collapses
   as the surface travels into it. */
.specials .k-btn:active:not(:disabled) {
  transform: translate(2px, 2px);
}

.specials .k-btn.primary:active:not(:disabled) {
  box-shadow: 2px 2px 0 var(--ink);
}

.specials .k-btn.secondary:active:not(:disabled) {
  box-shadow: 2px 2px 0 var(--cobalt);
}

.specials .k-btn:disabled,
.specials .k-btn[aria-disabled="true"] {
  background: var(--ink08);
  color: var(--ink40);
  border-color: transparent;
  box-shadow: none;
  cursor: not-allowed;
}

/* ── fields (React enroll form) ─────────────────────────────────────────── */

.specials .k-label {
  display: block;
  font-family: var(--round);
  font-weight: 800;
  font-size: 14px;
  color: var(--ink);
  margin: 0 0 7px;
}

.specials .k-field {
  width: 100%;
  background: var(--cream);
  border: 2.5px solid var(--ink);
  border-radius: var(--r-field);
  padding: 13px 16px;
  font-family: var(--sans);
  font-size: 16px; /* >=16px stops iOS Safari zooming on focus */
  font-weight: 500;
  color: var(--ink);
  /* No resting shadow — a field is FLAT until focused, exactly as in the ui-kit
     (design/app/ui-kit.html `.k-field` base has no box-shadow; `.k-field.focus`
     adds the lime offset). Carrying a grey shadow at rest made focused and
     unfocused fields nearly indistinguishable; the flat→lime pop is the whole
     signal. */
  outline: none;
  transition: box-shadow 140ms ease;
}

.specials .k-field::placeholder {
  color: var(--ink40);
  font-weight: 500;
}

.specials .k-field:focus {
  box-shadow: 3px 3px 0 var(--lime);
}

.specials .k-field.error {
  border-color: var(--err);
  box-shadow: 3px 3px 0 rgba(211, 47, 47, 0.35);
}

.specials textarea.k-field {
  min-height: 132px;
  resize: vertical;
  line-height: 1.5;
}

.specials select.k-field {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%),
    linear-gradient(135deg, var(--ink) 50%, transparent 50%);
  background-position:
    calc(100% - 19px) calc(50% + 2px),
    calc(100% - 13px) calc(50% + 2px);
  background-size:
    6px 6px,
    6px 6px;
  background-repeat: no-repeat;
  padding-right: 40px;
}

.specials .k-err {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--err);
  margin: 6px 0 0;
}

/* ── invalid state ──────────────────────────────────────────────────────────
   Applied only AFTER a submit attempt, never while typing — flagging a field
   the moment it's focused-and-empty punishes people for filling the form in
   order. `--err` is the canonical status.error from design/tokens.json.

   The keyline carries the signal, matching how the theme already signals focus
   (a coloured 2.5px rule + hard shadow), so it survives on a page where almost
   everything is already outlined in ink. `scroll-margin-top` is what stops the
   programmatic scroll from parking a field flush against the top edge with its
   label cropped off. */
.specials .k-fieldset,
.specials .k-consent {
  scroll-margin-top: 96px;
  scroll-margin-bottom: 96px;
}

.specials .k-field.is-invalid,
.specials .k-phone.is-invalid .PhoneInput {
  border-color: var(--err);
  box-shadow: 3px 3px 0 rgba(211, 47, 47, 0.24);
}

.specials .k-field.is-invalid:focus,
.specials .k-phone.is-invalid .PhoneInput--focus {
  box-shadow: 3px 3px 0 var(--err);
}

.specials .k-consent.is-invalid input[type="checkbox"] {
  border-color: var(--err);
  box-shadow: 2px 2px 0 rgba(211, 47, 47, 0.24);
}

.specials .k-consent.is-invalid > span {
  color: var(--err);
}

.specials .k-hint {
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink55);
  margin: 6px 0 0;
}

.specials .k-fieldset {
  margin: 0 0 18px;
  border: 0;
  padding: 0;
}

/* ── searchable country combobox ────────────────────────────────────────── */

.specials .k-combo {
  position: relative;
}

/* Clear button, shown only once a country is chosen and the popup is closed. */
.specials .k-combo-clear {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ink08);
  color: var(--ink);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}

.specials .k-combo-clear:hover {
  background: var(--lilac2);
}

.specials .k-combo-list {
  position: absolute;
  z-index: 30;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 240px;
  overflow-y: auto;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--cream);
  border: 2.5px solid var(--ink);
  border-radius: var(--r-field);
  box-shadow: 4px 4px 0 rgba(14, 14, 14, 0.2);
}

.specials .k-combo-opt {
  padding: 9px 10px;
  border-radius: var(--r-chip);
  font-size: 14px;
  cursor: pointer;
}

/* `.on` follows the keyboard/hover cursor; `.sel` marks the current value.
   They're separate so arrowing away from your own pick doesn't hide it. */
.specials .k-combo-opt.on {
  background: var(--lilac);
}

.specials .k-combo-opt.sel {
  font-weight: 700;
}

.specials .k-combo-opt.sel::after {
  content: " ✓";
}

.specials .k-combo-empty {
  padding: 12px 10px;
  font-size: 13px;
  color: var(--ink55);
}

/* ── ticket stepper ─────────────────────────────────────────────────────── */

.specials .k-step {
  display: flex;
  align-items: center;
  gap: 10px;
  /* The total chip is nowrap and the controls cost ~142px before it, which
     overflows a 360px viewport on a pricier ticket ("3 × €120.00 = €360.00").
     Wrapping drops the chip to its own line instead of clipping the amount at
     the moment the user decides whether to authorize it. */
  flex-wrap: wrap;
}

.specials .k-step-btn {
  width: 44px; /* 44px min touch target */
  height: 44px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--cream);
  border: 2.5px solid var(--ink);
  border-radius: var(--r-field);
  box-shadow: 3px 3px 0 rgba(14, 14, 14, 0.16);
  font-family: var(--round);
  font-weight: 800;
  font-size: 20px;
  line-height: 1;
  color: var(--ink);
  cursor: pointer;
}

.specials .k-step-btn:active:not(:disabled) {
  transform: translate(2px, 2px);
  box-shadow: 1px 1px 0 rgba(14, 14, 14, 0.16);
}

.specials .k-step-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.specials .k-step-value {
  font-family: var(--round);
  font-weight: 800;
  font-size: 20px;
  min-width: 30px;
  text-align: center;
}

.specials .k-step-total {
  font-family: var(--round);
  font-weight: 800;
  font-size: 14px;
  margin-left: 4px;
  padding: 7px 12px;
  background: var(--lime);
  border: 2.5px solid var(--ink);
  border-radius: var(--r-chip);
  white-space: nowrap;
}

/* ── event-page CTA ─────────────────────────────────────────────────────── */

/* Desktop: sits inline in the aside, under the ticket panel. */
.specials .sp-cta .k-btn {
  width: 100%;
}

@media (max-width: 1024px) {
  /* Phones: the aside stacks below a tall hero and description, so the buy
     button ends up far below the fold — it has to follow the reader instead.
     `--kreiso-consent-h` keeps it above the cookie bar and collapses to 0px
     once a choice is made, so the button then sits on the screen edge. */
  .specials .sp-cta {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    padding: 12px 18px calc(14px + env(safe-area-inset-bottom, 0px) + var(--kreiso-consent-h, 0px));
    /* Fade the dot-grid out behind it rather than a hard band edge. All three
       stops are the SAME hue as the ground — mixing in --lilac2 (as the
       hardcoded triples here used to) rendered the fade as a visibly more
       saturated stripe instead of a fade. */
    background: linear-gradient(
      to top,
      var(--lilac) 62%,
      rgba(var(--lilac-rgb), 0.92) 82%,
      rgba(var(--lilac-rgb), 0)
    );
  }

  .specials .sp-cta .k-btn {
    max-width: 520px;
    margin: 0 auto;
  }
}

/* Ported 1:1 from `.foot` in design/landing/ui-kit.html ("footer — all pages",
   legend: ink = footer). Deliberately plain: an ink panel, a solid lime
   wordmark, plain text links. No keylines, no chips, no hard shadows — the
   legal links are not calls to action and shouldn't carry button weight. */
.specials .sp-foot {
  max-width: 1080px;
  /* The bottom pad clears the cookie bar. `--kreiso-consent-h` is published by
     consent.vN.js and collapses to 0px once a choice is made, so this isn't a
     permanent guess at a height that varies with line wrapping. */
  margin: 72px auto 0;
  padding: 0 22px calc(24px + var(--kreiso-consent-h, 0px));
}

.specials .sp-foot__panel {
  background: var(--ink);
  color: var(--cream);
  border-radius: var(--r-card);
  padding: 24px;
}

/* Solid lime, NOT `.chrome`. The kit is explicit: on the ink footer the chrome
   keyline would vanish, so the wordmark goes solid. */
.specials .sp-foot__mark {
  display: inline-block;
  font-family: var(--round);
  font-weight: 800;
  font-size: 26px;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--lime);
  text-transform: lowercase;
  text-decoration: none;
}

.specials .sp-foot__links {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 14px;
  font-size: 13px;
}

.specials .sp-foot__links a,
.specials .sp-foot__links button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: rgba(251, 249, 242, 0.72);
  text-decoration: none;
  cursor: pointer;
  transition: color 120ms ease;
}

.specials .sp-foot__links a:hover,
.specials .sp-foot__links button:hover {
  color: var(--lime);
}

/* Lime, not the theme's --violet: #46299b on an ink panel is invisible. */
.specials .sp-foot__links a:focus-visible,
.specials .sp-foot__links button:focus-visible,
.specials .sp-foot__social a:focus-visible,
.specials .sp-foot__mark:focus-visible {
  outline: 2px solid var(--lime);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Social gets the chip treatment the legal links don't — these ARE actions. */
.specials .sp-foot__social {
  display: flex;
  gap: 10px;
  margin-top: 18px;
}

.specials .sp-foot__social a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1.5px solid rgba(251, 249, 242, 0.22);
  border-radius: 50%;
  color: rgba(251, 249, 242, 0.72);
  transition: color 120ms ease, border-color 120ms ease, background-color 120ms ease;
}

.specials .sp-foot__social a:hover {
  color: var(--ink);
  background: var(--lime);
  border-color: var(--lime);
}

.specials .sp-foot__fine {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(251, 249, 242, 0.45);
  margin: 18px 0 0;
}

/* MUST come after the `.sp-foot` shorthand above — a `padding-bottom` declared
   before it loses to the shorthand at equal specificity, which silently left
   the fine print sitting under the fixed CTA.
   The CTA's own padding already includes `--kreiso-consent-h`, so its height
   grows with the cookie bar; add the var here too so the clearance tracks it.

   Scoped to pages that actually HAVE the fixed CTA. `.sp-cta` is emitted only
   by render_detail_page's not-sold-out branch, but `.sp-foot` is on every
   specials surface — so unscoped this reserved a thumb's height of bare
   dot-grid under the footer on the catalog, sold-out detail pages, /enroll,
   /thanks and the 404. */
@media (max-width: 1024px) {
  .specials:has(.sp-cta) .sp-foot {
    padding-bottom: calc(112px + var(--kreiso-consent-h, 0px));
  }
}

/* ── option chips (multi-select) ─────────────────────────────────────────────
   For the life-stage picker: a small set of short labels where seeing all the
   options at once beats a dropdown, and where more than one can be true. Built
   on real <input type="checkbox"> + <label> so it stays keyboard-operable and
   announced; the input is visually hidden, not `display:none` (which would
   remove it from the tab order and the a11y tree).

   Selected uses LIME rather than ink so a chosen chip reads as "on" at a
   glance across a row — the same signal `.k-patch.on` carries in the SoT. */
.specials .k-opts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.specials .k-opt {
  position: relative;
  display: inline-flex;
}

.specials .k-opt input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  margin: 0;
  pointer-events: none;
}

.specials .k-opt span {
  display: inline-flex;
  align-items: center;
  font-family: var(--round);
  font-weight: 800;
  font-size: 13px;
  padding: 9px 13px;
  border: 2px solid var(--ink);
  border-radius: var(--r-chip);
  background: var(--cream);
  color: var(--ink);
  cursor: pointer;
  user-select: none;
  transition: background-color 120ms ease, box-shadow 120ms ease, transform 120ms ease;
}

.specials .k-opt input:checked + span {
  background: var(--lime);
  box-shadow: 2px 2px 0 var(--ink);
}

/* Keyboard focus has to be visible on the LABEL, since the input it belongs
   to is the hidden element. */
.specials .k-opt input:focus-visible + span {
  outline: 2px solid var(--cobalt);
  outline-offset: 2px;
}

.specials .k-opt input:disabled + span {
  opacity: 0.4;
  cursor: not-allowed;
}

.specials .k-opt input:active:not(:disabled) + span {
  transform: translate(1px, 1px);
}

.specials .k-opts.is-invalid .k-opt span {
  border-color: var(--err);
}

@media (prefers-reduced-motion: reduce) {
  .specials .k-opt span {
    transition: none;
  }
}

/* ── consent row ────────────────────────────────────────────────────────── */

.specials .k-consent {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  /* The gap below is deliberate and generous. This checkbox and the pay button
     are the two controls that decide whether a card gets authorized, and on a
     phone they sit within a thumb's width of each other at the bottom of a long
     form — close enough that reaching for "accept the terms" risks landing on
     "pay". Separating them is a mis-tap guard, not styling. Widened further at
     the mobile breakpoint below. */
  margin: 22px 0 26px;
  font-size: 13px;
  line-height: 1.5;
  cursor: pointer;
}

/* Also applies when the seats/submit error sits between them. */
.specials .k-consent + .k-btn,
.specials .k-consent + .k-err + .k-btn {
  margin-top: 4px;
}

@media (max-width: 640px) {
  .specials .k-consent {
    margin-bottom: 34px;
  }

  .specials .k-consent + .k-btn,
  .specials .k-consent + .k-err + .k-btn {
    margin-top: 8px;
  }
}

/* Still a real <input type="checkbox"> — focusable, announced, form-associated
   — just repainted to carry the theme's keyline, which `accent-color` alone
   can't do (it only fills). The tick is a background SVG rather than a
   pseudo-element because Firefox won't render ::before/::after on inputs. */
.specials .k-consent input[type="checkbox"] {
  flex: 0 0 auto;
  appearance: none;
  -webkit-appearance: none;
  width: 20px;
  height: 20px;
  margin: 0;
  background: var(--cream);
  border: 2.5px solid var(--ink);
  border-radius: 6px;
  box-shadow: 2px 2px 0 rgba(14, 14, 14, 0.16);
  cursor: pointer;
}

.specials .k-consent input[type="checkbox"]:checked {
  background-color: var(--ink);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fbf9f2' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 13px 13px;
}

.specials .k-consent input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
}

.specials .k-consent a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.specials .k-consent a:hover {
  color: var(--violet);
}

/* ── chips / patches ────────────────────────────────────────────────────── */

.specials .k-patch {
  font-family: var(--round);
  font-weight: 800;
  font-size: 12.5px;
  padding: 8px 11px;
  border: 2px solid var(--ink);
  border-radius: var(--r-chip);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--cream);
  color: var(--ink);
  white-space: nowrap;
}

.specials .k-patch.on {
  background: var(--lime);
  box-shadow: 2px 2px 0 var(--ink);
}

.specials .k-patch.lil {
  background: var(--lilac2);
}

.specials .k-patch.pk {
  background: var(--pink);
  color: #fff;
}

.specials .k-patch.price {
  background: var(--lime);
  box-shadow: 2px 2px 0 var(--ink);
  font-size: 14px;
}

.specials .k-patches {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* ── event card ─────────────────────────────────────────────────────────── */

.specials .k-card {
  position: relative;
  border: 2.5px solid var(--ink);
  border-radius: var(--r-card);
  overflow: hidden;
  box-shadow: 3px 3px 0 rgba(14, 14, 14, 0.18);
  background: var(--cream);
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: var(--ink);
  transition:
    transform 160ms ease,
    box-shadow 160ms ease;
}

.specials a.k-card:hover {
  transform: translate(-2px, -2px);
  box-shadow: 6px 6px 0 rgba(14, 14, 14, 0.22);
}

.specials .k-card .img {
  /* Square. `aspect-ratio` sizes the photo off the card/column width, so the
     same rule keeps the catalog card AND the detail hero square at every width
     — the detail hero used to be a fixed 300px, which read square on a narrow
     phone but very landscape in the wide desktop column. */
  aspect-ratio: 1 / 1;
  background: var(--lilac2) center / cover no-repeat;
  border-bottom: 2.5px solid var(--ink);
  position: relative;
}

/* Detail hero only: cap the square on desktop. A full-column 1:1 in the wide
   detail layout is a huge block; the catalog cards stay full-width-square
   because the grid already keeps them ~300px. */
@media (min-width: 861px) {
  .specials .sp-media {
    max-width: 380px;
  }
}

/* Rotated "when" tag — hand-placed feel, straight from the ui-kit. */
.specials .k-card .when,
.specials .when {
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  background: var(--lime);
  color: var(--ink);
  border: 2px solid var(--ink);
  padding: 5px 8px;
  border-radius: 6px;
  transform: rotate(-2deg);
  display: inline-block;
}

.specials .k-card .when {
  position: absolute;
  right: 10px;
  bottom: 10px;
}

.specials .k-card .bd {
  padding: 14px 15px 15px;
  display: flex;
  flex-direction: column;
  flex: 1;
}

.specials .k-card h3 {
  font-family: var(--display);
  font-weight: 400;
  font-size: 22px;
  letter-spacing: -0.03em;
  text-transform: lowercase;
  margin: 0;
  line-height: 1;
}

.specials .k-card .d {
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink70);
  margin: 7px 0 0;
}

.specials .k-card .tags {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 12px;
  /* A flex item's default `min-width: auto` refuses to shrink below its
     content, so a chip holding a long location pushed the row — and with it
     the card — past its own border. This is the belt to the braces of
     truncating the label server-side. */
  min-width: 0;
}

/* Location — the design SoT's quiet meta slot (`.join`, 11px @ 75%), NOT a
   patch. Patches are taxonomy: single words, `white-space: nowrap`, which is
   what makes a chip legible as a chip. An admin-typed location is prose and
   can run to a full sentence, so in a pill it either burst the card or got
   cropped mid-word — and the crop ate the one fact the reader wanted.

   Clamped to two lines rather than cut at a character count, so it always
   breaks at a word boundary and the browser places the ellipsis. The complete
   text is on the detail page. */
.specials .k-card .where {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  /* Bound to the teaser above it — location is part of the descriptive block,
     not a third thing. The air before the foot does the separating instead of
     a rule; a hairline across a sticker card reads as a receipt, not a patch. */
  margin: 10px 0 0;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.01em;
  line-height: 1.5;
  color: var(--ink55);
  min-width: 0;
}

.specials .k-card .where .pin {
  flex: 0 0 auto;
  font-size: 9.5px;
  line-height: 1.65;
}

.specials .k-card .where > span:last-child {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-width: 0;
}

/* The sticker language's own idiom for "this is pressable": the hard offset
   shadow deepens and the card lifts into it. */
.specials .k-card {
  transition: transform 140ms ease, box-shadow 140ms ease;
}

.specials .k-card:hover {
  transform: translate(-2px, -2px);
  box-shadow: 6px 6px 0 rgba(14, 14, 14, 0.2);
}

/* The button in the foot is a <span> — the card is the anchor — so `:active`
   never fires on it and it would be the one dead-looking element on a card
   that otherwise presses. Drive it from the card instead, so tapping anywhere
   collapses the button's offset shadow exactly as pressing a real one does. */
.specials .k-card .k-btn {
  transition: transform 140ms ease, box-shadow 140ms ease;
}

.specials .k-card:active .k-btn.secondary {
  transform: translate(2px, 2px);
  box-shadow: 2px 2px 0 var(--cobalt);
}

.specials .k-card.soldout:hover {
  transform: none;
  box-shadow: 3px 3px 0 rgba(14, 14, 14, 0.18);
}


@media (prefers-reduced-motion: reduce) {
  .specials .k-card,
  .specials .k-card:hover {
    transform: none;
  }
}

/* No rule above the foot. The SoT card has one, but its foot is a dense row of
   stacked avatars + a count + a status chip, where a line stops the two halves
   merging. Ours is two solid objects — a lime pill and an ink button — that
   already separate themselves by weight, and a hairline between them read as a
   receipt tear rather than part of the sticker language. Space does the work:
   a bigger gap above the foot than between title/teaser/location groups the
   copy as one block and the transaction as another. */
.specials .k-card .cfoot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: auto;
  padding-top: 18px;
}

.specials .k-card.soldout .img::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(251, 249, 242, 0.62);
}

/* ── torn-paper note (the payment explainer) ────────────────────────────── */

.specials .torn {
  background: var(--cream);
  border: 2.5px solid var(--ink);
  box-shadow: 3px 3px 0 var(--ink);
  border-radius: 13px;
  padding: 16px 17px;
}

.specials .torn .lbl {
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cobalt);
  margin: 0;
}

.specials .torn p {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink70);
  margin: 8px 0 0;
}

.specials .torn p + p {
  margin-top: 7px;
}

/* ── info rows (detail meta) ────────────────────────────────────────────── */

.specials .k-rowcard {
  background: var(--cream);
  border: 2.5px solid var(--ink);
  border-radius: 16px;
  overflow: hidden;
}

/* `flex-start`, not `center`: a long "where" wraps to two or three lines, and
   centring parked the label and the icon halfway down the block, level with
   nothing. Aligning to the top edge lines the label up with the FIRST line of
   its value, which is what reads as aligned. Single-line rows are unaffected
   because `min-height` + padding still centre them optically. */
.specials .k-row {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 13px 15px;
  min-height: 54px;
  font-size: 14.5px;
  color: var(--ink);
}

.specials .k-row .ic {
  width: 22px;
  text-align: center;
  font-size: 15px;
  opacity: 0.55;
}

/* The label takes only what it needs and never shrinks; the VALUE gets the
   remaining width. Previously the label was `flex: 1`, so it claimed all the
   free space and squeezed a long address into a narrow ragged column on the
   right. */
.specials .k-row .grow {
  flex: 0 0 auto;
  font-weight: 500;
}

.specials .k-row .val {
  flex: 1;
  min-width: 0;
  color: var(--ink55);
  font-size: 13px;
  text-align: right;
  /* An admin can type a single unbroken string (a URL, a long street name);
     without this it would push the row wider than the card. */
  overflow-wrap: anywhere;
}

.specials .k-div {
  height: 1.5px;
  background: var(--ink08);
  margin-left: 48px;
}

/* ── fun layer: tape, halftone, sunburst, Boris ─────────────────────────── */

.specials .htc {
  position: absolute;
  width: 130px;
  height: 130px;
  pointer-events: none;
  z-index: 0;
  background: radial-gradient(circle at 2px 2px, rgba(47, 45, 237, 0.5) 2px, transparent 0);
  background-size: 9px 9px;
  opacity: 0.28;
}

.specials .tape {
  position: absolute;
  width: 62px;
  height: 21px;
  background: rgba(196, 255, 61, 0.8);
  border: 1px dashed rgba(20, 20, 20, 0.4);
  z-index: 6;
}

.specials .sunburst {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: var(--ink);
  font-family: var(--round);
  font-weight: 800;
  line-height: 1.04;
  background: conic-gradient(
    from 0deg,
    var(--lime) 0 10%,
    var(--cream) 10% 20%,
    var(--lime) 20% 30%,
    var(--cream) 30% 40%,
    var(--lime) 40% 50%,
    var(--cream) 50% 60%,
    var(--lime) 60% 70%,
    var(--cream) 70% 80%,
    var(--lime) 80% 90%,
    var(--cream) 90% 100%
  );
  border-radius: 50%;
  border: 2.5px solid var(--ink);
}

.specials .sunburst.pink {
  background: conic-gradient(
    from 0deg,
    var(--pink) 0 10%,
    var(--cream) 10% 20%,
    var(--pink) 20% 30%,
    var(--cream) 30% 40%,
    var(--pink) 40% 50%,
    var(--cream) 50% 60%,
    var(--pink) 60% 70%,
    var(--cream) 70% 80%,
    var(--pink) 80% 90%,
    var(--cream) 90% 100%
  );
}

/* Die-cut Boris — the white keyline is four stacked drop-shadows, then one
   hard ink shadow, exactly as specced in the ui-kit. */
.specials .boris {
  width: 96px;
  height: 96px;
  flex: 0 0 auto;
  background: url("/boris-256.png") center / contain no-repeat;
  filter: drop-shadow(2px 0 0 #fff) drop-shadow(-2px 0 0 #fff) drop-shadow(0 2px 0 #fff)
    drop-shadow(0 -2px 0 #fff) drop-shadow(2px 3px 0 rgba(14, 14, 14, 0.8));
}

.specials .boris.sm {
  width: 62px;
  height: 62px;
}

.specials .k-bubble {
  position: relative;
  background: #fff;
  border: 2px solid var(--ink);
  border-radius: 12px;
  padding: 10px 12px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.4;
  box-shadow: 2px 2px 0 var(--ink);
}

.specials .k-bubble b {
  color: var(--violet);
}

.specials .boris-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 26px;
}

/* ── states ─────────────────────────────────────────────────────────────── */

.specials .k-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  padding: 48px 0;
}

.specials .k-empty .ic {
  width: 84px;
  height: 84px;
  border-radius: 50%;
  background: var(--cream);
  border: 2.5px solid var(--ink);
  box-shadow: 3px 3px 0 var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 32px;
}

.specials .k-spin {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 4px solid var(--ink14);
  border-top-color: var(--cobalt);
  animation: sp-spin 1s linear infinite;
  margin: 48px auto;
}

@keyframes sp-spin {
  to {
    transform: rotate(1turn);
  }
}

@media (prefers-reduced-motion: reduce) {
  .specials .k-spin {
    animation: none;
  }
  .specials .k-btn,
  .specials .k-card {
    transition: none;
  }
}

/* ── react-phone-number-input, dressed as a .k-field ────────────────────── */

.specials .k-phone .PhoneInput {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--cream);
  border: 2.5px solid var(--ink);
  border-radius: var(--r-field);
  padding: 11px 16px;
  /* Flat at rest, lime on focus — same as .k-field, so the phone field reads as
     part of the same set instead of the one control that's always shadowed. */
  transition: box-shadow 140ms ease;
}

.specials .k-phone .PhoneInput--focus {
  box-shadow: 3px 3px 0 var(--lime);
}

.specials .k-phone .PhoneInputInput {
  flex: 1;
  border: 0;
  outline: none;
  background: transparent;
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 500;
  color: var(--ink);
}

.specials .k-phone .PhoneInputInput::placeholder {
  color: var(--ink40);
}

.specials .k-phone .PhoneInputCountrySelectArrow {
  color: var(--ink);
  opacity: 0.6;
}
