/* ==========================================================================
   SVEF — components  ·  THRESHOLD

   Every class name here survives from the previous design, so all fifteen
   public pages keep their markup and inherit the new one. What changed is
   what the names resolve to: a light page of white cards and navy fills
   became a dark sequence of rooms separated by hairlines.

   Two rules run through the whole file:
     - Structure is carried by hairlines and space, never by shadow or
       radius. Nothing is raised and nothing is rounded.
     - There is one accent. Champagne appears on the thing being offered
       and almost nowhere else.
   ========================================================================== */

/* =========================================================== 1 · TYPE ==== */

/* The eyebrow. Every label, kicker and small caps in the site is this. */
.eyebrow {
  display: block;
  font-family: var(--font-body);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--champagne);
  margin-bottom: var(--space-4);
}
.eyebrow-muted { color: var(--smoke-2); }

/* Section titles are the one place the serif is spent, and it is set light
   and large so the contrast against the wide caps around it is the point. */
.section-title {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: var(--fs-section);
  line-height: 1.08;
  letter-spacing: var(--ls-normal);
  color: var(--bone);
  margin: 0 0 var(--space-6);
  max-width: 17ch;
}
.section-title-center { margin-inline: auto; text-align: center; }

/* 20ch is the right measure for a two or three word title; it is the wrong
   one for a whole sentence, which it breaks into three stacked fragments.
   This lifts the cap so a sentence-length heading holds one line where
   there is room, and still wraps on its own once there is not. */
.section-title-wide { max-width: min(100%, 40ch); }
.section-title em,
.section-title .accent {
  font-style: normal;
  font-weight: var(--fw-accent);
  color: var(--champagne);
}

.section-header { margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.section-header.text-center .section-title { margin-inline: auto; }

.section-intro {
  font-size: var(--fs-lead);
  line-height: var(--lh-relaxed);
  color: var(--smoke);
  max-width: 58ch;
}
.text-center .section-intro { margin-inline: auto; }

/* A short champagne rule under a heading. */
.heading-rule { position: relative; padding-bottom: var(--space-4); }
.heading-rule::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 3.5rem; height: 1px;
  background: var(--champagne-dim);
}
.text-center .heading-rule::after { left: 50%; transform: translateX(-50%); }

.hero-rule {
  width: clamp(3rem, 7vw, 6.875rem);
  height: 1px;
  background: var(--champagne-dim);
  margin-block: var(--space-6);
}

/* =========================================================== 2 · BUTTONS ==
   The names are inherited (btn-gold, btn-navy, btn-outline-navy). In this
   design there is no navy and no gold: there is the offer, the alternative
   and the quiet one. Renaming them would mean editing fifteen view files
   for no gain, so the names stay and the meanings move.

   The underline opens from the centre out to both ends — the same gesture
   the eyebrow rules and the aperture make. The page opens things from
   their middle; it does not sweep them. */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding: 0 0 var(--space-3);
  font-family: var(--font-body);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--bone);
  background: none;
  border: 0;
  transition: color var(--dur-base) var(--ease-curtain);
}

/* The resting hairline. */
.btn::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--champagne-dim);
  transition: opacity var(--dur-base) var(--ease-curtain);
}
/* The hover rule: heavier, brighter, opening from the centre. */
.btn::before {
  content: '';
  position: absolute;
  left: 0; bottom: -1px;
  width: 100%; height: 2px;
  background: var(--champagne);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 620ms var(--ease-curtain);
}
.btn:hover,
.btn:focus-visible { color: var(--champagne); }
.btn:hover::after,
.btn:focus-visible::after { opacity: 0; }
.btn:hover::before,
.btn:focus-visible::before { transform: scaleX(1); }

/* The primary offer. The one filled control in the site, so it reads as
   the single thing being asked of the reader. */
.btn-gold {
  padding: var(--space-4) var(--space-8);
  color: var(--obsidian);
  background: var(--champagne);
}
.btn-gold::after,
.btn-gold::before { display: none; }
.btn-gold:hover,
.btn-gold:focus-visible { color: var(--obsidian); background: var(--bone); }

/* The alternative: outlined, not filled. */
.btn-navy,
.btn-outline-navy,
.btn-outline-light {
  padding: var(--space-4) var(--space-8);
  color: var(--champagne);
  border: 1px solid var(--champagne-dim);
  transition: background var(--dur-base) var(--ease-curtain),
              color var(--dur-base) var(--ease-curtain),
              border-color var(--dur-base) var(--ease-curtain);
}
.btn-navy::after, .btn-navy::before,
.btn-outline-navy::after, .btn-outline-navy::before,
.btn-outline-light::after, .btn-outline-light::before { display: none; }
.btn-navy:hover, .btn-navy:focus-visible,
.btn-outline-navy:hover, .btn-outline-navy:focus-visible,
.btn-outline-light:hover, .btn-outline-light:focus-visible {
  background: var(--champagne);
  border-color: var(--champagne);
  color: var(--obsidian);
}

.btn-sm { font-size: 0.6875rem; padding: var(--space-3) var(--space-5); }
.btn-block { display: flex; width: 100%; justify-content: center; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.45; pointer-events: none; }

.btn-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5) var(--space-8);
  align-items: center;
}

/* Text links that behave like the actions in the hero.

   .page-link is deliberately NOT in this group. It is only ever used inside
   .pagination — here and on the gallery page — where .pagination a already
   draws the bordered box and, being the more specific selector, won every
   box property anyway. What it did not win was ::after: each pager button
   carried this underline, so hovering a page number swept a champagne line
   across the inside of its own border. */
.link-arrow,
.link-sweep {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding-bottom: var(--space-2);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--bone);
  transition: color var(--dur-base) var(--ease-curtain);
}
.link-arrow::after,
.link-sweep::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--champagne);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 620ms var(--ease-curtain);
}
.link-arrow:hover, .link-arrow:focus-visible,
.link-sweep:hover, .link-sweep:focus-visible { color: var(--champagne); }
.link-arrow:hover::after, .link-arrow:focus-visible::after,
.link-sweep:hover::after, .link-sweep:focus-visible::after { transform: scaleX(1); }

/* =========================================================== 3 · HEADER == */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-header);
  /* Pulled in from 1.4-2.25rem. The lockup is a full four-line image now and
     needs about 80px of its own; the old padding was sized around a 46px
     mark and would have pushed the header to 157. */
  padding-block: clamp(1rem, 2vw, 1.6rem);
  background: linear-gradient(to bottom, rgba(10, 11, 13, 0.86), rgba(10, 11, 13, 0));
  transition: padding var(--dur-base) var(--ease-glide),
              background var(--dur-base) var(--ease-glide);
}
.site-header.is-scrolled {
  padding-block: 0.9rem;
  background: rgba(10, 11, 13, 0.93);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--hair-soft);
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
}


/* ------------------------------------------------------------- the logo
   One picture everywhere: the supplied artwork with its navy plate cut to
   transparency (assets/img/logo-banner.webp, 1467 x 432), so the mark, the
   words and the horizon at their side stand on the page's own ground. See
   partials/logo.php.

   The header sizes it by height, because height is what a header has to
   give. At 84px the picture is 285px wide and the name reads; the strapline
   under it is a texture at that size, which is what the artwork is at that
   size on anything — it is 20px of the image's 432. The footer sizes it to
   its column instead (.footer-brand .logo). */

.logo { display: block; flex: none; line-height: 0; }
.logo img {
  display: block;
  height: 84px;
  width: auto;
  transition: height var(--dur-base) var(--ease-glide);
}

/* Scrolled, the lockup steps down one notch. */
.site-header.is-scrolled .logo img { height: 64px; }

/* A phone header has the menu button beside it; the picture steps down so
   the two never touch. 56px is 190px across, the name still legible. */
@media (max-width: 30rem) {
  .site-header .logo img { height: 56px; }
  .site-header.is-scrolled .logo img { height: 48px; }
}

/* ---------------------------------------------------------------- nav */

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

