/* ==========================================================================
   THE INFLUENCE TABLE - gold / v4 · The Room
   --------------------------------------------------------------------------
   Built to "Influence Table - Website Content.docx": an invitation-led
   landing page in five sections - hero, the table, request an invite,
   partnerships, closing - with a three-item nav.

   v4 is the build that uses the PHOTOGRAPH, and it is fixed behind the
   WHOLE document - the hero is transparent and every section below is
   translucent, so the room stays visible the whole way down instead of
   being covered after the first screen.

   That means the type-over-picture problem is NOT scoped to the hero:
   every run on this page sits on the photograph. So the contrast pass in
   section 04 covers all of it - the section titles, the body copy, the
   field labels, the disclaimer, the footer - not just the hero, and the
   section alpha in section 06 is set by that measurement rather than by
   taste.

   Contents
     01. Design tokens
     02. Base
     03. The room - the photograph
     04. The scrims, and the numbers behind them
     05. Gold foil
     06. Layout shell
     07. Nav
     08. 01 · Hero
     09. Section furniture - index, title, lede
     10. 02 · The Table
     11. 03/04 · The split sections
     12. Panels + forms
     13. Buttons
     14. 05 · Closing
     15. Foot
     16. Motion utilities
     17. Responsive
     18. Reduced motion
   ========================================================================== */


/* ==========================================================================
   01. DESIGN TOKENS
   Every gold was read off the emailer JPEG with a canvas pixel readback.
   The four builds are separate files on purpose (each is self-contained),
   but the palette must stay in step - if a colour changes here, change it
   in v1, v2 and v3 too.
   ========================================================================== */
:root {

  /* --- Ground ----------------------------------------------------------- */
  --ink-1000: #000000;
  --ink-975: #050403;
  --ink-950: #0B0906;
  --ink-925: #100D09;

  /* --- Gold ------------------------------------------------------------
     sealOuter #D8AA52 · titleRight #E7C063 · titleLeft #CFAA64
     titleMid  #E2C198 · sealText   #B3904E · presents   #9C8565
     -------------------------------------------------------------------- */
  --gold-hi: #F6E3B0;
  --gold: #E7C063;
  --gold-mid: #CFAA64;
  --gold-deep: #B3904E;
  --gold-dim: #9C8565;
  --gold-shadow: #6E5526;
  --gold-rgb: 231, 192, 99;

  /* v4's ramp starts at --gold-deep, not --gold-shadow. On black the dark
     end of the shared ramp is fine; over the photograph it measured
     1.22:1 and effectively disappeared. The wordmark is the one foil run
     that sits on the picture, so the ramp is cut for it. */
  --foil: linear-gradient(100deg,
      var(--gold-deep) 0%,
      var(--gold) 22%,
      var(--gold-hi) 42%,
      var(--gold) 60%,
      var(--gold-mid) 78%,
      var(--gold-hi) 100%);

  /* --- Text ------------------------------------------------------------- */
  --text-hi: #FFFEFB;
  --text-mid: #C9C2B4;
  --text-low: #8A8377;
  /* Was #6A645B. That measured 3.59:1 on PURE BLACK - already under the
     4.5 bar before the photograph was put behind the content sections.
     This value clears it against the lit backdrop as well. */
  --text-faint: #857E72;

  --line: rgba(var(--gold-rgb), .18);
  --line-soft: rgba(var(--gold-rgb), .11);
  --line-cool: rgba(255, 255, 255, .16);
  --line-hair: rgba(255, 255, 255, .08);

  --bad: #E48A76;
  --bad-line: rgba(224, 108, 88, .9);

  /* --- Type ------------------------------------------------------------- */
  --font-display: "Cormorant Garamond", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --font-body: "Jost", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  /* A didone, for standalone display NUMERALS only - the seat counts and
     the section plate numbers. Cormorant Garamond's figures are too
     ambiguous at that size even with lining figures forced on. The web
     font is subset to the ten digits in index.html, so only apply this to
     runs that contain nothing but digits. */
  --font-numeral: "Bodoni Moda", "Didot", "Bodoni MT", var(--font-display);

  /* The micro caps - nav, the facts labels, the section plates, the field
     labels, the footer. At .62rem these landed near 10px, and every one of
     them is letter-spaced uppercase at weight 400 over a photograph, which
     is the hardest case this page has. Raised to a ~12px floor; the tracking
     and the caps still carry the editorial read. */
  --fs-micro: .75rem;
  --fs-eyebrow: clamp(.72rem, .66rem + .22vw, .84rem);
  /* "THE", above the wordmark. Was clamp(.85rem, .7rem + .6vw, 1.3rem),
     which put it at 13.6px on a phone - a LIGHT serif, tracked .38em, in a
     mid gold, over a photograph. Every one of those makes a letterform
     thinner, and four of them together made it disappear. Bigger here; the
     weight and the colour are dealt with on the rule itself. */
  --fs-the: clamp(1.05rem, .85rem + .8vw, 1.65rem);
  /* The hero is full-bleed, so the wordmark is sized against the VIEWPORT
     rather than against a 1180px column. Dialled back from a 9.5rem cap:
     at that size it filled the frame and left the room with nothing to
     be seen through. */
  /* The steeper vw term is for PHONES, not for desktop - the cap is
     unchanged, so anything from ~1100px up renders exactly as before. At
     425px the wordmark was 38.6px against a 383px column, which left the
     mark looking like body copy on the one screen that has to do the
     selling. It now sets around 49px there and still clears the column at
     320px with room to spare. */
  --fs-wordmark: clamp(2.9rem, .55rem + 9.6vw, 6.6rem);
  --fs-title: clamp(1.7rem, 1.05rem + 2.6vw, 3.4rem);
  --fs-lede: clamp(1.02rem, .96rem + .34vw, 1.22rem);
  --fs-input: clamp(1rem, .95rem + .22vw, 1.08rem);

  /* --- Motion: one curve, everywhere ------------------------------------ */
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --dur-fast: 200ms;
  --dur-base: 320ms;
  --dur-reveal: 900ms;

  /* --- Layout ----------------------------------------------------------- */
  --gutter: clamp(1.25rem, .4rem + 3.4vw, 4rem);
  --shell: 1180px;
  /* Sized off .brand__seal, not the link text - the bar has to keep a
     margin around the mark at every step, and scroll-padding-top rides
     on this token too. */
  --nav-h: clamp(80px, 4.2rem + 2.6vw, 110px);
  --section-y: clamp(4.5rem, 3rem + 7vw, 9rem);
}


/* ==========================================================================
   02. BASE
   ========================================================================== */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchored sections must not land under the fixed nav. */
  scroll-padding-top: var(--nav-h);
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

body {
  margin: 0;
  min-height: 100svh;
  background: var(--ink-1000);
  color: var(--text-mid);
  font-family: var(--font-body);
  font-weight: 300;
  line-height: 1.7;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img {
  max-width: 100%;
}

/* LINING FIGURES - not optional.
   Cormorant Garamond defaults to OLD-STYLE (text) figures: the zero is
   x-height, the one is a small-cap-ish glyph with serifs, and three and
   five descend below the baseline. "01" therefore reads as "OI".

   The two runs that are NOTHING BUT a number - the seat counts and the
   section plate numbers - solve this by changing face entirely, to the
   didone in --font-numeral. This rule covers the rest: display-face runs
   that mix words and digits, like the closing title's "25 Seats", where
   swapping the face is not an option and lining figures are the fix.

   If you add another display run that can contain a digit, add it here.
   font-feature-settings repeats the same intent for older Safari; the two
   agree, so they cannot fight. */
.wordmark,
.section__title,
.section__index span,
.seats__n,
.panel__title,
.closing__title {
  font-variant-numeric: lining-nums tabular-nums;
  font-feature-settings: "lnum" 1, "tnum" 1;
}

::selection {
  background: rgba(var(--gold-rgb), .3);
  color: var(--text-hi);
}

:focus-visible {
  outline: 1px solid var(--gold);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 300;
}

.skip-link:focus {
  left: 1rem;
  top: 1rem;
  padding: .6rem 1rem;
  background: var(--ink-950);
  border: 1px solid var(--gold);
  color: var(--gold);
  font-size: .8rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-decoration: none;
}


/* ==========================================================================
   03. THE ROOM
   Fixed behind the entire document at z-index 0. .page sits above it at
   z-index 1; the hero is transparent so the picture reads through, and
   every section below it is TRANSLUCENT, so the picture stays visible the
   whole way down rather than being covered after the first screen.
   ========================================================================== */
.room {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: var(--ink-1000);
}

.room__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Centre 58%, not centre. The picture is 4:3 and the viewport is wider,
     so cover crops the top and bottom; biasing down keeps the dark table
     foreground under the hero's content instead of letting the bright
     lake sit there. */
  object-position: center 58%;
  /* The photograph is dark to begin with (whole-frame avg luminance 0.076,
     section 04) and then sits under four black layers. Lifting it here
     rather than thinning the scrims further keeps the type protection the
     measurements in section 04 were set for. */
  filter: brightness(1.28) contrast(.96) saturate(.95);
}


/* ==========================================================================
   04. THE SCRIMS, AND THE NUMBERS BEHIND THEM
   Measured off img/bg.png with a canvas readback, in relative luminance:

     the ceiling band     max 0.739   avg 0.041
     the window / greens  max 1.000   avg 0.150
     the table band       max 0.962   avg 0.042
     whole photograph     max 1.000   avg 0.076

   The picture is dark on average but carries near-white speculars - the
   glassware, the water, the sky. An average-based scrim would leave those
   punching through the type, so both scrims are set from the MAXIMUM.

   A black overlay at alpha a composites in gamma space, so a pixel at sRGB
   255 lands at 255(1-a).

   The hero now carries more runs than the old single-screen build, and
   they sit higher up the frame, so these were re-measured against the
   rendered page rather than inherited. Method: hide .page, screenshot the
   backdrop, and compare the BRIGHTEST pixel inside each run's own box
   against that run's ink.

   Re-run that check if you move any hero text or change img/bg.png. A run
   that shifts 200px up the page can land on the lake, and nothing in this
   file will warn you.

   REBALANCED: the stack read as near-black - the room, the table and the
   view were all lost. The photograph is now lifted at source
   (.room__img brightness) and these alphas were thinned to match, so the
   picture is legible as a picture. The worst case for type is unchanged:
   the speculars were already at sRGB 255 before the brightness lift, so
   the brightest pixel behind any run is the same pixel it always was, and
   the max-based reasoning above still holds at the new alphas.
   ========================================================================== */
.room__wash {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .12);
}

/* The global scrim. It is deliberately MILD, because .room is fixed and
   therefore sits behind every section, not just the hero - the picture is
   meant to stay visible the whole way down the page. The hero's own heavy
   scrim is local to the hero (.hero::before); it is not in here, or every
   section below would inherit a vertical band that has nothing to do with
   its content. */
.room__foot {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom,
      rgba(0, 0, 0, .26) 0%,
      rgba(0, 0, 0, .10) 42%,
      rgba(0, 0, 0, .28) 100%),
    linear-gradient(to right,
      rgba(0, 0, 0, .22) 0%,
      rgba(0, 0, 0, .05) 52%,
      rgba(0, 0, 0, 0) 82%);
}

/* A 2% noise tile. Over a photograph it does double duty: it hides the
   banding in the scrim gradients, and it puts a little grain back into an
   image that has been enlarged past its native size. */
.grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}


/* ==========================================================================
   05. GOLD FOIL
   ========================================================================== */
.foil {
  background-image: var(--foil);
  background-size: 260% 100%;
  background-position: 0% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: foil-sweep 9s var(--ease) infinite;
}

@keyframes foil-sweep {

  0%,
  100% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }
}


/* ==========================================================================
   06. LAYOUT SHELL
   ========================================================================== */
.page {
  position: relative;
  z-index: 1;
}

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* TRANSLUCENT, not opaque. The photograph is fixed behind the whole
   document and stays visible the whole way down - the room reads as a
   faint ground under every section rather than only under the hero.

   .87 is not a taste value: it is the most light this can pass and still
   keep the quietest ink on the page (--text-faint on the disclaimer and
   the field notes) above 4.5:1 against the brightest pixel the picture
   puts behind it. See section 04. */
.section {
  position: relative;
  background: rgba(0, 0, 0, .7);
  padding-block: var(--section-y);
}

/* One hairline between sections rather than a heavier divider - the
   restraint the brief asks for. */
.section+.section {
  border-top: 1px solid var(--line-hair);
}


/* ==========================================================================
   07. NAV
   Transparent while it is over the photograph; .is-stuck (set by
   js/main.js once the hero is scrolled past) drops in the ground.
   ========================================================================== */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: var(--nav-h);
  padding-inline: var(--gutter);

  /* HOW GROUNDED THE BAR IS: 0 over the photograph, 1 once it is solid.
     js/main.js drives it straight off the scroll position - long on
     desktop, where the bar arrives dark by the middle of the hero, and
     short on phones, where it grounds within a thumb's worth of scroll.
     Every value on ::before below is a fraction of it.

     It used to be a plain .is-stuck switch at 70svh with a 320ms fade on
     the far side of it, which on desktop meant the bar spent the whole
     hero transparent and then changed state in one move under the
     reader. There is no transition on any of this now: the scroll IS the
     timeline, and a duration on top of it only makes the bar lag the
     page. */
  --nav-ground: 0;
}

/* THE GROUND IS A PSEUDO-ELEMENT, NOT .nav's OWN BACKGROUND - and it has
   to stay that way. A backdrop-filter makes its element the containing
   block for fixed-position descendants, and the phone sheet (.nav__links)
   is a fixed descendant of .nav. With the blur on .nav itself, opening the
   menu anywhere below the top of the page gave a sheet the height of the
   BAR - measured at 129px against an 844px viewport. Keeping the filter
   on ::before keeps .nav filter-free and the sheet anchored to the
   viewport. */
.nav::before {
  content: "";
  position: absolute;
  inset: 0;
  /* Behind the bar's content but in front of .nav's own background box.
     .nav carries z-index 100, so this is the stacking context it sits in
     and a negative index cannot escape it. */
  z-index: -1;
  background-color: rgba(5, 4, 3, calc(var(--nav-ground) * .88));
  border-bottom: 1px solid rgba(255, 255, 255, calc(var(--nav-ground) * .08));
  pointer-events: none;
}

/* The blur is gated on the class rather than sitting at blur(0px) for the
   whole of the hero - a live backdrop root is compositor work on every
   frame whether or not it is blurring anything. js/main.js adds the class
   the moment --nav-ground leaves zero, so the gate and the value cannot
   disagree. */
.nav.is-stuck::before {
  -webkit-backdrop-filter:
    blur(calc(var(--nav-ground) * 14px))
    saturate(calc(1 - var(--nav-ground) * .1));
  backdrop-filter:
    blur(calc(var(--nav-ground) * 14px))
    saturate(calc(1 - var(--nav-ground) * .1));
}

@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .nav::before {
    background-color: rgba(5, 4, 3, calc(var(--nav-ground) * .97));
  }
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .7rem;
  text-decoration: none;
  flex: none;
}

/* img/IIGC-logo.png is now the finished gold-on-black seal, so it is drawn
   as-is. It used to be black artwork on transparency, which is why this
   block previously masked a gold-gradient box with the file's alpha and
   carried an @supports invert/sepia fallback - none of that is needed for
   real artwork, and recolouring a finished mark would only damage it.

   The seal carries the brand in the bar on its own (the wordmark beside it
   is commented out), so it is sized to be read as the mark rather than as
   an icon next to a label. It stays inside --nav-h at every step. */
.brand__seal {
  position: relative;
  display: block;
  width: clamp(56px, 5.2vw, 78px);
  aspect-ratio: 1;
  flex: none;
}

.brand__mark {
  position: absolute;
  inset: 0;
  background: url("../img/iigc-logo.png") center / contain no-repeat;
  /* The mark sits over the photograph in the transparent nav, and its
     outer edge is a mid gold against whatever the picture puts behind it.
     This is edge separation, not a colour change. */
  filter: drop-shadow(0 1px 6px rgba(0, 0, 0, .9));
}

.brand__name {
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  /* --gold-dim is the quiet gold on a flat ground; over the photograph it
     measured 3.41:1 here, so v4 uses the full accent. */
  color: var(--gold);
  text-shadow: 0 1px 10px rgba(0, 0, 0, .95);
  transition: color var(--dur-base) var(--ease);
}