.nav-link {
  position: relative;
  padding-bottom: var(--space-1);
  font-family: var(--font-body);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-ui);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: #C6CCD2;
  white-space: nowrap;
  transition: color var(--dur-base) var(--ease-curtain);
}
.nav-link::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--champagne);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 620ms var(--ease-curtain);
}
.nav-link:hover,
.nav-link:focus-visible,
.nav-link.is-active { color: var(--bone); }
.nav-link:hover::after,
.nav-link:focus-visible::after,
.nav-link.is-active::after { transform: scaleX(1); }
.nav-link.is-active::after { background: var(--champagne-dim); }

.header-actions { display: flex; align-items: center; gap: var(--space-5); }
.header-actions .btn { padding: 0.7rem 1.4rem; }
.nav-cta { display: none; }

/* --------------------------------------------------------- the drawer
   The header runs out of room long before a phone does: the wordmark, the
   mark, seven letterspaced items and the key need about 1240px between
   them. Below that the nav becomes a drawer rather than disappearing. */

.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  align-items: center;
  justify-content: center;
  color: var(--bone);
}
.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  display: block;
  width: 22px; height: 1px;
  background: currentColor;
  transition: transform var(--dur-base) var(--ease-curtain),
              opacity var(--dur-fast) var(--ease-curtain);
}
.nav-toggle-bars { position: relative; }
.nav-toggle-bars::before,
.nav-toggle-bars::after { content: ''; position: absolute; left: 0; }
.nav-toggle-bars::before { top: -7px; }
.nav-toggle-bars::after  { top: 7px; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after  { transform: translateY(-7px) rotate(-45deg); }

.nav-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer);
  background: rgba(6, 7, 10, 0.7);
  backdrop-filter: blur(3px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-base) var(--ease-curtain),
              visibility var(--dur-base) var(--ease-curtain);
}
.nav-backdrop.is-open { opacity: 1; visibility: visible; }

@media (max-width: 77.5rem) {
  .nav-toggle { display: inline-flex; order: 3; }
  .header-actions { display: none; }

  .nav {
    position: fixed;
    inset: 0 0 0 auto;
    z-index: calc(var(--z-drawer) + 1);
    width: min(24rem, 86vw);
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: var(--space-6);
    padding: var(--space-16) var(--space-10);
    background: var(--obsidian);
    border-left: 1px solid var(--hair);
    transform: translateX(100%);
    visibility: hidden;
    transition: transform var(--dur-slow) var(--ease-curtain),
                visibility var(--dur-slow) var(--ease-curtain);
  }
  .nav.is-open { transform: none; visibility: visible; }

  .nav-link { font-size: 0.8125rem; }
  .nav-cta { display: inline-flex; margin-top: var(--space-4); }
}

/* ======================================================== 4 · PAGE HERO ==
   Every page except the home page opens on this: a photograph pushed most
   of the way to black, a champagne kicker, and the title in the serif. */

.page-hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: clamp(24rem, 58svh, 34rem);
  padding-top: calc(var(--header-h) + var(--space-8));
  padding-bottom: clamp(2.5rem, 6vw, 4.5rem);
  overflow: hidden;
  background: var(--obsidian);
}
/* Clips the entrance: the photograph is scaled past 1 while it settles, so
   an unclipped wrapper let it hang ~9px off the right of a phone screen and
   widened the document by that much. */
.page-hero-media { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.page-hero-media img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(0.58) contrast(1.06) brightness(0.5);
}
.page-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(125% 106% at 6% 100%,
      rgba(10, 11, 13, 0.96) 0%, rgba(10, 11, 13, 0.88) 24%,
      rgba(10, 11, 13, 0.46) 52%, rgba(10, 11, 13, 0) 78%),
    linear-gradient(to top, rgba(10, 11, 13, 0.58) 0%, rgba(10, 11, 13, 0.16) 42%, rgba(10, 11, 13, 0.34) 100%);
}
.page-hero-inner { position: relative; z-index: 2; width: 100%; }

.page-hero-title {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: var(--fs-page);
  line-height: 1.04;
  letter-spacing: var(--ls-hero);
  color: var(--bone);
  max-width: 15ch;
  margin: 0;
}
.page-hero-title em,
.page-hero-title .accent { font-style: normal; font-weight: var(--fw-accent); color: var(--champagne); }

.page-hero-sub {
  display: block;
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--champagne);
  margin-bottom: var(--space-5);
}
.page-hero-text {
  margin-top: var(--space-6);
  max-width: 52ch;
  font-size: var(--fs-lead);
  line-height: var(--lh-relaxed);
  color: #D6DBE0;
}

/* ========================================================== 5 · SURFACES ==
   A card is a region of a slightly different dark bounded by a hairline.
   It is not a raised white rectangle, so it has no shadow and no radius,
   and its hover state changes ground rather than height. */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--slate);
  border: 1px solid var(--hair-soft);
  transition: background var(--dur-slow) var(--ease-curtain),
              border-color var(--dur-slow) var(--ease-curtain);
}
.card::before {
  content: '';
  position: absolute;
  inset: -1px 0 auto 0;
  height: 1px;
  background: var(--champagne);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 700ms var(--ease-curtain);
}
.card-hover:hover,
.card:hover { background: var(--slate-2); border-color: var(--hair); }
.card-hover:hover::before,
.card:hover::before { transform: scaleX(1); }

/* A flex column so a card-footer nested inside it can be pushed to the
   floor of the card. Without that, a row of cards with different amounts
   of copy leaves every Learn More at a different height. */
.card-body {
  padding: clamp(1.5rem, 3vw, 2.25rem);
  flex: 1;
  display: flex;
  flex-direction: column;
}
.card-body > .card-footer {
  margin-top: auto;
  margin-inline: calc(clamp(1.5rem, 3vw, 2.25rem) * -1);
  margin-bottom: calc(clamp(1.5rem, 3vw, 2.25rem) * -1);
}
.card-body-lg { padding: clamp(2rem, 4vw, 3rem); }
.card-footer {
  padding: var(--space-5) clamp(1.5rem, 3vw, 2.25rem);
  border-top: 1px solid var(--hair-soft);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}

.card-title {
  font-family: var(--font-body);
  font-size: var(--fs-h3);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-tight);
  color: var(--bone);
  margin: 0 0 var(--space-3);
}
.card-title-upper {
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--champagne);
}
.card-text { color: var(--smoke-2); font-size: var(--fs-sm); margin: 0; }

.card-media { overflow: hidden; }
.card-media img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  filter: grayscale(0.55) brightness(0.78) contrast(1.08);
  transition: filter var(--dur-slow) var(--ease-curtain),
              transform 1600ms var(--ease-curtain);
}
.card:hover .card-media img { filter: grayscale(0.2) brightness(0.9); transform: scale(1.03); }

/* The panel: a card that is quieter still. Used for asides and figures. */
.panel {
  background: var(--slate-2);
  border: 1px solid var(--hair-soft);
  padding: clamp(1.5rem, 3vw, 2.25rem);
}
.panel-navy { background: #06070A; }
.panel-title {
  font-family: var(--font-body);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--champagne);
  margin: 0 0 var(--space-4);
}
.panel-title-rule { padding-bottom: var(--space-4); border-bottom: 1px solid var(--hair); }

/* --------------------------------------------------------------- badges */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.3rem 0.7rem;
  font-size: 0.6875rem;
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--champagne);
  border: 1px solid var(--champagne-lo);
}
.badge-solid { background: var(--champagne); color: var(--obsidian); border-color: var(--champagne); }
.badge-muted { color: var(--smoke-2); border-color: var(--hair); }

/* ----------------------------------------------------------- icon badge */

.icon-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.25rem; height: 3.25rem;
  flex: none;
  color: var(--champagne);
  border: 1px solid var(--champagne-lo);
}
.icon-badge-outline { background: none; }

/* ---------------------------------------------------------------- icons
   The sprite states the contract in its own header: every symbol is a
   24x24 outline drawn with NO fill and NO stroke of its own, so this rule
   supplies fill:none, stroke:currentColor and the weight. That is what
   lets one sprite render champagne on obsidian and ink on paper without a
   duplicate asset — and without it, all seventy-five icons fall back to
   the SVG default of solid black, which on this ground is invisible.

   The brand marks are the exception: LinkedIn, X, YouTube and Instagram
   are solid shapes rather than outlines, so they fill instead of stroke. */