.brand:hover .brand__name,
.brand:focus-visible .brand__name {
  color: var(--gold-hi);
}

.brand__name-short {
  display: none;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: clamp(1rem, .4rem + 1.7vw, 2.25rem);
}

/* The control and the two pieces that exist only inside the phone sheet.
   Above 768px the bar is the full three-link row it has always been. */
.nav__toggle,
.nav__n,
.nav__meta {
  display: none;
}

.nav__link {
  position: relative;
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--text-mid);
  text-decoration: none;
  white-space: nowrap;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .95);
  transition: color var(--dur-base) var(--ease);
}

/* The rule grows from the left rather than fading in - one gesture, and
   it reads as underlining rather than as a highlight. */
.nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -.4em;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-base) var(--ease);
}

.nav__link:hover,
.nav__link:focus-visible,
.nav__link.is-current {
  color: var(--gold);
}

.nav__link:hover::after,
.nav__link:focus-visible::after,
.nav__link.is-current::after {
  transform: scaleX(1);
}


/* --------------------------------------------------------------------------
   NAV · PHONES - logo left, control right, links behind it

   WHY. Below 576px the bar used to wrap to two centred rows: the seal, then
   the three labels shrunk to .68rem at .08em tracking to clear 320px. That
   cost 104px of a 100svh hero and read as a desktop bar that had run out of
   room. A masthead with one mark and one control is the shape this page
   wants, and it gives the links a full sheet to be set in properly rather
   than a line with 26px of slack in it.

   HOW. One set of links serves both layouts - .nav__links is the row on
   desktop and the fixed sheet here. Nothing is duplicated, so js/main.js
   still finds exactly one .nav__link per section for the scrollspy.

   CLOSED STATE is visibility:hidden, not display:none - it takes the sheet
   out of the accessibility tree AND out of hit-testing on its own, so the
   only ARIA the script has to maintain is aria-expanded on the button.
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {

  /* The sheet is a CHILD of .nav, and a fixed child paints over its parent's
     own background and border. So the bar's two items take a layer of their
     own above it, rather than the bar being restyled while it is open. */
  .brand,
  .nav__toggle {
    position: relative;
    z-index: 2;
  }

  /* --- The control ----------------------------------------------------- */
  .nav__toggle {
    display: inline-flex;
    align-items: center;
    gap: .65rem;
    /* 44px is the touch floor; the bar's own padding keeps it off the edge. */
    min-height: 44px;
    padding: .5rem .9rem;
    /* Glass, not a fill: over the photograph a solid chip would read as a UI
       control dropped onto a picture. This is the same hairline-and-blur
       language the grounded bar already speaks. */
    background: rgba(5, 4, 3, .34);
    -webkit-backdrop-filter: blur(10px) saturate(.9);
    backdrop-filter: blur(10px) saturate(.9);
    border: 1px solid var(--line);
    border-radius: 2px;
    color: var(--gold);
    font-family: inherit;
    font-size: .68rem;
    font-weight: 400;
    letter-spacing: .2em;
    /* Balances the trailing letter-space so the word sits centred in the
       chip - the same correction .btn makes. */
    text-indent: .2em;
    text-transform: uppercase;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition:
      color var(--dur-base) var(--ease),
      border-color var(--dur-base) var(--ease),
      background-color var(--dur-base) var(--ease);
  }

  .nav__toggle:hover,
  .nav__toggle:focus-visible {
    color: var(--gold-hi);
    border-color: rgba(var(--gold-rgb), .42);
  }

  .nav__toggle-word--close {
    display: none;
  }

  /* Open, the chip has the sheet behind it rather than the photograph, so
     the glass has nothing left to do and only muddies the mark. */
  .nav.is-open .nav__toggle {
    background: transparent;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-color: var(--line-soft);
  }

  .nav.is-open .nav__toggle-word--open {
    display: none;
  }

  .nav.is-open .nav__toggle-word--close {
    display: inline;
  }

  /* Two rules, not three. Three is the app convention; two reads as a mark,
     and it crosses into the X without a middle bar that has to be faded out
     halfway through the move. */
  .nav__bars {
    position: relative;
    display: block;
    width: 18px;
    height: 9px;
    flex: none;
  }

  .nav__bar {
    position: absolute;
    left: 0;
    width: 100%;
    height: 1px;
    background: currentColor;
    transition: transform var(--dur-base) var(--ease);
  }

  .nav__bar:nth-child(1) {
    top: 0;
  }

  .nav__bar:nth-child(2) {
    top: 8px;
  }

  /* Translate first, then rotate - both bars land on the same centre line
     (4px from either end) before they turn, so the X closes cleanly. */
  .nav.is-open .nav__bar:nth-child(1) {
    transform: translateY(4px) rotate(45deg);
  }

  .nav.is-open .nav__bar:nth-child(2) {
    transform: translateY(-4px) rotate(-45deg);
  }

  /* --- The sheet -------------------------------------------------------- */
  .nav__links {
    position: fixed;
    inset: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    /* Clears the bar at the top; env() keeps the foot off the home indicator
       on a notched phone. */
    padding:
      calc(var(--nav-h) + clamp(1.25rem, 1rem + 2vw, 2.25rem))
      var(--gutter)
      calc(clamp(1.5rem, 1.2rem + 1.6vw, 2.25rem) + env(safe-area-inset-bottom, 0px));
    /* A wash of gold off the top edge, so the sheet is lit from where the
       mark is rather than being a flat black panel. */
    background:
      radial-gradient(125% 70% at 50% 0%,
        rgba(var(--gold-rgb), .085) 0%,
        rgba(var(--gold-rgb), 0) 62%),
      rgba(5, 4, 3, .95);
    -webkit-backdrop-filter: blur(20px) saturate(.85);
    backdrop-filter: blur(20px) saturate(.85);
    overflow-y: auto;
    /* Stops the page behind taking over the scroll once the sheet ends. */
    overscroll-behavior: contain;
    visibility: hidden;
    opacity: 0;
    /* It drops out of the bar rather than sliding in from an edge - the bar
       is what was tapped, so that is where it should come from. */
    transform: translateY(-1.5rem);
    transition:
      opacity var(--dur-base) var(--ease),
      transform var(--dur-base) var(--ease),
      visibility 0s linear var(--dur-base);
  }

  .nav.is-open .nav__links {
    visibility: visible;
    opacity: 1;
    transform: none;
    /* Visible from frame one on the way in; only the way out has to wait for
       the fade to finish before it is taken out of the tree. */
    transition:
      opacity var(--dur-base) var(--ease),
      transform var(--dur-base) var(--ease),
      visibility 0s;
  }

  @supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .nav__links {
      background:
        radial-gradient(125% 70% at 50% 0%,
          rgba(var(--gold-rgb), .085) 0%,
          rgba(var(--gold-rgb), 0) 62%),
        rgba(5, 4, 3, .99);
    }
  }

  /* --- The links, set as an index rather than as a menu ----------------- */
  .nav__link {
    display: flex;
    align-items: baseline;
    gap: clamp(.8rem, .6rem + 1vw, 1.15rem);
    padding-block: clamp(1.3rem, 1rem + 2.2vw, 1.9rem);
    border-bottom: 1px solid var(--line-hair);
    font-family: var(--font-display);
    font-size: clamp(1.65rem, 1.25rem + 2.4vw, 2.35rem);
    font-weight: 300;
    line-height: 1.05;
    letter-spacing: .005em;
    text-transform: none;
    color: var(--text-hi);
    /* On the sheet there is no photograph to be separated from. */
    text-shadow: none;
    white-space: normal;
    opacity: 0;
    transform: translateY(.65rem);
    transition:
      opacity var(--dur-base) var(--ease),
      transform var(--dur-base) var(--ease),
      color var(--dur-base) var(--ease);
  }

  /* Three links on an 844px screen left the index stacked under the bar
     with the bottom half of the sheet empty. This margin and the one on
     .nav__meta are both auto, so the free space splits between them: the
     index settles near the middle of the sheet and the facts stay on the
     floor. When the content does fill the sheet both collapse to nothing
     and it scrolls normally. */
  .nav__link:first-of-type {
    margin-top: auto;
    border-top: 1px solid var(--line-hair);
  }

  /* The growing rule belongs to the desktop bar. Here every link already
     sits on a hairline, and a second one under it read as a double rule. */
  .nav__link::after {
    display: none;
  }

  .nav__link:hover,
  .nav__link:focus-visible,
  .nav__link.is-current {
    color: var(--gold-hi);
  }

  .nav__link:hover .nav__n,
  .nav__link:focus-visible .nav__n,
  .nav__link.is-current .nav__n {
    color: var(--gold);
  }

  /* Baseline-aligned with the serif beside it, which is what makes the pair
     read as a plate number rather than as a bullet. The face is subset to
     the ten digits in index.html - see the note on --font-numeral. */
  .nav__n {
    display: block;
    flex: none;
    width: 2ch;
    font-family: var(--font-numeral);
    font-size: .78rem;
    font-weight: 400;
    letter-spacing: .1em;
    color: var(--gold-dim);
    font-variant-numeric: lining-nums tabular-nums;
    font-feature-settings: "lnum" 1, "tnum" 1;
    transition: color var(--dur-base) var(--ease);
  }

  /* --- The foot of the sheet -------------------------------------------- */
  .nav__meta {
    display: flex;
    flex-direction: column;
    gap: .4rem;
    /* The second of the two auto margins - see .nav__link:first-of-type. */
    margin: auto 0 0;
    padding-top: clamp(1.75rem, 1.4rem + 2.4vw, 2.75rem);
    font-size: var(--fs-micro);
    font-weight: 300;
    line-height: 1.6;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--text-low);
    opacity: 0;
    transform: translateY(.65rem);
    transition:
      opacity var(--dur-base) var(--ease),
      transform var(--dur-base) var(--ease);
  }

  .nav__meta-gold {
    color: var(--gold-dim);
  }

  /* Staggered, but only just - 70ms apart is enough to read as one gesture
     unfolding rather than as four things arriving separately. */
  .nav.is-open .nav__link,
  .nav.is-open .nav__meta {
    opacity: 1;
    transform: none;
  }

  .nav.is-open .nav__link:nth-of-type(1) {
    transition-delay: 90ms;
  }

  .nav.is-open .nav__link:nth-of-type(2) {
    transition-delay: 160ms;
  }

  .nav.is-open .nav__link:nth-of-type(3) {
    transition-delay: 230ms;
  }

  .nav.is-open .nav__meta {
    transition-delay: 310ms;
  }

  /* The page behind must not scroll under the sheet. js/main.js sets the
     class on both elements - iOS honours it on <html>, the rest on <body>. */
  html.is-nav-open,
  html.is-nav-open body {
    overflow: hidden;
  }
}