.icon {
  display: inline-block;
  flex: none;
  vertical-align: middle;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: inherit;
}
.icon-gold  { color: var(--champagne); }
.icon-white { color: var(--bone); }
.icon-brand { color: var(--smoke-2); fill: currentColor; stroke: none; }

/* ------------------------------------------------------------ check list */

.check-list { display: grid; gap: 0; }
.check-list li {
  display: grid;
  grid-template-columns: 1.5rem 1fr;
  gap: var(--space-3);
  align-items: start;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--hair-soft);
  color: var(--bone);
  font-size: var(--fs-body);
  font-weight: var(--fw-light);
}
.check-list li:last-child { border-bottom: 0; }
.check-list svg { color: var(--champagne-dim); margin-top: 0.35em; }

/* A feature row: an icon, a name and a line about it. Sits inside a
   .check-list but carries its own two-line body, so it aligns from the top
   rather than centring a single line against the icon. */
.feature-row { align-items: flex-start; gap: var(--space-4); }
.feature-body { display: block; }
.feature-name {
  display: block;
  margin-bottom: var(--space-1);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-tight);
  color: var(--champagne);
}
.feature-text {
  display: block;
  font-size: var(--fs-sm);
  line-height: 1.65;
  color: var(--smoke);
}

/* ---------------------------------------------------------- meta / misc */

.meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
  align-items: center;
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  color: var(--smoke-2);
}
.meta-row svg { color: var(--champagne-dim); }

/* align-items and gap are not optional on an icon + label pair. Without them
   the tab was the one such component in the set without either: the space
   between the icon and the word is a whitespace text node, which a flex
   container collapses, so the two sat flush against each other — and the
   default normal alignment left the 16px icon riding 4px above the label's
   centre. Same pairing as .btn, .meta-item and .category-item. */
.filter-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) 0;
  margin-right: var(--space-6);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--smoke-2);
  border-bottom: 1px solid transparent;
  transition: color var(--dur-base) var(--ease-curtain),
              border-color var(--dur-base) var(--ease-curtain);
}
.filter-tab:hover,
.filter-tab.is-active { color: var(--bone); border-bottom-color: var(--champagne); }

/* ============================================================ 6 · FORMS ==
   A field is a dark well with a hairline under it, not a boxed input. The
   champagne appears only on the field being used. */

.form-grid { display: grid; gap: var(--space-6); }
.form-grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
.form-field { display: flex; flex-direction: column; gap: var(--space-2); }
.form-field-full { grid-column: 1 / -1; }

.form-label {
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--smoke-2);
}
.form-required { color: var(--champagne); }

.form-input,
.form-textarea,
.form-select,
select.form-input {
  width: 100%;
  padding: var(--space-4) var(--space-4);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  color: var(--bone);
  background: var(--slate-2);
  border: 1px solid var(--hair);
  border-radius: 0;
  transition: border-color var(--dur-base) var(--ease-curtain),
              background var(--dur-base) var(--ease-curtain);
}
.form-input::placeholder,
.form-textarea::placeholder { color: var(--smoke-3); }
.form-input:hover,
.form-textarea:hover { border-color: var(--hair-strong); }
.form-input:focus,
.form-textarea:focus,
.form-select:focus {
  outline: none;
  background: var(--slate-3);
  border-color: var(--champagne);
}
.form-textarea { min-height: 9rem; resize: vertical; }

/* ------------------------------------------------------------ the select --
   A native <select> can be styled shut but not open — the option list is the
   operating system's, so a dark form drops a white list the moment it is
   touched. select.js draws the list instead, and the native control stays
   underneath as the thing that actually posts and validates.

   .select-native is transparent and click-through but still laid out: a
   required select that is display:none cannot be focused, so the browser
   silently refuses to submit and shows the visitor nothing. Leaving it a real
   box gives the validation bubble somewhere to point.

   Without JavaScript none of this markup exists and the plain select shows. */

.select { position: relative; }

.select-native {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
}

.select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
  padding: var(--space-4);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  text-align: left;
  color: var(--bone);
  background: var(--slate-2);
  border: 1px solid var(--hair);
  border-radius: 0;
  cursor: pointer;
  transition: border-color var(--dur-base) var(--ease-curtain),
              background var(--dur-base) var(--ease-curtain);
}
.select-trigger:hover { border-color: var(--hair-strong); }
.select-trigger:focus-visible,
.select-trigger[aria-expanded="true"] {
  outline: none;
  background: var(--slate-3);
  border-color: var(--champagne);
}
/* The unchosen state reads as a prompt, not as an answer. */
.select-trigger.is-placeholder { color: var(--smoke-3); }

.select-caret {
  flex: none;
  color: var(--smoke-2);
  transition: transform var(--dur-base) var(--ease-curtain),
              color var(--dur-base) var(--ease-curtain);
}
.select-trigger[aria-expanded="true"] .select-caret { transform: rotate(180deg); color: var(--champagne); }

/* Mirrored from the native control rather than duplicated in script, so the
   two can never disagree: forms.js puts .has-error on the real field. */
.select-native.has-error ~ .select-trigger { border-color: var(--danger); }
.select-native:disabled ~ .select-trigger { opacity: 0.5; pointer-events: none; }

.select-menu {
  position: absolute;
  z-index: 40;
  top: calc(100% - 1px);
  left: 0;
  right: 0;
  max-height: 17rem;
  margin: 0;
  padding: var(--space-2) 0;
  overflow-y: auto;
  list-style: none;
  background: var(--slate-3);
  border: 1px solid var(--champagne-dim);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
}

.select-option {
  padding: var(--space-3) var(--space-4);
  font-size: var(--fs-body);
  color: var(--smoke);
  cursor: pointer;
  transition: color var(--dur-base) var(--ease-curtain),
              background var(--dur-base) var(--ease-curtain);
}
.select-option.is-placeholder { color: var(--smoke-3); }
/* is-active is the row the keyboard is on and the row the mouse is over —
   one highlight for both, so they can never show two different candidates. */
.select-option.is-active { color: var(--bone); background: rgba(232, 229, 222, 0.06); }
.select-option[aria-selected="true"] {
  color: var(--champagne);
  box-shadow: inset 2px 0 0 var(--champagne);
}
.select-option[aria-disabled="true"] { opacity: 0.4; cursor: default; }

@media (prefers-reduced-motion: reduce) {
  .select-trigger, .select-caret, .select-option { transition: none; }
}

.form-hint { font-size: var(--fs-xs); color: var(--smoke-2); }
.form-error { font-size: var(--fs-xs); color: var(--danger); }
.form-input.has-error,
.form-textarea.has-error { border-color: var(--danger); }

.form-check { display: flex; gap: var(--space-3); align-items: flex-start; }
.form-check input { margin-top: 0.4em; accent-color: var(--champagne); }

/* ----------------------------------------------------------------- alerts */

.alert {
  padding: var(--space-5) var(--space-6);
  border: 1px solid var(--hair);
  border-left: 2px solid var(--champagne);
  background: var(--slate-2);
  color: var(--smoke);
  font-size: var(--fs-sm);
}
.alert-success { border-left-color: var(--success); background: var(--success-bg); color: var(--success); }
.alert-danger  { border-left-color: var(--danger);  background: var(--danger-bg);  color: var(--danger); }
.alert-warning { border-left-color: var(--warning); background: var(--warning-bg); color: var(--warning); }

/* ======================================================= 7 · CTA BAND ==== */

.cta-band {
  position: relative;
  padding: clamp(2.5rem, 6vw, 4.5rem);
  background: var(--slate);
  border: 1px solid var(--hair);
  overflow: hidden;
}
.cta-band-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(2rem, 5vw, 4rem);
}
.cta-band-text { display: flex; align-items: flex-start; gap: var(--space-6); max-width: 46ch; }
.cta-title {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: clamp(1.45rem, 2.7vw, 2.15rem);
  line-height: 1.12;
  color: var(--bone);
  margin: 0 0 var(--space-4);
}
.cta-title em, .cta-title .accent { font-style: normal; font-weight: var(--fw-accent); color: var(--champagne); }
.cta-text { color: var(--smoke); margin: 0; }
.cta-band-actions { display: flex; flex-direction: column; gap: var(--space-5); align-items: flex-start; }
.cta-band-buttons { display: flex; flex-wrap: wrap; gap: var(--space-5) var(--space-8); align-items: center; }