/* ==========================================================================
   08. 01 · HERO
   Transparent - the photograph behind it IS the hero's ground. Content is
   bottom-weighted so it sits over the dark table foreground rather than
   over the windows.
   ========================================================================== */
.hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 100svh;
  padding-top: calc(var(--nav-h) + 2rem);
  padding-bottom: clamp(3.5rem, 2.5rem + 4vw, 6rem);
}

/* The hero's own scrim, LOCAL to the hero rather than in .room.
   .room is fixed and underlies the whole document, so a bottom-weighted
   gradient in there would repeat itself behind every section. This one
   scrolls away with the hero, which is the only place that needs it:
   the top band stays open because that is the view, and it goes
   near-solid under the wordmark and the facts row. Alphas are from the
   measurement in section 04, re-run after the size change. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(to bottom,
      rgba(0, 0, 0, .38) 0%,
      rgba(0, 0, 0, .14) 16%,
      rgba(0, 0, 0, .34) 34%,
      rgba(0, 0, 0, .50) 50%,
      rgba(0, 0, 0, .62) 66%,
      rgba(0, 0, 0, .74) 84%,
      rgba(0, 0, 0, .82) 100%);
}

/* Above that scrim. Without this the hero's own overlay would paint over
   the type it exists to protect. */
.hero__shell,
.hero__scroll {
  position: relative;
  z-index: 1;
}

/* Full-bleed on purpose. Every other section is inside .shell; the hero is
   not, so it runs the width of the viewport on the gutter alone. */
.hero__shell {
  width: 100%;
  max-width: none;
  padding-inline: var(--gutter);
}

.eyebrow {
  display: flex;
  align-items: center;
  gap: clamp(.7rem, .5rem + .8vw, 1.2rem);
  margin: 0 0 clamp(.9rem, .7rem + .8vw, 1.5rem);
  font-size: var(--fs-eyebrow);
  font-weight: 400;
  letter-spacing: .34em;
  text-transform: uppercase;
  /* The highest run in the hero, so it sits on the brightest backdrop.
     --gold measured 4.19:1 there - under the 4.5 bar for text this size.
     --gold-hi clears it. */
  color: var(--gold-hi);
  text-shadow: 0 1px 10px rgba(0, 0, 0, .95);
}

/* A short gold hairline leading into the label. It is the same gesture the
   section indices use further down, so the page has one rule language. */
.eyebrow__rule {
  display: block;
  flex: none;
  width: clamp(28px, 1rem + 3.6vw, 76px);
  height: 1px;
  background: linear-gradient(to right, var(--gold-deep), var(--gold));
}

.wordmark {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 300;
  /* Tighter than the old build: at full-bleed size the two lines have to
     lock together as one block rather than read as two sentences. */
  line-height: .88;
  text-transform: uppercase;
}

.wordmark__the,
.wordmark__line {
  display: block;
}

/* The inline run carries the tracking and pulls the trailing letter-space
   back off the advance, so a line measures its glyphs and nothing else. */
.wordmark .ink {
  display: inline;
  white-space: nowrap;
}

.wordmark__the {
  margin-bottom: clamp(.3rem, .25rem + .3vw, .5rem);
  font-size: var(--fs-the);
  /* 500, not the 300 the .wordmark block sets. The two big lines can carry
     a light weight because they are 40px+ and get a drop-shadow; this run
     is a fraction of their size and was reading as a grey smudge. 500 is
     loaded in index.html, so this costs nothing. */
  font-weight: 500;
  /* --gold-dim is the quiet gold on a flat ground, and it is what the
     other three builds use here. It does not hold over the picture: this
     run sits high in the frame, where the window light is, and it
     measured 3.51:1 at 1280. --gold-mid cleared the bar at 5.6:1 but read
     as muddy next to the foil below it, so this takes the full accent -
     lighter than --gold-mid, so the contrast only improves. */
  color: var(--gold);
  /* Two shadows, like the wordmark lines: a tight one for edge definition
     and a wide one to darken the picture immediately around the glyphs. */
  text-shadow:
    0 1px 8px rgba(0, 0, 0, .95),
    0 0 26px rgba(0, 0, 0, .85);
}

.wordmark__the .ink {
  letter-spacing: .38em;
  margin-inline-end: -.38em;
}

.wordmark__line {
  font-size: var(--fs-wordmark);
  /* Over a picture the glow is doing legibility work, not decoration: it
     separates the caps from whatever is behind them. */
  filter:
    drop-shadow(0 2px 3px rgba(0, 0, 0, .85)) drop-shadow(0 0 34px rgba(0, 0, 0, .8));
}

.wordmark__line .ink {
  letter-spacing: .08em;
  margin-inline-end: -.08em;
}

/* The words on the left, the call to action on the right, sitting on the
   same baseline band. On a full-bleed hero this is what stops the right
   half of the frame from being dead space. */
.hero__row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(1.5rem, .8rem + 3vw, 4rem);
  margin-top: clamp(1.4rem, 1rem + 1.6vw, 2.6rem);
}

.hero__say {
  min-width: 0;
}

.hero__seats {
  margin: 0;
  font-size: clamp(.94rem, .84rem + .42vw, 1.18rem);
  font-weight: 300;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--text-hi);
  text-shadow: 0 1px 10px rgba(0, 0, 0, .95);
}

.hero__lede {
  max-width: 48ch;
  margin: clamp(.8rem, .65rem + .6vw, 1.15rem) 0 0;
  font-size: var(--fs-lede);
  font-weight: 300;
  line-height: 1.7;
  color: var(--text-mid);
  text-shadow: 0 1px 12px rgba(0, 0, 0, .95);
}

/* --- The facts: edge to edge under a full-width rule --------------------
   Spread rather than clustered. The rule spans the whole viewport gutter
   to gutter, and the three items sit at the two ends and the middle of it,
   which is what actually sells the hero as full-bleed. */
.facts {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: clamp(1.1rem, .5rem + 2.2vw, 3rem);
  margin: clamp(1.8rem, 1.2rem + 2.2vw, 3.2rem) 0 0;
  padding-top: clamp(1.1rem, .85rem + 1vw, 1.6rem);
  border-top: 1px solid var(--line);
}

.facts__item {
  min-width: 0;
}

/* The last item squares off against the right gutter so the rule reads as
   a measured band rather than as a row that ran out. */
.facts__item--end {
  text-align: right;
}

.facts__label {
  margin: 0 0 .25rem;
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--gold-dim);
  text-shadow: 0 1px 10px rgba(0, 0, 0, .95);
}

.facts__value {
  margin: 0;
  font-size: clamp(.92rem, .84rem + .34vw, 1.06rem);
  font-weight: 300;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-hi);
  text-shadow: 0 1px 10px rgba(0, 0, 0, .95);
}

.facts__value--gold {
  color: var(--gold);
}

.hero__cta {
  flex: none;
  margin: 0;
}

/* A hairline that says the page continues. Not an arrow, not a word. */
.hero__scroll {
  position: absolute;
  left: 50%;
  bottom: clamp(1.1rem, .8rem + 1vw, 1.9rem);
  width: 1px;
  height: clamp(28px, 4vh, 46px);
  overflow: hidden;
  transform: translateX(-50%);
  background: var(--line-cool);
}

.hero__scroll-rule {
  position: absolute;
  inset: 0;
  background: var(--gold);
  animation: scroll-hint 2.6s var(--ease) infinite;
}

@keyframes scroll-hint {
  0% {
    transform: translateY(-100%);
  }

  55%,
  100% {
    transform: translateY(100%);
  }
}


/* ==========================================================================
   09. SECTION FURNITURE
   ========================================================================== */
.section__index {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin: 0 0 clamp(1rem, .8rem + .9vw, 1.6rem);
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--gold-dim);
}

/* The number is set in the display face, a size up from its label - the
   section marker reads as a plate number rather than as part of the run
   of small caps. */
.section__index span {
  font-family: var(--font-numeral);
  font-size: 1.55em;
  font-weight: 500;
  letter-spacing: .06em;
  line-height: 1;
  color: var(--gold);
}

/* The rule fills whatever is left of the line, so the label always reads
   as the head of a ruled band regardless of its length. */
.section__index::after {
  content: "";
  flex: 1;
  height: 1px;
  /* Fades out rather than stopping dead at the gutter - a hard-ended rule
     at this weight reads as a table border. */
  background: linear-gradient(to right, var(--line), transparent);
}

.section__title {
  max-width: 18ch;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: 300;
  line-height: 1.08;
  letter-spacing: .015em;
  text-transform: uppercase;
  color: var(--text-hi);
  /* These titles are 3-6 words in a light display face; balancing stops
     the last line from falling to a single orphaned word. */
  text-wrap: balance;
}

/* Title against copy, two columns. The title is the larger of the two so
   it takes the wider track; the copy sits to its right on the same top
   line rather than under it. */
.section__head {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  align-items: start;
  gap: clamp(2rem, 1rem + 4vw, 5.5rem);
}

.section__head .section__title {
  max-width: 14ch;
}

/* Optically aligned to the title's first baseline rather than its box -
   the display face carries a lot of space above its caps. */
.section__head .section__body {
  margin-top: .4rem;
}

@media (max-width: 991.98px) {
  .section__head {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.5rem, 1.2rem + 1.6vw, 2.25rem);
  }

  .section__head .section__title {
    max-width: 18ch;
  }

  .section__head .section__body {
    margin-top: 0;
  }
}

.section__body {
  margin-top: clamp(1.5rem, 1.1rem + 1.6vw, 2.4rem);
  display: grid;
  gap: clamp(1rem, .8rem + .9vw, 1.5rem);
  max-width: 62ch;
}

.lede {
  margin: 0;
  font-size: var(--fs-lede);
  font-weight: 300;
  line-height: 1.7;
  color: var(--text-mid);
  max-width: 56ch;
}

/* In the split sections the copy follows the title directly, with no
   .section__body wrapper to carry the gap. */
.section__title+.lede {
  margin-top: clamp(1.25rem, 1rem + 1.4vw, 2.25rem);
}

/* Scoped to the split sections only. Inside .section__body the grid gap
   already spaces these, and both would stack into a doubled gutter. */
.split__say .lede+.lede {
  margin-top: clamp(1rem, .8rem + .9vw, 1.5rem);
}

.lede--quiet {
  color: var(--text-low);
}

.disclaimer {
  margin: clamp(1.25rem, 1rem + 1.1vw, 2rem) 0 0;
  padding-left: 1rem;
  border-left: 1px solid var(--text-mid);
  font-size: 1rem;
  line-height: 1.65;
  letter-spacing: .03em;
  /* color: var(--text-faint); */
  max-width: 46ch;
}


/* ==========================================================================
   10. 02 · THE TABLE
   The four counts. A ruled row on desktop, a 2×2 on narrow screens - the
   numbers are the content, so they get the display face.
   ========================================================================== */
.seats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  margin: clamp(2.5rem, 1.8rem + 2.6vw, 4.5rem) 0 0;
  padding: 0;
  list-style: none;
  /* The 1px gap plus this ground draws the seams - no per-cell borders to
     double up at the joins. */
  background: var(--line-hair);
  border: 1px solid var(--line-hair);
}

.seats__item {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .55rem;
  padding: clamp(1.6rem, 1.1rem + 2vw, 2.75rem) clamp(1rem, .8rem + 1vw, 1.6rem);
  background: rgba(0, 0, 0, .28);
  transition: background-color var(--dur-base) var(--ease);
}

/* A gold seam that draws itself along the top of the cell on hover. The
   cells are not links, so this is the only affordance they need - it says
   the row is one set of four, not four boxes. */
.seats__item::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-base) var(--ease);
}

.seats__item:hover {
  background: var(--ink-950);
}

.seats__item:hover::before {
  transform: scaleX(1);
}

/* The counts are the content of this section, so they carry it: display
   face, near-hero scale, and the full accent gold. */
.seats__n {
  font-family: var(--font-numeral);
  font-size: clamp(2.8rem, 1.6rem + 4vw, 5rem);
  font-weight: 400;
  line-height: 1;
  /* A didone's hairlines need a little air at display size, or the thick
     stems close the counters up. */
  letter-spacing: .05em;
  color: var(--gold);
}

/* NOT uppercased, unlike every other label on the page: "CMOs" set in
   caps becomes "CMOS", which reads as the chip. The tracking carries the
   label style instead. */
.seats__what {
  font-size: clamp(.78rem, .73rem + .2vw, .88rem);
  font-weight: 400;
  letter-spacing: .16em;
  line-height: 1.5;
  /* color: var(--text-low); */
  transition: color var(--dur-base) var(--ease);
}

.seats__item:hover .seats__what {
  color: var(--text-mid);
}


/* ==========================================================================
   11. 03 / 04 · THE SPLIT SECTIONS
   The words on the left, the form on the right. The form column is fixed
   rather than fluid so the fields never stretch to an unusable measure on
   a wide screen.
   ========================================================================== */
.shell--split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 30rem);
  align-items: start;
  gap: clamp(2.5rem, 1.5rem + 4vw, 5.5rem);
}

.split__say {
  min-width: 0;
  /* Holds the words beside the top of the form on tall panels. */
  position: sticky;
  top: calc(var(--nav-h) + 3rem);
}

.split__form {
  min-width: 0;
}

/* Sticky is wrong once the columns stack - the words would peel off the
   form they belong to. */
@media (max-width: 991.98px) {
  .split__say {
    position: static;
  }
}


/* ==========================================================================
   12. PANELS + FORMS
   The panel is the one raised surface on the page: a shade off black with
   a gold hairline, so it reads as an object placed on the ground rather
   than a box drawn on it.
   ========================================================================== */