/* ======================================================= 8 · PAGINATION == */

.pagination { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; justify-content: center; }
.pagination a,
.pagination span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;
  padding: var(--space-3);
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  color: var(--smoke-2);
  border: 1px solid var(--hair-soft);
  transition: color var(--dur-base) var(--ease-curtain),
              border-color var(--dur-base) var(--ease-curtain);
}
.pagination a:hover { color: var(--bone); border-color: var(--champagne-dim); }
/* The markup emits is-active — both here and on the gallery page. This rule
   said is-current, so the current page was never highlighted and the pager
   read as though no page were selected. */
.pagination .is-active { color: var(--obsidian); background: var(--champagne); border-color: var(--champagne); }

/* ========================================================== 9 · FOOTER === */

.site-footer {
  background: #06070A;
  border-top: 1px solid var(--hair);
  padding-block: clamp(3rem, 6vw, 5rem) var(--space-10);
  color: var(--smoke-2);
}
/* Five columns: the brand, three navs and contact. auto-fit after an
   explicit track sizes off the wrong basis and collapses the navs into
   each other, so the wide layout is stated outright and the narrow one
   is the plain auto-fit. */
/* minmax(0, ...) rather than a bare 1fr on every track. A 1fr column
   carries an implicit min-width:auto, so it refuses to shrink below its
   own min-content — and one unbreakable child then pushes the whole grid
   wider than its container. That is what was overflowing the page on a
   phone: the brand column's min-content was 290px inside a 350px grid. */
/* The brand column is sized to the lockup rather than the other way round:
   it carries the mark, the rule and a wordmark that must not break, so it
   gets a wider share than the link columns and a floor deep enough to hold
   the whole thing on one line. */
.footer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: clamp(2rem, 4vw, 3.5rem);
}
.footer-grid > * { min-width: 0; }
/* Contact carries the three strings that cannot be hyphenated — an address,
   a phone number and a URL — and at a plain 1fr its column came out 168px
   against the ~243px they need with their icons. Every one of them broke
   mid-word. A floor of 15.5rem holds them on one line each and the four
   flexible tracks give up the difference, so the column is sized by what it
   has to hold rather than by an even split that suits none of it.

   The brand column keeps a floor of its own. The 20rem is what the lockup
   needs to read at the head of the column, and the blurb under it, whose
   32ch measure wants about the same width to avoid setting three words to
   a line, agrees.

   Both floors are sized against the type above, so they moved when it did:
   at --fs-xs the contact strings need 14.5rem rather than 15.5rem, and five
   columns fit from 80rem rather than 85rem. Below that the auto-fit above
   takes over and lands on two or three wide ones, which all five blocks
   read better in than five squeezed ones. */
@media (min-width: 80rem) {
  .footer-grid {
    grid-template-columns:
      minmax(20rem, 2.2fr) repeat(3, minmax(0, 1fr)) minmax(14.5rem, 1.6fr);
  }
}

/* The footer runs the full lockup — four lines against the mark — so the
   type is set a step smaller than the header's to keep the whole thing
   inside one column. */

/* Footer body copy runs at --fs-xs rather than the --fs-sm the page uses.
   Nothing down here is read start to finish — it is a directory people scan
   for one link — and a step below the body size is what makes the footer
   read as the end of the page rather than as another section of it. The
   uppercase headings stay at --fs-xxs: that is the floor the scale allows,
   and the scale reserves it for labels. */
/* The brand heads the first column: the same picture the header carries,
   sized to the column it stands in rather than by height. The column is
   20rem at its narrowest and about 21rem on a wide screen, so the picture
   runs roughly 330px across and 100px tall — the mark and the name read,
   the horizon stands at the side, and the blurb and the social links sit
   under it the way the rest of the column's copy does. The cap keeps it
   from swelling on the two- and three-column layouts between 48 and 80rem,
   where a column can run past 30rem. */
.footer-brand .logo { margin-bottom: var(--space-5); }
.footer-brand .logo img {
  height: auto;
  width: 100%;
  max-width: 22rem;
}

.footer-blurb { max-width: 32ch; font-size: var(--fs-xs); color: var(--smoke-2); }

.footer-title,
.site-footer h4 {
  margin: 0 0 var(--space-5);
  font-family: var(--font-body);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--champagne);
}
.site-footer li { margin-bottom: var(--space-3); }
.site-footer a { font-size: var(--fs-xs); color: var(--smoke); }
.site-footer a:hover { color: var(--bone); }

.footer-contact-item { display: flex; gap: var(--space-3); align-items: flex-start; font-size: var(--fs-xs); }
.footer-contact-item svg { color: var(--champagne-dim); margin-top: 0.3em; flex: none; }
/* The icon holds its size; everything beside it gives way. `anywhere` rather
   than `break-word` because only `anywhere` lowers the min-content width,
   which is the measurement that was overflowing — and an email address is
   the one string here with no space in it to break at. */
.footer-contact-item > :not(svg) {
  min-width: 0;
  overflow-wrap: anywhere;
}

.social-list { display: flex; gap: var(--space-4); margin-top: var(--space-5); }
.social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem; height: 2.5rem;
  border: 1px solid var(--hair);
  color: var(--smoke-2);
  transition: color var(--dur-base) var(--ease-curtain),
              border-color var(--dur-base) var(--ease-curtain);
}
.social-link:hover { color: var(--champagne); border-color: var(--champagne-dim); }

.footer-base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-4);
  margin-top: clamp(2.5rem, 5vw, 4rem);
  padding-top: var(--space-6);
  border-top: 1px solid var(--hair-soft);
  font-size: var(--fs-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--smoke-2);
}
.footer-legal { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); }

.newsletter-form { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-5); }
.newsletter-form .form-input { flex: 1 1 12rem; }

/* ====================================================== 10 · HOME PAGE ===
   The home page is the only one with its own layout rather than a
   composition of the components above. Its sections are rooms. */

/* -------------------------------------------------------- room 0 · hero */

.hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: 100svh;
  padding-top: clamp(6.5rem, 15vh, 10rem);
  overflow: hidden;
  background: var(--obsidian);
}

/* The stage is masked shut until the overture opens it. */
.hero-stage {
  position: absolute;
  inset: 0;
  z-index: 0;
  clip-path: inset(50% 0 50% 0);
  transition: clip-path 1900ms var(--ease-curtain);
}
html.is-open .hero-stage { clip-path: inset(0 0 0 0); }

.hero-stage-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--dur-dissolve) linear;
}
.hero-stage-slide.is-current { opacity: 1; }
.hero-stage-slide img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(0.58) contrast(1.06) brightness(0.58);
  /* Each successive room is framed tighter than the last — the crop is
     the argument, not decoration. --frame is set per slide in the view. */
  transform: scale(var(--frame, 1));
  transition: transform 12s linear;
}
.hero-stage-slide.is-current img { transform: scale(calc(var(--frame, 1) * 1.045)); }

/* The scrim is a pool of shadow under the copy, not a wash over the whole
   frame. Two overlapping linear gradients multiply, and .97 over .74
   leaves under one per cent of the photograph — which is how a hero ends
   up looking like an empty black rectangle. */
.hero-media::after,
.hero-scrim {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(125% 106% at 6% 100%,
      rgba(10, 11, 13, 0.96) 0%, rgba(10, 11, 13, 0.88) 24%,
      rgba(10, 11, 13, 0.46) 52%, rgba(10, 11, 13, 0) 78%),
    linear-gradient(to top, rgba(10, 11, 13, 0.58) 0%, rgba(10, 11, 13, 0.16) 42%, rgba(10, 11, 13, 0.34) 100%);
}

.hero-inner {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-bottom: clamp(3.5rem, 10vh, 7rem);
}

.hero-eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}
.hero-eyebrow .line {
  height: 1px;
  width: clamp(48px, 7vw, 110px);
  background: var(--champagne-dim);
  transform: scaleX(0);
  transition: transform var(--dur-slow) var(--ease-curtain) 900ms;
}
/* The pair opens outward from the label rather than both sweeping the same
   way. A symmetric ornament animating asymmetrically reads as an accident. */
.hero-eyebrow .line:first-child { transform-origin: right; }
.hero-eyebrow .line:last-child  { transform-origin: left; }
html.is-open .hero-eyebrow .line { transform: scaleX(1); }

.hero-eyebrow .eyebrow {
  margin: 0;
  color: var(--bone);
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-curtain) 1000ms;
}
html.is-open .hero-eyebrow .eyebrow { opacity: 1; }

.hero-title {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: var(--fs-hero);
  line-height: 1.04;
  letter-spacing: var(--ls-hero);
  color: var(--bone);
  margin: 0;
  max-width: 13ch;
}
.hero-title .accent,
.hero-title em { font-style: normal; font-weight: var(--fw-accent); color: var(--champagne); }

/* The headline sets itself line by line, each rising from behind its own
   mask — the aperture again, at the scale of a single line of type. */
.hero-title .ln { display: block; overflow: hidden; }
.hero-title .ln i {
  display: block;
  font-style: normal;
  transform: translateY(108%);
  transition: transform 1250ms var(--ease-curtain);
}
html.is-open .hero-title .ln i { transform: none; }
.hero-title .ln:nth-child(1) i { transition-delay: 1150ms; }
.hero-title .ln:nth-child(2) i { transition-delay: 1250ms; }
.hero-title .ln:nth-child(3) i { transition-delay: 1350ms; }

.hero-foot {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-10);
  margin-top: clamp(2.25rem, 5vw, 3.5rem);
  padding-top: clamp(1.75rem, 3vw, 2.5rem);
}
.hero-foot::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: var(--hair);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-draw) var(--ease-curtain) 1900ms;
}
html.is-open .hero-foot::before { transform: scaleX(1); }
.hero-foot > * {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 1000ms var(--ease-curtain) 2050ms,
              transform 1000ms var(--ease-curtain) 2050ms;
}
html.is-open .hero-foot > * { opacity: 1; transform: none; }
.hero-text { margin: 0; max-width: 46ch; color: #D6DBE0; }

/* ------------------------------------------- room 1 · what membership carries */

.value-strip { border-top: 1px solid var(--hair); }
.value-strip-grid { display: grid; grid-template-columns: repeat(5, 1fr); }
.value-item {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(2.5rem, 5vw, 4rem) clamp(1.4rem, 2.2vw, 2.25rem) clamp(3rem, 6vw, 5rem);
  border-right: 1px solid var(--hair-soft);
  transition: background var(--dur-slow) var(--ease-curtain);
}
.value-item:last-child { border-right: 0; }
.value-item::after {
  content: '';
  position: absolute;
  inset: -1px 0 auto 0;
  height: 1px;
  background: var(--champagne);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 700ms var(--ease-curtain);
}
.value-item:hover { background: var(--slate); }
.value-item:hover::after { transform: scaleX(1); }
/* The essence leads. Set large in the serif and in the accent, these five
   words are the layer a reader scans, and reading across the row answers
   the question the block exists to answer. */
.value-title { margin: 0 0 var(--space-5); }

.value-word {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: clamp(1.7rem, 2.4vw, 2.45rem);
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--champagne);
  transition: color var(--dur-base) var(--ease-curtain);
}

/* The rule between the word and the name is the card's one moving part:
   it extends across the column on hover, which is the same opening
   gesture the rest of the site makes, at the scale of a card. */
.value-word::after {
  content: '';
  display: block;
  width: 2.25rem;
  height: 1px;
  margin: var(--space-5) 0;
  background: var(--champagne-dim);
  transform-origin: left;
  transition: width 700ms var(--ease-curtain),
              background var(--dur-base) var(--ease-curtain);
}

.value-name {
  display: block;
  font-family: var(--font-body);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  line-height: 1.5;
  color: var(--bone);
}

.value-text { margin: 0; font-size: var(--fs-sm); line-height: 1.75; color: var(--smoke-2); }

.value-item:hover .value-word { color: var(--bone); }
.value-item:hover .value-word::after { width: 100%; background: var(--champagne); }

/* ------------------------------------ room 2 · character and composition
   Two blocks built from the same parts: a roster of short lines beside a
   photograph. Who the forum IS, then who is actually in the room.

   Each row is a hairline whose mark reaches toward the name on hover while
   the row indents — the row acknowledging the pointer without moving
   anything the reader is trying to read. The pair is mirrored, plate left
   then plate right, so the repetition reads as a spread rather than as the
   same block printed twice. */

.assembly {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: center;
  margin-top: clamp(3.5rem, 8vw, 6rem);
}

/* The pair is mirrored: plate left on the first block, plate right on the
   second, so two blocks built from the same parts read as a spread rather
   than as the same block printed twice. */
.assembly-reverse { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); }
.assembly-reverse .assembly-plate { order: -1; }
/* min-width:0 because a grid child defaults to min-content width, and the
   longest seat label would otherwise push the column wider than its track
   and force the whole row to overflow. */
.assembly-roster { min-width: 0; }
.assembly-head { margin-bottom: var(--space-6); }

.seats { border-top: 1px solid var(--hair); }
.seat {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--space-5);
  padding: clamp(1rem, 1.8vw, 1.35rem) 0;
  border-bottom: 1px solid var(--hair-soft);
  opacity: 0;
  transform: translateX(-14px);
  transition: opacity var(--dur-reveal) var(--ease-curtain),
              transform var(--dur-reveal) var(--ease-curtain),
              padding-left var(--dur-base) var(--ease-curtain);
}
.seat.is-in { opacity: 1; transform: none; }

/* The mark reaches toward the name on hover — the row acknowledging the
   pointer without moving anything the reader is trying to read. */
.seat-rule {
  display: block;
  width: 1.5rem;
  height: 1px;
  background: var(--champagne-dim);
  transition: width var(--dur-base) var(--ease-curtain),
              background var(--dur-base) var(--ease-curtain);
}
.seat-name {
  font-family: var(--font-body);
  font-size: clamp(1rem, 1.25vw, 1.0625rem);
  font-weight: var(--fw-light);
  letter-spacing: 0.01em;
  color: var(--bone);
  transition: color var(--dur-base) var(--ease-curtain);
}
.seat:hover { padding-left: var(--space-3); }
.seat:hover .seat-rule { width: 2.75rem; background: var(--champagne); }
.seat:hover .seat-name { color: var(--champagne); }

.assembly-plate { margin: 0; aspect-ratio: 4 / 3; overflow: hidden; }
.assembly-plate img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(0.55) brightness(0.72) contrast(1.08);
  transform: scale(1.05);
  transition: transform 2800ms var(--ease-curtain);
}
.assembly-plate.is-in img { transform: scale(1); }

.figure-tall { position: relative; aspect-ratio: 4 / 5; overflow: hidden; }

/* The aperture, applied to the inner box so the figure itself stays a
   clean rectangle for the observer to measure.

   The opening rule is keyed to the revealed CONTAINER rather than to any
   one figure class, so every plate in the site opens the same way and a
   new one cannot be added that silently never opens. */
.figure-mask {
  display: block;
  width: 100%; height: 100%;
  clip-path: inset(50% 0 50% 0);
  transition: clip-path var(--dur-mask) var(--ease-curtain);
}
[data-reveal].is-in .figure-mask,
[data-reveal].is-in > .figure-mask { clip-path: inset(0 0 0 0); }

.figure-tall img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(0.55) brightness(0.74) contrast(1.1);
  transform: scale(1.04);
  transition: transform 2400ms var(--ease-curtain);
}
.figure-tall.is-in img { transform: scale(1); }

/* -------------------------------------- room 3 · mission, vision, purpose */

.pillars { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(2rem, 5vw, 5rem); margin-top: clamp(2.5rem, 6vw, 4.5rem); }
.pillar { position: relative; padding-top: var(--space-6); }
.pillar::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: var(--champagne-dim);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 1200ms var(--ease-curtain);
}
.pillar.is-in::before { transform: scaleX(1); }
.pillar-question {
  display: block;
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--smoke-2);
}
.pillar-name {
  font-family: var(--font-display);
  font-weight: var(--fw-accent);
  font-style: normal;
  font-size: clamp(1.35rem, 2.3vw, 1.9rem);
  letter-spacing: 0;
  color: var(--bone);
  margin: var(--space-3) 0 var(--space-4);
}
.pillar-text { margin: 0; color: var(--smoke); }