.panel {
  position: relative;
  padding: clamp(1.6rem, 1.2rem + 1.8vw, 2.75rem);
  /* Translucent like the sections, so the room reads through the plate
     too - but blurred. The blur is doing legibility work, not decoration:
     it destroys the picture's speculars, which is what lets the panel sit
     lighter than the section around it and still hold small form text. */
  background:
    linear-gradient(160deg, rgba(16, 13, 9, .90) 0%, rgba(5, 4, 3, .93) 62%);
  -webkit-backdrop-filter: blur(18px) saturate(.9);
  backdrop-filter: blur(18px) saturate(.9);
  border: 1px solid var(--line);
  box-shadow: 0 30px 70px -30px rgba(0, 0, 0, .9);
}

/* No blur available, so the speculars would survive. Go opaque rather
   than lighten to compensate. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .panel {
    background: linear-gradient(160deg, var(--ink-925) 0%, var(--ink-975) 62%);
  }
}

/* Two gold corner brackets, top-left and bottom-right. Cheaper than a
   heavier border and it reads as a plate rather than as a form box. */
.panel::before,
.panel::after {
  content: "";
  position: absolute;
  width: clamp(18px, 2.2vw, 30px);
  height: clamp(18px, 2.2vw, 30px);
  pointer-events: none;
}

.panel::before {
  top: -1px;
  left: -1px;
  border-top: 1px solid var(--gold);
  border-left: 1px solid var(--gold);
}

.panel::after {
  right: -1px;
  bottom: -1px;
  border-right: 1px solid var(--gold);
  border-bottom: 1px solid var(--gold);
}

.panel__done[hidden] {
  display: none;
}

.panel__done:focus {
  outline: none;
}

.panel__ask {
  margin: 0 0 .3rem;
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold-dim);
}

.panel__title {
  margin: 0 0 .9rem;
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 1.2rem + .9vw, 1.85rem);
  font-weight: 400;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-hi);
}

.panel__done-sub {
  margin: 0;
  font-size: .98rem;
  line-height: 1.65;
  letter-spacing: .02em;
  color: var(--text-mid);
  max-width: 34ch;
}

/* --- Fields ------------------------------------------------------------- */
.field+.field,
.field-row+.field,
.field+.field-row,
.field-row+.field-row {
  margin-top: clamp(.9rem, .75rem + .6vw, 1.2rem);
}

.field-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(.9rem, .6rem + 1.2vw, 1.5rem);
}

.field-row .field+.field {
  margin-top: 0;
}

.field__label {
  display: block;
  margin-bottom: .3rem;
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: .2em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--gold-dim);
  transition: color var(--dur-base) var(--ease);
}

.field:focus-within .field__label {
  color: var(--gold);
}

.req {
  color: var(--gold);
}

/* "Recommended" / "Optional" - the doc's own requirement notes, kept on
   the label rather than hidden in a placeholder that vanishes on typing. */
.field__note {
  margin-left: .4em;
  color: var(--text-faint);
  letter-spacing: .14em;
  text-transform: none;
  font-size: .95em;
}

.field__input {
  width: 100%;
  padding: .55rem .1rem;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line-cool);
  border-radius: 0;
  color: var(--text-hi);
  font-family: inherit;
  font-size: var(--fs-input);
  font-weight: 300;
  letter-spacing: .02em;
  transition: border-color var(--dur-base) var(--ease);
}

.field__input::placeholder {
  color: var(--text-low);
  opacity: 1;
}

.field__input:hover {
  border-bottom-color: var(--line);
}

.field__input:focus {
  outline: none;
  border-bottom-color: var(--gold);
}

.field__input--area {
  resize: vertical;
  min-height: 4.5rem;
  line-height: 1.6;
}

/* --- The select --------------------------------------------------------- */
.select {
  position: relative;
}

.field__input--select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 1.5rem;
  cursor: pointer;
}

/* The native menu is the OS's, and it is light. Force the options dark so
   the open list does not flash white on a black page. */
.field__input--select option {
  background: var(--ink-925);
  color: var(--text-hi);
}

/* Until something is chosen the control is showing placeholder text, so it
   takes the placeholder's colour rather than the ink colour. */
.field__input--select:invalid,
.field__input--select.is-empty {
  color: var(--text-low);
}

.select__chevron {
  position: absolute;
  right: .3rem;
  top: 50%;
  width: .48rem;
  height: .48rem;
  margin-top: -.35rem;
  border-right: 1px solid var(--gold-dim);
  border-bottom: 1px solid var(--gold-dim);
  transform: rotate(45deg);
  pointer-events: none;
  transition: border-color var(--dur-base) var(--ease);
}

.select:focus-within .select__chevron {
  border-color: var(--gold);
}

/* --- Errors and counters ------------------------------------------------ */

/* .is-invalid is only ever set by JS after a submit attempt - never on
   :invalid, which would flag every field the moment the page loads. */
.field.is-invalid .field__input {
  border-bottom-color: var(--bad-line);
}

.field.is-invalid .field__label,
.field__error {
  color: var(--bad);
}

.field__error {
  margin: .25rem 0 0;
  min-height: 1.05em;
  font-size: .82rem;
  line-height: 1.4;
  letter-spacing: .04em;
}

.field__count {
  margin: .3rem 0 0;
  font-size: .78rem;
  letter-spacing: .1em;
  text-align: right;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.field__count.is-full {
  color: var(--gold-dim);
}

.form__note {
  margin: .8rem 0 0;
  min-height: 1.35em;
  font-size: .84rem;
  letter-spacing: .06em;
  color: var(--text-low);
  opacity: 0;
  transform: translateY(4px);
  transition:
    opacity var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease);
}

.form__note.is-shown {
  opacity: 1;
  transform: none;
}

/* A note that is reporting a failure rather than progress. The muted
   --text-low above is right for "sending…"; it is too quiet for the one
   line telling someone their request did not go through. */
.form__note.is-error {
  color: var(--bad);
}


/* ==========================================================================
   13. BUTTONS
   --------------------------------------------------------------------------
   BOOTSTRAP OWNS .btn. index.html loads bootstrap@5.3.3 before this file,
   and Bootstrap ships state rules - .btn:hover, .btn:first-child:active,
   .btn:disabled - that are MORE SPECIFIC than the plain .btn below, so
   they win no matter what order the files load in.

   Every one of those rules reads a --bs-btn-* token that only Bootstrap's
   own variants (.btn-primary and friends) ever define. This page uses none
   of them, so on hover the tokens were undefined, and an undefined var()
   is invalid at computed-value time: for `color` that resolves to INHERIT,
   which handed the label body grey (#C9C2B4) on pale gold, and for
   border-color it fell back to currentColor, so the gold edge went with it.

   Fixing it by out-specifying Bootstrap means chasing :hover, :active,
   :disabled and :first-child:active separately and re-losing on the next
   Bootstrap bump. Defining the tokens instead means its selectors keep
   winning - they just resolve to this build's palette. Anything else that
   borrows a Bootstrap class name on this page needs the same treatment.
   ========================================================================== */
.btn {
  /* Fed to Bootstrap's own state rules. See the note above. */
  --bs-btn-color: var(--ink-1000);
  --bs-btn-hover-color: var(--ink-1000);
  --bs-btn-active-color: var(--ink-1000);
  --bs-btn-disabled-color: var(--ink-1000);
  --bs-btn-border-color: var(--gold);
  --bs-btn-hover-border-color: var(--gold);
  --bs-btn-active-border-color: var(--gold);
  --bs-btn-disabled-border-color: var(--gold);
  --bs-btn-bg: transparent;
  --bs-btn-hover-bg: transparent;
  --bs-btn-active-bg: transparent;
  --bs-btn-disabled-bg: transparent;
  --bs-btn-box-shadow: none;
  --bs-btn-active-shadow: none;
  --bs-btn-focus-box-shadow: none;
  --bs-btn-disabled-opacity: .55;

  position: relative;
  display: inline-block;
  padding: .9rem clamp(1.5rem, 1.1rem + 1.6vw, 2.5rem);
  background: transparent;
  border: 1px solid var(--gold);
  border-radius: 2px;
  color: var(--ink-1000);
  font-family: inherit;
  font-size: .84rem;
  font-weight: 400;
  letter-spacing: .22em;
  text-indent: .22em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  /* Clips the sheen to the face. Without it the band runs out past the
     border and reads as a stray highlight on the photograph. */
  overflow: hidden;
  transition:
    color var(--dur-base) var(--ease),
    border-color var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease),
    box-shadow var(--dur-base) var(--ease);
}