.creed {
  margin-top: clamp(3rem, 7vw, 5rem);
  padding-top: clamp(1.75rem, 3vw, 2.5rem);
  border-top: 1px solid var(--hair);
  text-align: center;
}
.creed-label {
  display: block;
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--champagne);
}
.creed-list {
  display: block;
  margin: var(--space-6) 0;
  font-family: var(--font-display);
  font-weight: var(--fw-accent);
  font-style: normal;
  /* Sized to hold all six on one line at desktop. The serif fitted them at
     2.6rem; Montserrat is wider per character, so the cap comes down to
     match the line, not the number. */
  font-size: clamp(1.25rem, 2.6vw, 2.05rem);
  line-height: 1.5;
  color: var(--bone);
}
.creed-list li { display: inline; }
.creed-list li + li::before { content: ' · '; color: var(--champagne-lo); font-style: normal; }
.creed-list li {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 800ms var(--ease-curtain), transform 800ms var(--ease-curtain);
}
.creed.is-in .creed-list li { opacity: 1; transform: none; }
.creed.is-in .creed-list li:nth-child(1) { transition-delay:   0ms; }
.creed.is-in .creed-list li:nth-child(2) { transition-delay: 110ms; }
.creed.is-in .creed-list li:nth-child(3) { transition-delay: 220ms; }
.creed.is-in .creed-list li:nth-child(4) { transition-delay: 330ms; }
.creed.is-in .creed-list li:nth-child(5) { transition-delay: 440ms; }
.creed.is-in .creed-list li:nth-child(6) { transition-delay: 550ms; }

/* -------------------------------------------------- room 4 · the figures */

.stats-band { border-top: 1px solid var(--hair); }
.stats-grid { display: grid; grid-template-columns: repeat(5, 1fr); }
.stat {
  padding: clamp(2.5rem, 5vw, 4rem) var(--space-4);
  border-right: 1px solid var(--hair-soft);
  text-align: center;
}
.stat:last-child { border-right: 0; }
.stat-value {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: clamp(2.4rem, 5.3vw, 4.4rem);
  line-height: 1;
  color: var(--champagne);
  margin-bottom: var(--space-4);
  font-variant-numeric: tabular-nums;
}
.stat-label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--bone);
  margin-bottom: var(--space-2);
}
.stat-note { display: block; margin: 0; font-size: var(--fs-xs); color: var(--smoke-2); }

/* ------------------------------------------------ room 5 · the statement */

.statement-band {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 80svh;
  padding-block: clamp(4rem, 10vh, 8rem);
  text-align: center;
}
.statement-text {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: clamp(1.55rem, 3.7vw, 3rem);
  line-height: 1.35;
  color: var(--bone);
  margin: 0 auto;
  max-width: 19ch;
}
/* The one beat of drama in the page, at the one place it is earned: the
   claim arrives, and the promise follows half a second behind it. */
.statement-text em,
.statement-text .accent {
  display: inline-block;
  font-style: normal;
  font-weight: var(--fw-accent);
  color: var(--champagne);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 1200ms var(--ease-curtain) 520ms,
              transform 1200ms var(--ease-curtain) 520ms;
}
.statement-band.is-in .statement-text em,
.statement-band.is-in .statement-text .accent { opacity: 1; transform: none; }

/* ------------------------------------------------- room 6 · the admission
   Named for its place in the home page sequence, but not owned by it: the
   Partners page closes on the same band. Nothing in here is home-specific —
   it takes a photograph, a title with an accent clause, a line of copy and
   a group of links — so keep it that way if it picks up a third caller. */

.admission {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 70svh;
  overflow: hidden;
}
.admission > img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(0.7) brightness(0.4) contrast(1.1);
  transform: scale(1.06);
  transition: transform 3000ms var(--ease-curtain);
}
.admission.is-in > img { transform: scale(1); }
.admission .hero-scrim { background: linear-gradient(to right, rgba(10, 11, 13, 0.95), rgba(10, 11, 13, 0.42)); }
.admission-inner { position: relative; z-index: 2; width: 100%; padding-block: clamp(3rem, 7vw, 5rem); }
.admission-title {
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: clamp(1.65rem, 3.5vw, 2.75rem);
  line-height: 1.14;
  color: var(--bone);
  margin: 0 0 var(--space-6);
  max-width: 21ch;
}
/* The second sentence takes its own line and the accent colour, so the
   pair reads as two statements rather than one long run of type. */
.admission-title em,
.admission-title .accent {
  display: block;
  margin-top: var(--space-2);
  font-style: normal;
  font-weight: var(--fw-accent);
  color: var(--champagne);
}
.admission-text { max-width: 46ch; margin: 0 0 var(--space-10); }

/* ======================================================= 11 · RESPONSIVE == */

/* Five columns is only honest on a wide desktop. Step through three and
   two rather than dropping straight to two, or each card gets a measure
   far wider than its three lines of copy. */
@media (max-width: 80rem) {
  .value-strip-grid { grid-template-columns: repeat(3, 1fr); }
  .value-item { border-bottom: 1px solid var(--hair-soft); }
}
@media (max-width: 62rem) {
  .value-strip-grid,
  .stats-grid { grid-template-columns: repeat(2, 1fr); }
  .value-item,
  .stat { border-bottom: 1px solid var(--hair-soft); }
  .pillars { grid-template-columns: 1fr; }
  .assembly { grid-template-columns: 1fr; }
  .assembly-plate { order: -1; aspect-ratio: 16 / 9; }
}

@media (max-width: 44rem) {
  .value-strip-grid,
  .stats-grid { grid-template-columns: 1fr; }
  .cta-band-inner { flex-direction: column; align-items: flex-start; }
  /* Two columns forced at any width put the contact block in 135px on a
     phone, which is narrower than the email. Back to auto-fit with a floor
     deep enough for it: two columns where they fit, one where they do not. */
  .footer-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); }
  /* Half of a phone is not enough for the lockup, and the lockup is not
     something to break up. It takes the full row and the link columns
     pair off underneath it. */
  .footer-brand { grid-column: 1 / -1; }
}

/* ====================================================== 12 · LONG TAIL ====
   The components that only two or three pages use. Same rules as the rest
   of the file: hairlines and space carry the structure, one accent, no
   radius, no shadow. Grouped by the page that owns them so the next person
   editing Events knows where to look.
   ========================================================================== */

/* --------------------------------------------------------- footer detail
   These class names come from footer.php and predate this design. */

.footer-heading {
  margin: 0 0 var(--space-5);
  font-family: var(--font-body);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--champagne);
}
.footer-links li { margin-bottom: var(--space-3); }
.footer-link {
  font-size: var(--fs-xs);
  color: var(--smoke);
  transition: color var(--dur-base) var(--ease-curtain);
}
.footer-link:hover,
.footer-link.is-active { color: var(--bone); }

/* The same min-content trap the .footer-grid note above describes, one
   level further in. This grid states no columns, so it gets a single
   implicit `auto` track — and an auto track refuses to shrink below its
   item's min-content. A contact row is a flex box whose min-content is the
   whole unbroken string, so the address sized the track to 254px inside a
   145px column and pushed the document wider than the phone. Naming the
   track minmax(0, 1fr) removes that floor; the min-width on the rows lets
   the text inside them wrap rather than set the width. */
.footer-contact {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  margin-top: clamp(2.5rem, 5vw, 4rem);
  padding-top: var(--space-6);
  border-top: 1px solid var(--hair-soft);
  font-size: var(--fs-xs);
  letter-spacing: 0.08em;
  color: var(--smoke-2);
}
.footer-divider { color: var(--champagne-lo); }

/* ------------------------------------------------------------- variants */

.btn-outline-gold {
  padding: var(--space-4) var(--space-8);
  color: var(--champagne);
  border: 1px solid var(--champagne-dim);
}
.btn-outline-gold::after,
.btn-outline-gold::before { display: none; }
.btn-outline-gold:hover,
.btn-outline-gold:focus-visible { background: var(--champagne); color: var(--obsidian); border-color: var(--champagne); }
.btn-group-center { justify-content: center; }

.badge-gold  { background: var(--champagne); color: var(--obsidian); border-color: var(--champagne); }
.badge-light { color: var(--bone); border-color: var(--hair-strong); }
.badge-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5rem;
  padding: 0 0.4rem;
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  color: var(--champagne);
  border: 1px solid var(--champagne-lo);
}

.alert-error { border-left-color: var(--danger); background: var(--danger-bg); color: var(--danger); }
.alert-title {
  display: block;
  margin-bottom: var(--space-2);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  font-size: var(--fs-xxs);
}

.icon-badge-sm { width: 2.25rem; height: 2.25rem; }
.icon-badge-lg { width: 4.5rem; height: 4.5rem; }

.is-disabled { opacity: 0.4; pointer-events: none; }
.mt-16 { margin-top: var(--space-16); }
.mb-5  { margin-bottom: var(--space-5); }

/* A faint architectural wash for bands that would otherwise be flat black.
   Two hairline gradients at a shallow angle, nothing more. */
.navy-texture {
  background-image:
    linear-gradient(115deg, rgba(201, 179, 147, 0.05) 0 1px, transparent 1px 46%),
    linear-gradient(295deg, rgba(201, 179, 147, 0.04) 0 1px, transparent 1px 52%);
  background-size: 340px 340px;
}

/* ------------------------------------------------------------- card kin */

/* Left aligned, like everything else in this design. The category cards
   were setting three alignments inside one card — a centred title, a
   centred standfirst, a left-aligned feature list and a centred button —
   which is what made the row look unsettled. */
.card-centered { text-align: left; }
.card-centered .card-body { align-items: stretch; }

/* .card-inline is set on the CARD, but the row it names — an icon beside
   its text — lives one level down inside .card-body. Declaring the flex
   row on the card itself did nothing except leave the icon and the text
   stacked in the body's column with a gap of exactly zero. */
.card-inline > .card-body {
  flex-direction: row;
  align-items: flex-start;
  gap: clamp(1rem, 2vw, 1.5rem);
}
.card-inline > .card-body > .icon {
  margin-top: 0.15em;
  color: var(--champagne);
}
.card-inline-text { flex: 1; min-width: 0; }
.card-inline .card-title { margin-bottom: var(--space-3); }

.card-media { position: relative; }
.card-media-badge {
  position: absolute;
  left: var(--space-4); top: var(--space-4);
  padding: 0.3rem 0.7rem;
  font-size: 0.6875rem;
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--obsidian);
  background: var(--champagne);
}
.card-media-label {
  position: absolute;
  left: var(--space-5); bottom: var(--space-4);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider);
  text-transform: uppercase;
  color: var(--bone);
}

/* ------------------------------------------------------ events: the date
   A date is data, so it is set in tabular figures and stacked, not written
   into a sentence. */

.date-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 4.5rem;
  padding: var(--space-3);
  border: 1px solid var(--champagne-lo);
  flex: none;
}
.date-day {
  font-family: var(--font-display);
  font-size: 2rem;
  font-weight: var(--fw-display);
  line-height: 1;
  color: var(--champagne);
  font-variant-numeric: tabular-nums;
}
.date-month {
  font-size: 0.75rem;
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--smoke-2);
  margin-top: var(--space-1);
}

/* ------------------------------------------------ insights: list & filter */

.filter-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--space-2);
  border-bottom: 1px solid var(--hair);
  margin-bottom: clamp(2rem, 4vw, 3rem);
}

/* An explicit, shrinkable track. Without one the implicit column sizes to
   min-content — here 585px, driven by the fixed-width thumbnail and the
   action button — and then overflows a 475px container, crushing the title
   column to 72px. Same trap as the footer grid: a track that defaults to
   auto will not shrink below its content. */
.list-rows { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0; }
.list-rows > * { min-width: 0; }
/* Five children, four of them fixed-width: a date block, an icon, the
   meta and the action. On a 475px row those plus the gaps came to exactly
   475px, leaving the title and description — the only part anyone is
   actually reading — a width of zero.

   So the row wraps, and the main column carries a flex-basis so it claims
   its measure BEFORE the meta and the action, which drop to a second line
   rather than squeezing it out. */
.list-row {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1rem, 2vw, 1.75rem);
  align-items: center;
  padding: clamp(1.25rem, 3vw, 2rem) 0;
  border-bottom: 1px solid var(--hair-soft);
  transition: background var(--dur-slow) var(--ease-curtain);
}
.list-row:hover { background: var(--slate); }
.list-row-thumb { width: clamp(6rem, 14vw, 11rem); flex: none; overflow: hidden; }
.list-row-thumb img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  filter: grayscale(0.55) brightness(0.78) contrast(1.08);
  transition: filter var(--dur-slow) var(--ease-curtain);
}
.list-row:hover .list-row-thumb img { filter: grayscale(0.15) brightness(0.92); }
.list-row-main { flex: 1 1 18rem; min-width: 0; }
.list-row-title {
  font-size: var(--fs-h3);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-tight);
  color: var(--bone);
  margin: var(--space-2) 0;
}
.list-row-text { color: var(--smoke-2); font-size: var(--fs-sm); margin: 0; }
.list-row-meta {
  display: flex;
  flex-wrap: wrap;
  min-width: 0;
  gap: var(--space-2) var(--space-5);
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  color: var(--smoke-2);
}
.list-row-action { flex: none; }

.category-list { display: grid; gap: 0; }

/* A row is an icon, a name, and — on most pages — a trailing count and/or
   chevron held against the right edge.

   The free space is given to the NAME. It used to be handed to the gaps by
   justify-content: space-between, which only ever placed the LAST item
   correctly: everything between the icon and that item came to rest
   wherever its own text width left it. So each row was indented by a
   different amount, and the further a row's text was from its neighbours'
   in length, the worse the rag — names landing 67/37/74/70px in on
   /insights, and 35/77/68/93px on the contact panel, all from an icon
   column that never moved.

   Growing the name closes the gap it was floating in. Rows keep their
   trailing item exactly where it was, hard against the right edge. */
.category-item {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--hair-soft);
  transition: padding-left var(--dur-base) var(--ease-curtain);
}
.category-item:hover { padding-left: var(--space-2); }
.category-name { flex: 1; color: var(--bone); font-size: var(--fs-sm); }

.meta-item { display: inline-flex; align-items: center; gap: var(--space-2); }
.meta-row-stacked { flex-direction: column; align-items: flex-start; gap: var(--space-2); }

.review-list { display: grid; gap: var(--space-6); }

/* The wizard emits the key and the value as two bare spans with nothing
   between them, so with no layout here they ran together into one line of
   text — "First NameVenkata". Give the label its own column, in the same
   uppercase treatment as .form-label so a review row reads like the field it
   is echoing back, and let a long answer wrap in the column beside it. */
.review-item {
  display: grid;
  grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
  gap: var(--space-2) var(--space-6);
  align-items: baseline;
}
.review-key {
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--smoke-2);
}
/* An email address or a pasted URL has no break opportunity and would other-
   wise push its column wider than the panel. */
.review-value { color: var(--bone); overflow-wrap: anywhere; }

@media (max-width: 40rem) {
  .review-item { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); }
}

/* ---------------------------------------------------- insight: the quote
   The one place the serif appears at size outside a heading. */

.quote-band {
  position: relative;
  padding: clamp(2rem, 5vw, 3.5rem) 0;
  margin-block: clamp(2rem, 5vw, 3.5rem);
  border-block: 1px solid var(--hair);
}
.quote-mark {
  display: block;
  font-family: var(--font-display);
  font-size: 4rem;
  line-height: 0.5;
  color: var(--champagne-lo);
  margin-bottom: var(--space-4);
}
.quote-text {
  font-family: var(--font-display);
  font-weight: var(--fw-accent);
  font-style: italic;
  font-size: clamp(1.4rem, 2.8vw, 2.1rem);
  line-height: 1.4;
  color: var(--bone);
  margin: 0;
  max-width: 32ch;
}

/* ------------------------------------------------- partners: logo wall */

.grid-logos {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 1px;
  background: var(--hair-soft);
  border: 1px solid var(--hair-soft);
}
.grid-logos > * {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 8rem;
  padding: var(--space-6);
  background: var(--obsidian);
  transition: background var(--dur-slow) var(--ease-curtain);
}
.grid-logos > *:hover { background: var(--slate); }
.grid-logos img {
  max-height: 3rem;
  width: auto;
  opacity: 0.55;
  filter: grayscale(1) brightness(1.9);
  transition: opacity var(--dur-base) var(--ease-curtain);
}
.grid-logos > *:hover img { opacity: 1; }