.btn--block {
  display: block;
  width: 100%;
  margin-top: clamp(1.25rem, 1rem + 1.1vw, 1.85rem);
}

/* LAYER 1 - the foil itself. Sized to 200% so there is gradient to spare
   off the right edge, and the hover slides the ramp across rather than
   only brightening it: the gold turns, the way a foil block turns when the
   card moves under a light. */
.btn--gold::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, var(--gold-deep), var(--gold), var(--gold-hi));
  background-size: 200% 100%;
  background-position: 0% 50%;
  transition:
    filter var(--dur-base) var(--ease),
    background-position 900ms var(--ease);
}

/* LAYER 2 - the sheen. A narrow raked band of light that crosses the face
   once per hover.

   The long transition lives in the :hover rule, NOT here. That is what
   makes the return read correctly: on leave this rule takes over, and with
   no transition on transform the band snaps back to its start off the left
   edge while only its opacity fades. Put the duration here instead and the
   sheen visibly reverses back across the button, which reads as an
   animation running backwards rather than as light passing. */
.btn--gold::after {
  content: "";
  position: absolute;
  top: -60%;
  bottom: -60%;
  left: 0;
  width: 30%;
  pointer-events: none;
  /* Dark shoulders, not just a white core. The foil ramp ends at --gold-hi
     (#F6E3B0), so a plain white band is invisible across the right half of
     its own travel - measured, not guessed: it only read over the deep end.
     Shouldering it in --gold-shadow gives the glint something to sit
     against at every point on the ramp, which is also how a specular
     actually behaves on a metallic surface. */
  background: linear-gradient(90deg,
      rgba(110, 85, 38, 0) 0%,
      rgba(110, 85, 38, .20) 26%,
      rgba(255, 255, 255, .82) 50%,
      rgba(110, 85, 38, .20) 74%,
      rgba(110, 85, 38, 0) 100%);
  transform: translateX(-180%) skewX(-18deg);
  opacity: 0;
  transition: opacity 240ms var(--ease);
}

/* Above both layers, so the sheen passes UNDER the lettering and the label
   stays a crisp black throughout. */
.btn__label {
  position: relative;
  z-index: 1;
}

/* The colour and the border are restated here, not just left to the tokens
   above, so the hover still holds if Bootstrap is ever dropped from the
   page - and so the one state that actually broke is legible in this file
   rather than only in a comment. */
/* The lift is 2px and the glow drops from 40px to 52px of blur at a lower
   offset - the button rises off the photograph rather than growing. Scale
   was tried here and rejected: it resamples the lettering, and at .84rem
   with .22em of tracking that shows. */
.btn:hover,
.btn:focus-visible {
  color: var(--ink-1000);
  border-color: var(--gold-hi);
  transform: translateY(-2px);
  box-shadow: 0 18px 52px -18px rgba(var(--gold-rgb), .68);
}

/* A keyboard ring the mouse never sees. The glow above is an invitation,
   not a focus indicator - it fails on its own against a lit photograph. */
.btn:focus-visible {
  outline: 1px solid var(--gold-hi);
  outline-offset: 3px;
}

/* Was 1.12. The gradient already ends at --gold-hi (#F6E3B0), so a 12%
   lift drove its light end to near-white and the face washed out. 1.05
   reads as the same gesture without flattening the foil - and now it is
   the background-position slide, not the brightness, doing the work. */
.btn--gold:hover::before,
.btn--gold:focus-visible::before {
  filter: brightness(1.05);
  background-position: 100% 50%;
}

/* NOT var(--ease). That curve is a settle - it spends ~60% of its progress
   in the first 15% of its time, which is right for something arriving and
   wrong for a light crossing a surface: the band cleared the dark left end
   of the foil, where it is actually visible, in about 40ms and the rest of
   the sweep happened over the pale end where white on #F6E3B0 shows
   nothing. This curve is close to even, with just enough ease-out to stop
   it feeling mechanical. */
.btn--gold:hover::after,
.btn--gold:focus-visible::after {
  transform: translateX(430%) skewX(-18deg);
  opacity: 1;
  transition:
    transform 950ms cubic-bezier(.36, .18, .28, 1),
    opacity 140ms linear;
}

/* Faster than the hover, and it lands BELOW the resting position rather
   than at it - a press has to feel like it went somewhere. The glow
   collapses in the same beat so the button reads as pushed into the page
   instead of hovering over it. */
.btn:active {
  transform: translateY(1px);
  box-shadow: 0 4px 14px -10px rgba(var(--gold-rgb), .5);
  transition-duration: var(--dur-fast);
}

/* Nothing moves on a button that cannot be pressed - no lift, no sheen. */
.btn[disabled] {
  cursor: default;
  opacity: .55;
}

.btn[disabled]:hover {
  transform: none;
  box-shadow: none;
}

.btn--gold[disabled]:hover::before {
  filter: none;
  background-position: 0% 50%;
}

.btn--gold[disabled]:hover::after {
  opacity: 0;
  transform: translateX(-180%) skewX(-18deg);
}

/* Send another: a word, not a button. */
.link-btn {
  margin-top: clamp(1rem, .85rem + .9vw, 1.5rem);
  padding: 0;
  background: none;
  border: 0;
  color: var(--gold);
  font-family: inherit;
  font-size: var(--fs-micro);
  letter-spacing: .2em;
  text-transform: uppercase;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-color: var(--line);
  transition: text-decoration-color var(--dur-base) var(--ease);
}

.link-btn:hover,
.link-btn:focus-visible {
  text-decoration-color: var(--gold);
}

.link {
  color: var(--text-hi);
  text-decoration: none;
  background-image: linear-gradient(var(--gold), var(--gold));
  background-size: 100% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  padding-bottom: 2px;
  transition: color var(--dur-base) var(--ease);
}

.link:hover,
.link:focus-visible {
  color: var(--gold);
}


/* ==========================================================================
   14. 05 · CLOSING
   Centred, and the only centred block on the page - which is what makes it
   read as an ending rather than as another section.
   ========================================================================== */
.closing {
  position: relative;
  background: rgba(0, 0, 0, .76);
  border-top: 1px solid var(--line-hair);
  padding-block: clamp(5rem, 3.5rem + 8vw, 10rem);
  text-align: center;
}

.closing__shell {
  display: grid;
  justify-items: center;
  gap: clamp(1.4rem, 1.1rem + 1.4vw, 2.25rem);
}

/* A hairline dropping into the closing block from the section above it,
   so the ending is approached rather than just arrived at. */
.closing::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 1px;
  height: clamp(2.5rem, 1.5rem + 4vw, 5rem);
  background: linear-gradient(to bottom, var(--gold), transparent);
}

.closing__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2rem, 1rem + 4.4vw, 5rem);
  font-weight: 300;
  line-height: 1.1;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-wrap: balance;
}

.closing__lines {
  margin: 0;
  font-size: var(--fs-lede);
  font-weight: 300;
  line-height: 2;
  letter-spacing: .06em;
  color: var(--text-mid);
}

.closing__when {
  margin: 0;
  padding: clamp(1rem, .8rem + .9vw, 1.5rem) clamp(1.5rem, 1rem + 2vw, 3rem) 0;
  border-top: 1px solid var(--line);
  font-size: clamp(.84rem, .78rem + .22vw, .95rem);
  font-weight: 400;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--text-hi);
}

.closing__when .dot {
  color: var(--gold-deep);
  margin-inline: .3em;
}

.closing__seal {
  margin: 0;
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--gold-dim);
}


/* ==========================================================================
   15. FOOT
   ========================================================================== */
.foot {
  position: relative;
  background: rgba(0, 0, 0, .90);
  border-top: 1px solid var(--line-soft);
}

.foot__shell {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: clamp(1.1rem, .9rem + .9vw, 1.6rem);
}

.foot__write,
.foot__by {
  margin: 0;
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: .2em;
  text-transform: uppercase;
}

.foot__write {
  color: var(--text-low);
}

.foot__by {
  color: var(--gold-dim);
  text-align: right;
}

/* The confirmation that the address reached the clipboard. It only ever
   appears after a deliberate click on the address, and it takes no space
   until then - visibility, not display, so the live region stays in the
   accessibility tree and is announced when it fills. */
.foot__copied {
  margin-left: .6rem;
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gold);
  white-space: nowrap;
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease);
}