/* ------------------------------------------ membership: process & choices
   These ARE a sequence, so the numbering is real information rather than
   decoration: step three cannot happen before step two. */

/* ------------------------------------------------------------- timeline
   The application process and the partnership process are both genuine
   sequences — an application cannot be reviewed before it is submitted —
   so this is drawn as a timeline and the numbering carries real
   information rather than decorating a list.

   Horizontal on a wide desktop, where a row of nodes reads as a route
   across the page. Vertical below 75rem, and the number is not arbitrary:
   five steps need roughly 200px of measure each to avoid setting four
   words to a line, which is 5 x (200 + padding) plus the page gutters.
   Below that the row is worse than the stack, and a horizontally scrolling
   process is one most readers never see the end of.

   The node stays square. Nothing else in this design is rounded, and a row
   of circles here would be the one place it broke its own rule. */

.steps {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  --node: clamp(2.75rem, 3.6vw, 3.25rem);
}

.step {
  position: relative;
  padding-right: clamp(1rem, 1.8vw, 1.75rem);
}

/* The connector runs from the right edge of this node to the left edge of
   the next. The steps carry padding rather than the grid carrying a gap,
   so the line can reach the column edge — which is exactly where the next
   node begins — without having to bridge a gap it cannot measure. */
.step::before {
  content: '';
  position: absolute;
  top: calc(var(--node) / 2);
  left: var(--node);
  right: 0;
  height: 1px;
  margin-top: -0.5px;
  background: var(--champagne-lo);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 900ms var(--ease-curtain) 220ms,
              background var(--dur-base) var(--ease-curtain);
}
.step.is-in::before { transform: scaleX(1); }
.step:last-child::before { content: none; }

/* Behind you: the connector of a step already passed fills to the accent,
   so the line reads as a route travelled rather than as identical rules. */
.step.is-passed::before { background: var(--champagne-dim); }

/* The node sits above the line and carries its own ground, so the
   connector runs behind it rather than through it. */
.step-badge {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--node);
  height: var(--node);
  flex: none;
  color: var(--champagne);
  background: var(--obsidian);
  border: 1px solid var(--champagne-lo);
}
/* On an alternating band the node has to match the band, not the page, or
   it reads as a hole punched in the line. */
.section-alt .step-badge,
.section-navy .step-badge { background: var(--slate); }

.step-body { min-width: 0; padding-top: var(--space-6); }

.step-number {
  display: block;
  margin-bottom: var(--space-2);
  font-family: var(--font-body);
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wider);
  color: var(--champagne-dim);
  font-variant-numeric: tabular-nums;
}
.step-title {
  font-size: var(--fs-h3);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-tight);
  line-height: 1.25;
  color: var(--bone);
  margin: 0 0 var(--space-3);
}
/* Set explicitly rather than from --fs-body. The rem tokens resolve
   against <html>, which is 16px, while body copy inherits the 17px set on
   <body> — so --fs-body here would have read a pixel SMALLER than the
   paragraphs around it, which is the opposite of the intent. */
.step-text { margin: 0; font-size: 1.0625rem; line-height: 1.7; color: var(--smoke); }

/* ------------------------------------------------------- the focus state
   Deliberately NOT dimming the other steps. Reducing the contrast of the
   text you are not reading makes a page look focused and read worse, and
   that is not a fair trade — the focus is carried entirely by things that
   are decoration rather than content.

   The scale lives on the node, never on a paragraph: a fractionally scaled
   block of body copy resamples its glyphs and reads as slightly out of
   focus, which is the opposite of the intent. */
.step-badge,
.step-number {
  transition: transform var(--dur-base) var(--ease-curtain),
              color var(--dur-base) var(--ease-curtain),
              border-color var(--dur-base) var(--ease-curtain),
              background var(--dur-base) var(--ease-curtain);
}

.step:hover .step-badge,
.step.is-current .step-badge {
  transform: scale(1.12);
  color: var(--obsidian);
  background: var(--champagne);
  border-color: var(--champagne);
}
.step:hover .step-number,
.step.is-current .step-number { color: var(--champagne); }
.step:hover::before,
.step.is-current::before { background: var(--champagne); }

/* ---------------------------------------------------- the vertical form */
@media (max-width: 75rem) {
  .steps { grid-auto-flow: row; grid-auto-columns: auto; }

  .step {
    display: grid;
    grid-template-columns: var(--node) minmax(0, 1fr);
    align-items: start;
    gap: clamp(1.25rem, 2.5vw, 2rem);
    padding-right: 0;
    padding-bottom: clamp(2.25rem, 4.5vw, 3.5rem);
  }
  .step:last-child { padding-bottom: 0; }

  /* The connector turns through ninety degrees with the layout: from the
     underside of this node down to the next one. */
  .step::before {
    top: var(--node);
    left: calc(var(--node) / 2);
    right: auto;
    bottom: 0;
    width: 1px;
    height: auto;
    margin-top: 0;
    margin-left: -0.5px;
    transform: scaleY(0);
    transform-origin: top;
  }
  .step.is-in::before { transform: scaleY(1); }

  .step-body { padding-top: 0; padding-bottom: var(--space-2); }
  .step-text { max-width: 62ch; }
}

.choice-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); gap: var(--space-5); }
.choice {
  display: block;
  padding: clamp(1.25rem, 3vw, 1.75rem);
  background: var(--slate);
  border: 1px solid var(--hair);
  cursor: pointer;
  transition: border-color var(--dur-base) var(--ease-curtain),
              background var(--dur-base) var(--ease-curtain);
}
.choice:hover { border-color: var(--champagne-dim); background: var(--slate-2); }
.choice input { position: absolute; opacity: 0; pointer-events: none; }
.choice:has(input:checked) { border-color: var(--champagne); background: var(--slate-2); }
.choice:has(input:focus-visible) { outline: 2px solid var(--champagne); outline-offset: 3px; }
.choice-title {
  display: block;
  font-size: var(--fs-h4);
  font-weight: var(--fw-medium);
  color: var(--bone);
  margin-bottom: var(--space-2);
}
.choice-text { display: block; font-size: var(--fs-sm); color: var(--smoke-2); }

/* ----------------------------------------------------- apply: the wizard */

.wizard-progress {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: clamp(2rem, 4vw, 3rem);
}
.wizard-step { display: flex; align-items: center; gap: var(--space-3); flex: none; }
.wizard-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem; height: 2rem;
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--smoke-2);
  border: 1px solid var(--hair);
  transition: color var(--dur-base) var(--ease-curtain),
              border-color var(--dur-base) var(--ease-curtain),
              background var(--dur-base) var(--ease-curtain);
}
.wizard-step.is-active .wizard-dot { color: var(--obsidian); background: var(--champagne); border-color: var(--champagne); }
.wizard-step.is-done .wizard-dot,
.is-done .wizard-dot { color: var(--champagne); border-color: var(--champagne-dim); }
.wizard-label {
  font-size: var(--fs-xxs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  color: var(--smoke-2);
}
.wizard-step.is-active .wizard-label { color: var(--bone); }
.wizard-line { flex: 1; height: 1px; background: var(--hair); min-width: var(--space-4); }
.wizard-step.is-done + .wizard-line { background: var(--champagne-lo); }
.wizard-panel { display: none; }
.wizard-panel.is-active { display: block; }
.wizard-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5) var(--space-8);
  align-items: center;
  justify-content: space-between;
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-top: var(--space-6);
  border-top: 1px solid var(--hair);
}

/* ----------------------------------------------------------- form extras */

.form-inline { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-end; }
.form-message { font-size: var(--fs-sm); color: var(--smoke-2); }
.image-preview {
  margin-top: var(--space-3);
  border: 1px solid var(--hair);
  max-width: 14rem;
  overflow: hidden;
}
.image-preview img { width: 100%; height: auto; }

@media (max-width: 44rem) {
  /* The timeline keeps its two columns on a phone: collapsing it would
     put the node above the text and leave the connector pointing at
     nothing. Only the node itself shrinks. */
  .steps { --node: 2.5rem; }
  .wizard-label { display: none; }
}