.foot__copied.is-shown {
  opacity: 1;
}


/* ==========================================================================
   16. MOTION UTILITIES
   The brief asks for minimal animation, so this is one gesture: a short
   rise on entry, resolved by an IntersectionObserver in js/main.js.
   ========================================================================== */
.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity var(--dur-reveal) var(--ease),
    transform var(--dur-reveal) var(--ease);
}

.reveal.is-in {
  opacity: 1;
  transform: none;
}

/* The photograph settles in behind everything rather than appearing with
   it - a still frame that arrives at the same moment as the type reads as
   a slideshow. */
.room__img {
  opacity: 0;
  transform: scale(1.04);
  transition:
    opacity 1400ms var(--ease),
    transform 2600ms var(--ease);
}

.room__img.is-in {
  opacity: 1;
  transform: none;
}


/* ==========================================================================
   17. RESPONSIVE
   ========================================================================== */

/* Tablet: the split sections stack, and the form goes under its words. */
@media (max-width: 991.98px) {
  .shell--split {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(2rem, 1.5rem + 2.5vw, 3rem);
  }

  .split__form {
    max-width: 34rem;
  }

  .seats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 767.98px) {
  .brand__name-full {
    display: none;
  }

  .brand__name-short {
    display: inline;
  }

  /* Below this the picture cannot be relied on to stay quiet under a full
     phone-width column of type, so the ground is weighted towards the
     bottom of the frame where the type sits.

     REBALANCED. This used to end at .97, which on a phone meant the lower
     two thirds of EVERY screen was solid black - .room is fixed, so this
     gradient is relative to the viewport, not to the page. Stacked with
     the .7 that .section already paints, the photograph reached the screen
     at roughly 1% and the whole build read as flat black with type on it.
     The section alpha is doing the legibility work; this only has to keep
     the picture from competing, so it no longer doubles up on it. */
  .room__foot {
    background: linear-gradient(to bottom,
        rgba(0, 0, 0, .44) 0%,
        rgba(0, 0, 0, .26) 20%,
        rgba(0, 0, 0, .54) 44%,
        rgba(0, 0, 0, .64) 62%,
        rgba(0, 0, 0, .72) 100%);
  }

  /* The scrim above buys back the photograph, and it has to be paid for
     here rather than by putting the black back. Measured, not estimated:
     hide .page, screenshot the fixed room, take its BRIGHTEST pixel, and
     composite .section over it - see the method in section 04.

     .room is fixed, so that backdrop does not move while the page does,
     which means every run passes over the brightest pixel sooner or later.
     The two faintest inks were the only ones that could not survive it, so
     they lift on phones and the section takes a little more black. The
     display inks are untouched: they already clear it by 8:1. */
  :root {
    --text-low: #9A9285;
    --text-faint: #968E80;
    /* The quiet gold, on the facts labels and the footer. Same reason. */
    --gold-dim: #A68E6C;
  }

  .section {
    background: rgba(0, 0, 0, .76);
  }

  /* Was 92svh. On a phone that left the hero ending ABOVE the fold, so the
     first screen finished with the hero's bottom padding and the next
     section's top padding stacked into one ~130px band of black under the
     facts row. The hero now owns the whole first screen and that band
     falls below it, where it belongs.

     The top padding is trimmed to match: the bar is 104px here and the
     content is bottom-anchored anyway, so the desktop's extra 2rem was
     only ever pushing the wordmark down on the screen that has least room
     for it. */
  .hero {
    min-height: 100svh;
    padding-top: calc(var(--nav-h) + .5rem);
    padding-bottom: clamp(2.25rem, 1.6rem + 2.6vw, 3.25rem);
  }

  .hero__scroll {
    display: none;
  }

  /* The CTA goes under the words rather than beside them - at this width
     there is no right half to put it in. */
  .hero__row {
    flex-direction: column;
    align-items: flex-start;
    gap: clamp(1.5rem, 1.2rem + 1.6vw, 2.25rem);
  }

  .hero__cta {
    width: 100%;
  }

  .hero__cta .btn {
    display: block;
  }
}

@media (max-width: 575.98px) {

  /* The bar used to wrap to two centred rows here - seal above, three
     shrunken labels below - and take --nav-h to 104px to pay for it. The
     hamburger replaced all of it; the sheet is in section 07. --nav-h is
     left on its own clamp, which is a single row at every phone width, so
     scroll-padding-top stays honest without an override. */
  .facts {
    flex-direction: column;
    gap: .9rem;
  }

  /* Stacked, so there is no right edge to square off against. */
  .facts__item--end {
    text-align: left;
  }

  /* NOT one column. Four counts stacked single-file ran to roughly 500px of
     mostly empty cell - each number left-aligned with two thirds of its row
     dead to the right, which read as a sparse list rather than as a set.
     There are exactly four, so 2x2 halves the height and closes the gap,
     and the tighter padding stops the cells being mostly air. */
  .seats__item {
    padding: clamp(1.1rem, .9rem + 1.2vw, 1.5rem) clamp(.85rem, .7rem + .8vw, 1.15rem);
    gap: .35rem;
  }

  .field-row {
    grid-template-columns: minmax(0, 1fr);
  }

  .field-row .field+.field {
    margin-top: clamp(.9rem, .75rem + .6vw, 1.2rem);
  }

  .btn {
    letter-spacing: .16em;
    text-indent: .16em;
  }

  .foot__shell {
    flex-direction: column;
    align-items: flex-start;
    gap: .4rem;
  }

  .foot__by {
    text-align: left;
  }
}

/* A short landscape phone: a 100svh hero would put the wordmark and the
   button in a 300px band. Let it grow and scroll instead. */
@media (max-height: 560px) and (orientation: landscape) {
  .hero {
    min-height: 0;
    padding-block: calc(var(--nav-h) + 2rem) 3rem;
  }

  .hero__scroll {
    display: none;
  }
}


/* ==========================================================================
   18. REDUCED MOTION
   Nothing may be left hidden - every animated state resolves to its end,
   the photograph included.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {

  *,
  *::before,
  *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    transition-delay: 0ms !important;
  }

  .reveal {
    opacity: 1;
    transform: none;
  }

  .room__img {
    opacity: 1;
    transform: none;
  }

  .hero__scroll {
    display: none;
  }

  /* Parks the foil sweep mid-travel instead of leaving it at one end.
     .brand__mark is not listed: the seal is finished artwork now and has
     no sweep to park. */
  .foil {
    background-position: 50% 50%;
  }
}
/* ==========================================================================
   SUBMIT BUTTON - BUSY STATE
   js/main.js sets aria-busy="true" on the button for the length of the
   request, so the attribute already tells the truth about the state and this
   is purely its visual form. No extra class to keep in sync.

   The mark sits in the same layer as .btn__label (z-index 1): .btn--gold
   paints its foil in ::before across the whole face, and anything left in
   the default layer disappears underneath it.
   ========================================================================== */
.btn__spin {
  display: none;
  position: relative;
  z-index: 1;
  width: .82em;
  height: .82em;
  margin-right: .6em;
  /* Sits on the cap height rather than the baseline, so it centres against
     the uppercase lettering instead of riding low. */
  vertical-align: -.08em;
  border: 1.5px solid currentColor;
  /* One transparent quadrant is what makes the rotation legible - a full
     ring spinning looks static. */
  border-top-color: transparent;
  border-radius: 50%;
  /* currentColor is the button's black lettering, which reads correctly
     against the gold foil in every state the button has. */
  color: inherit;
  animation: btn-spin .68s linear infinite;
}

.btn[aria-busy="true"] .btn__spin {
  display: inline-block;
}

/* The sheen is a hover flourish. Holding it still during a submit keeps the
   spinner the only thing moving on the face. */
.btn[aria-busy="true"]::after {
  opacity: 0;
}

.btn[aria-busy="true"] {
  cursor: progress;
}

@keyframes btn-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Motion-sensitive visitors still need to know it is working, so the mark
   stays and pulses instead of spinning - a static ring would read as an
   ornament rather than as progress. */
@media (prefers-reduced-motion: reduce) {
  .btn__spin {
    animation: btn-spin-fade 1.1s ease-in-out infinite;
  }

  @keyframes btn-spin-fade {
    0%, 100% { opacity: 1; }
    50% { opacity: .35; }
  }
}
