/* ==========================================================================
   TRUE NORTH BILLBOARDS
   A media brand, not a sign company.

   Near-black + warm ivory. One accent. Type does the work.
   ========================================================================== */

/* Fonts are linked from each page head, not imported here. An @import makes
   the browser download this stylesheet, parse it, and only then discover the
   font request, which serialises two round trips that can run in parallel. */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  --ink:        #0A0A0A;
  --ink-soft:   #101010;
  --ink-lift:   #171717;
  --ink-edge:   #1F1F1F;

  --ivory:      #F2EFE9;
  --ivory-2:    rgba(242,239,233,.62);
  /* .40 measured 3.45:1 on the near-black ground, under the 4.5:1 needed for
     normal text, and this tint carries most of the small copy on the site. */
  --ivory-3:    rgba(242,239,233,.50);
  --ivory-4:    rgba(242,239,233,.22);

  /* The single accent. Spent sparingly: it should feel like it costs money. */
  --accent:     #E0241C;

  /* The accent measures 4.18:1 on the near-black ground, which clears the 3:1
     bar for large text but not the 4.5:1 one for normal text. Error copy is
     the one place that has to be read under pressure, so it uses a lifted red
     at 6.03:1. Everything else keeps the brand accent. */
  --accent-text: #FF4D42;

  --line:       rgba(242,239,233,.13);
  --line-2:     rgba(242,239,233,.26);

  /* Type. The label role used to be a monospace; it now shares the display
     grotesque, set in caps with open tracking. Reads editorial, not technical. */
  --display: 'Inter Tight', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --body:    'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --util:    'Inter Tight', 'Helvetica Neue', Helvetica, Arial, sans-serif;

  /* --pad closes a section. --join is the top padding of anything that follows
     another block, so every seam on every page measures the same. Two values,
     no exceptions: a colour change is not a reason to space differently. */
  --pad:  clamp(2.5rem, min(6.5vw, 7vh), 6rem);
  --join: clamp(1.5rem, min(3.25vw, 3.5vh), 3rem);

  /* In-section steps. Every gap inside a section uses one of these three, so
     nothing is set by a hand-picked number in a style attribute. */
  --gap-s: clamp(0.875rem, 1.8vh, 1.25rem);
  --gap-m: clamp(1.75rem, 3.4vh, 2.5rem);
  --gap-l: clamp(2.5rem, 5vh, 3.75rem);

  --wrap: 1440px;
  --gutter: clamp(1.25rem, 4vw, 4.5rem);

  /* The bar sets the wordmark large on load, then contracts on scroll so the
     header stops competing with the page. */
  --nav-h: 96px;
  --nav-h-stuck: 70px;

  --ease: cubic-bezier(.16,.84,.24,1);
  --ease-io: cubic-bezier(.65,.02,.24,1);
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h-stuck) + 1rem);
  /* The booking bar is fixed to the bottom edge, so a tabbed-to control near
     the foot of the page would land underneath it. Reserve the room. */
  scroll-padding-bottom: 2rem;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--ivory);
  font-family: var(--body);
  font-size: 1.0625rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 900;
  line-height: .88;
  letter-spacing: -.045em;
  text-transform: uppercase;
  margin: 0;
}

p { margin: 0 0 1rem; }
p:last-child { margin-bottom: 0; }

::selection { background: var(--accent); color: #fff; }

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

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--ivory); color: var(--ink);
  padding: 1rem 1.5rem;
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
}
.skip-link:focus { left: 0; }

/* --------------------------------------------------------------------------
   3. Type roles
   -------------------------------------------------------------------------- */

/* Label: the small voice. Coordinates, labels, counts. Small, but never
   so small it has to be squinted at. */
.util {
  font-family: var(--util);
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ivory-3);
}

/* Section marker: a number and a word, hairline rule beneath. It has to hold
   its own against the display heading that follows it. */
.marker {
  display: flex; align-items: baseline; gap: 1.125rem;
  padding-bottom: 1.125rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: clamp(2rem, min(6vw, 6.5vh), 5rem);
}
.marker__n {
  font-family: var(--util); font-weight: 700;
  font-size: 1.0625rem; letter-spacing: .1em;
  color: var(--accent);
}
.marker__t {
  font-family: var(--util); font-weight: 600;
  font-size: 1.0625rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ivory-2);
}

/* Display sizes: do not be shy. Only two are in use: .d1 carries every page
   headline, .d4 the subheadings inside a board page's prose. */
.d1 { font-size: clamp(3.25rem, min(13.5vw, 16vh), 12rem); }
.d4 { font-size: clamp(1.5rem, 3vw, 2.25rem); letter-spacing: -.035em; }

.accent { color: var(--accent); }
.dim { color: var(--ivory-2); }

.lede {
  font-size: clamp(1.125rem, 1.6vw, 1.375rem);
  line-height: 1.55;
  color: var(--ivory-2);
  max-width: 46ch;
}

/* --------------------------------------------------------------------------
   4. Layout
   -------------------------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }

.section { padding-block: var(--pad); position: relative; }

/* Every seam uses the same top padding, so no join on any page is measurably
   different from any other. Without this each block pays a full closing
   measure and the next pays a full opening one, doubling the gap. */
.hero + .section,
.section + .section,
.panel + .section { padding-top: var(--join); }

/* The spec strip ends on a hard rule with no space beneath it, so the section
   after it opens on a full measure. That makes it match the one other seam
   that follows a full-bleed edge, the panel image. */
.board-top + .section { padding-top: var(--pad); }
.section + .cta .cta__inner,
.panel + .cta .cta__inner { padding-top: var(--join); }
.section--ivory { background: var(--ivory); color: var(--ink); }
.section--ivory .util { color: rgba(10,10,10,.45); }
.section--ivory .marker { border-color: rgba(10,10,10,.14); }
.section--ivory .marker__t { color: rgba(10,10,10,.45); }
.section--ivory .lede { color: rgba(10,10,10,.66); }
.section--ivory .dim { color: rgba(10,10,10,.6); }

/* --------------------------------------------------------------------------
   4b. Spacing utilities
   These exist so no page carries a one-off number in a style attribute; every
   in-section gap resolves to the same three steps on every page.
   -------------------------------------------------------------------------- */
.stack-s { margin-top: var(--gap-s); }
.stack-m { margin-top: var(--gap-m); }
.stack-l { margin-top: var(--gap-l); }
.stack-below { margin-bottom: var(--pad); }
.small { font-size: .9375rem; }
.btn--full { width: 100%; }

/* A section that opens a page sits under the fixed header, so it clears the
   bar and then opens with the same measure any other section would. */
.section--page-top { padding-top: calc(var(--nav-h) + var(--pad)); }

/* Marker variants: one introduces a block inside a column, one introduces a
   full-width block further down a page. */
.marker--aside { margin-top: var(--gap-l); margin-bottom: var(--gap-s); }
.marker--block { margin-top: var(--pad); }

/* A highlighted aside inside prose. */
.prose--note { margin-top: var(--gap-l); padding-top: var(--gap-m); border-top: 1px solid var(--accent); }

/* Off-screen spam honeypot. Never shown, never focused. */
.trap { position: absolute; left: -9999px; }

/* --------------------------------------------------------------------------
   4c. Status badge
   One board is running; the rest are not yet. Saying so plainly is worth more
   than the impression that all five are already selling.
   -------------------------------------------------------------------------- */
.status {
  display: inline-flex; align-items: center; gap: .5rem;
  font-family: var(--util); font-weight: 700; font-size: .75rem;
  letter-spacing: .14em; text-transform: uppercase;
  padding: .3125rem .625rem;
  border: 1px solid currentColor;
  white-space: nowrap;
}
.status__dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex: none; }
.status--live { color: var(--accent-text); }
.status--soon { color: var(--ivory-3); }
.section--ivory .status--soon { color: rgba(10,10,10,.5); }

/* Live boards get a slow pulse. Motion is the point of the word, so it stops
   when the visitor has asked for less of it. */
.status--live .status__dot { animation: pulse 2.4s var(--ease) infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) { .status--live .status__dot { animation: none; } }

/* City and status share a line above the board name. */
.board-row__meta { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; margin-bottom: .75rem; }
.board-row__meta .board-row__city { margin-bottom: 0; }
/* --------------------------------------------------------------------------
   5. Navigation: part of the brand, not a website header
   -------------------------------------------------------------------------- */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 90;
  height: var(--nav-h);
  display: flex; align-items: center;
  transition: background .4s var(--ease), border-color .4s var(--ease), height .4s var(--ease);
  border-bottom: 1px solid transparent;
}
.nav.is-stuck {
  height: var(--nav-h-stuck);
  background: rgba(10,10,10,.86);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border-bottom-color: var(--line);
}
.nav__inner {
  width: 100%; max-width: var(--wrap); margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex; align-items: center; justify-content: space-between; gap: 2rem;
}

/* Type alone carries the brand up here. The illustrated mark could not hold
   its own detail at header size, so the name does the work instead. */
.nav__brand { display: flex; align-items: center; flex: none; }

.nav__wordmark {
  display: flex; flex-direction: column; align-items: center;
  font-family: var(--display); font-weight: 900;
  font-size: 1.625rem; line-height: .9;
  letter-spacing: -.035em; text-transform: uppercase;
  transition: font-size .4s var(--ease);
}
/* Both words are ten characters, so at matching tracking they render within 3px
   of the same width and the centring is invisible: the lockup reads as flush
   left. The width difference is made on the FIRST line, by opening its tracking,
   rather than by shrinking the second. Shrinking BILLBOARDS also shortened its
   letters, and the two lines of a stacked wordmark have to share a cap height.
   Both lines therefore keep the same font size and undistorted letterforms. */
.nav__wordmark span:first-child { letter-spacing: .037em; }
.nav__wordmark span:last-child { color: var(--accent); }
.nav.is-stuck .nav__wordmark { font-size: 1.25rem; }

.nav__links { display: flex; align-items: center; gap: 2.25rem; }
.nav__link {
  font-family: var(--util); font-weight: 600; font-size: .9375rem;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ivory-2);
  padding: .5rem 0;
  position: relative;
  transition: color .25s var(--ease);
}
.nav__link:hover { color: var(--ivory); }
.nav__link::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px; background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform .35s var(--ease);
}
/* The Network link keeps its underline on the five board pages: a board sits
   inside the Network section without being that page. That is a visual cue only,
   so it rides on a class. It used to be aria-current="true", which made a screen
   reader announce Network as the current link while you were on a board page. */
.nav__link:hover::after, .nav__link[aria-current]::after,
.nav__link--section::after { transform: scaleX(1); }
.nav__link[aria-current], .nav__link--section { color: var(--ivory); }

.nav__cta {
  font-family: var(--display); font-weight: 800;
  font-size: .9375rem; letter-spacing: .05em; text-transform: uppercase;
  display: inline-flex; align-items: center; gap: .625rem;
  padding: .9375rem 1.625rem;
  background: var(--accent); color: #fff;
  min-height: 48px;
  transition: background .25s var(--ease);
}
.nav__cta:hover { background: #fff; color: var(--ink); }
.nav__cta svg { width: 15px; height: 15px; }

.nav__toggle {
  display: none;
  width: 44px; height: 44px;
  background: none; border: 0; color: var(--ivory);
  cursor: pointer;
  align-items: center; justify-content: center;
}

/* --------------------------------------------------------------------------
   6. Buttons: minimal, sharp
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: space-between;
  gap: 2.5rem;
  font-family: var(--display); font-weight: 800;
  font-size: .9375rem; letter-spacing: .06em; text-transform: uppercase;
  padding: 1.3125rem 1.875rem;
  min-height: 58px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease);
}
.btn svg { width: 18px; height: 18px; flex: none; transition: transform .3s var(--ease); }
.btn:hover svg { transform: translateX(5px); }

.btn--fill { background: var(--accent); color: #fff; }
.btn--fill:hover { background: var(--ivory); color: var(--ink); }

.btn--line { border-color: var(--line-2); color: var(--ivory); }
.btn--line:hover { border-color: var(--ivory); background: var(--ivory); color: var(--ink); }

.section--ivory .btn--line { border-color: rgba(10,10,10,.28); color: var(--ink); }
.section--ivory .btn--line:hover { background: var(--ink); color: var(--ivory); border-color: var(--ink); }

.btn-row { display: flex; flex-wrap: wrap; gap: 1rem; }

/* --------------------------------------------------------------------------
   7. HERO: the billboard is monumental, not a card on a page
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding-top: var(--nav-h);
  overflow: hidden;
}

.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__slide {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity 1.1s var(--ease-io);
}
.hero__slide.is-live { opacity: 1; }
.hero__slide img {
  width: 100%; height: 100%; object-fit: cover;
  filter: grayscale(.28) contrast(1.14) brightness(.62);
  transform: scale(1.04);
}
.hero__media::after {
  content: '';
  position: absolute; inset: 0;
  background:
    linear-gradient(to top, var(--ink) 0%, rgba(10,10,10,.72) 34%, rgba(10,10,10,.30) 68%, rgba(10,10,10,.55) 100%);
}

/* The hero closes with the same measure a section does, so the seam into the
   first section matches every other seam on the page. */
.hero__body { position: relative; z-index: 2; padding-bottom: var(--pad); }

/* Big, but not so big it buries the billboard. The product has to stay
   visible above the type: that is the whole point of the picture. */
.hero__title {
  font-size: clamp(2.5rem, min(8.2vw, 11vh), 7.25rem);
  line-height: .86;
  letter-spacing: -.05em;
  max-width: 15ch;
}
.hero__title span { display: block; }

/* Fixed columns, not wrapping flex. With flex-wrap the readout jumped from
   beside the lede to underneath it depending on how long that board name and
   its details happened to be, so the layout changed on every slide. */
.hero__foot {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(17rem, 23rem);
  gap: var(--gutter);
  align-items: end;
  margin-top: clamp(1.75rem, 4vw, 3rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}
.hero__lede { max-width: none; font-size: clamp(1.0625rem, 1.5vw, 1.3125rem); color: var(--ivory-2); }

/* The live board readout: the product mechanic, stated quietly */
.hero__now { display: flex; align-items: center; flex-wrap: wrap; gap: .875rem 1rem; }
/* The name and details take a full row of their own and reserve their height,
   so a two-line board and a one-line board occupy the same space. */
.hero__now-txt { flex: 1 1 100%; display: flex; flex-direction: column; gap: .3125rem; min-height: 3.25rem; }
.hero__now-place {
  font-family: var(--display); font-weight: 800; font-size: 1.1875rem;
  text-transform: uppercase; letter-spacing: -.015em;
}
/* The board name is a link to that board's page. Bare inline it measured 23px,
   just under the 24px pointer-target minimum. */
.hero__now-place a { display: inline-block; padding-block: 2px; }
.hero__now-meta { font-family: var(--util); font-weight: 600; font-size: .8125rem; letter-spacing: .1em; color: var(--ivory-3); text-transform: uppercase; }

.hero__ticks { display: flex; gap: .375rem; }
.hero__tick {
  width: 34px; height: 24px; padding: 0;
  background: none; border: 0; cursor: pointer;
  display: inline-flex; align-items: center;
}
.hero__tick::after {
  content: ''; display: block; width: 100%; height: 2px;
  background: var(--ivory-3);
  transition: background .3s var(--ease);
}
.hero__tick:hover::after { background: var(--ivory-2); }
.hero__tick[aria-current="true"]::after { background: var(--accent); }

.hero__pause {
  width: 36px; height: 36px;
  background: none; border: 1px solid var(--line-2); color: var(--ivory-2);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.hero__pause:hover { color: var(--ivory); border-color: var(--ivory); }
.hero__pause svg { width: 12px; height: 12px; }

.hero__slot { height: 2px; background: var(--ivory-4); position: relative; overflow: hidden; margin-top: 1.25rem; }
.hero__slot-fill {
  position: absolute; inset: 0;
  background: var(--accent);
  transform: scaleX(0); transform-origin: left center;
}
.hero__slot-fill.is-running { animation: slot linear forwards; }
@keyframes slot { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* --------------------------------------------------------------------------
   8. Statement: type dominates, copy whispers
   -------------------------------------------------------------------------- */
.statement__title { max-width: 14ch; }
.statement__body { margin-top: clamp(1.75rem, min(5vw, 5.5vh), 4rem); display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--gutter); }
.statement__body .lede { grid-column: 7 / 13; }
@media (max-width: 900px) { .statement__body .lede { grid-column: 1 / -1; } }

/* --------------------------------------------------------------------------
   9. Big numbers
   -------------------------------------------------------------------------- */
.figures { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gutter); margin-top: clamp(2rem, min(6vw, 6vh), 4.5rem); }
.figure { border-top: 1px solid var(--line); padding-top: 1.5rem; }
.section--ivory .figure { border-color: rgba(10,10,10,.16); }
.figure__n {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(2.5rem, min(7.5vw, 8vh), 6rem);
  line-height: .85; letter-spacing: -.05em;
  font-variant-numeric: tabular-nums;
}
.figure__n em { font-style: normal; color: var(--accent); }
.figure__k { margin-top: 1rem; }

/* --------------------------------------------------------------------------
   10. Network: locations as architecture, not inventory
   -------------------------------------------------------------------------- */
.board-list { border-top: 1px solid var(--line); margin-top: clamp(2.5rem, min(7vw, 8vh), 6rem); }

.board-row {
  position: relative;
  display: grid;
  grid-template-columns: 5.5rem 1fr auto;
  gap: var(--gutter);
  align-items: center;
  padding: clamp(1.75rem, 3.5vw, 2.75rem) 0;
  border-bottom: 1px solid var(--line);
  transition: background .45s var(--ease);
}
.board-row:hover { background: var(--ink-soft); }

.board-row__i { font-family: var(--util); font-weight: 600; font-size: .875rem; letter-spacing: .14em; color: var(--ivory-3); }

.board-row__city {
  font-family: var(--util); font-weight: 700; font-size: .875rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--accent);
  margin-bottom: .75rem; display: block;
}
.board-row__name {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(1.75rem, min(4.6vw, 5vh), 3.75rem);
  line-height: .9; letter-spacing: -.045em; text-transform: uppercase;
  transition: transform .45s var(--ease);
}
.board-row:hover .board-row__name { transform: translateX(14px); }
.board-row__name a::after { content: ''; position: absolute; inset: 0; }
.board-row__addr { font-family: var(--util); font-weight: 500; font-size: .9375rem; letter-spacing: .06em; color: var(--ivory-3); margin-top: .875rem; }

.board-row__fig { text-align: right; }
.board-row__fig b {
  display: block;
  font-family: var(--display); font-weight: 800;
  font-size: clamp(1.25rem, 2.6vw, 1.9375rem);
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
}
.board-row__fig span { font-family: var(--util); font-weight: 600; font-size: .75rem; letter-spacing: .14em; text-transform: uppercase; color: var(--ivory-3); }

/* The image reveals on hover, pinned to the cursor side */
.board-row__peek {
  position: absolute; right: 12%; top: 50%;
  width: 22vw; max-width: 330px; aspect-ratio: 4 / 3;
  transform: translateY(-50%) scale(.94);
  opacity: 0; pointer-events: none;
  overflow: hidden; z-index: 3;
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.board-row:hover .board-row__peek { opacity: 1; transform: translateY(-50%) scale(1); }
.board-row__peek img { width: 100%; height: 100%; object-fit: cover; filter: grayscale(.2) contrast(1.1) brightness(.85); }
@media (max-width: 1100px) { .board-row__peek { display: none; } }

/* --------------------------------------------------------------------------
   11. Full-bleed statement panels
   -------------------------------------------------------------------------- */
/* The photograph carried a large stretch of empty sky above the headline, which
   cost a screen of scrolling for nothing. Shorter frame, and the crop favours
   the lower part of the image where the board and the street are. */
.panel {
  position: relative;
  min-height: 68svh;
  display: flex; align-items: flex-end;
  overflow: hidden;
}
.panel__img { position: absolute; inset: 0; }
.panel__img img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 62%; filter: grayscale(.3) contrast(1.16) brightness(.55); }
/* Solid ink at both ends. The bottom edge always closed into the page, but the
   top stopped at 25% and left a hard horizontal seam where the photograph met
   the section above it. Now it reaches full ink at the top edge too, so the
   image arrives and leaves the same way. */
.panel__img::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to top,
    var(--ink) 2%,
    rgba(10,10,10,.45) 38%,
    rgba(10,10,10,.32) 62%,
    rgba(10,10,10,.52) 80%,
    rgba(10,10,10,.82) 92%,
    var(--ink) 100%);
}
.panel__body { position: relative; z-index: 2; width: 100%; padding-bottom: var(--pad); }
.panel__title { font-size: clamp(3.5rem, min(16vw, 18vh), 14rem); line-height: .82; letter-spacing: -.06em; }
/* This line sits under the largest type on the site. At body size it vanished
   next to it, which rather undercut a headline about being impossible to miss. */
.panel__note {
  margin-top: 1.75rem; max-width: 46ch; color: var(--ivory-2);
  font-size: clamp(1.125rem, 1.9vw, 1.625rem); line-height: 1.45;
}

/* --------------------------------------------------------------------------
   12. Three ideas: sparse
   -------------------------------------------------------------------------- */
.ideas { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gutter); margin-top: clamp(2.5rem, min(7vw, 7.5vh), 5.5rem); }
.idea { border-top: 1px solid var(--line); padding-top: 1.75rem; }
.section--ivory .idea { border-color: rgba(10,10,10,.16); }
.idea h3 { font-size: clamp(1.25rem, 2.2vw, 1.75rem); margin-bottom: 1rem; letter-spacing: -.03em; }
.idea p { color: var(--ivory-2); font-size: clamp(1.0625rem, 1.25vw, 1.1875rem); line-height: 1.55; }
.section--ivory .idea p { color: rgba(10,10,10,.66); }

/* --------------------------------------------------------------------------
   13. Reach estimator
   Every figure it prints is derived from the same LOCATIONS data as the rest
   of the site, so it can never drift away from what the board pages claim.
   -------------------------------------------------------------------------- */
.reach {
  display: grid; grid-template-columns: 1fr .9fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
  margin-top: clamp(2rem, min(6vw, 5.5vh), 4rem);
}

.reach__field { border-top: 1px solid var(--line); padding-top: 1.25rem; margin-bottom: 2.5rem; }
.reach__head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: 1.25rem; }
.reach__lab {
  font-family: var(--util); font-weight: 600; font-size: .875rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ivory-2);
}
.reach__val {
  font-family: var(--display); font-weight: 800; font-size: 1.25rem;
  letter-spacing: -.02em; color: var(--accent);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.reach__note { font-size: .875rem; color: var(--ivory-3); margin: .75rem 0 0; }

.reach__select {
  width: 100%; background: transparent; color: var(--ivory);
  border: 1px solid var(--line-2);
  font-family: var(--body); font-size: 1.0625rem;
  padding: .9375rem 2.75rem .9375rem 1rem; min-height: 54px;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F2EFE9' stroke-opacity='.5' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 1rem center; background-size: 18px;
  transition: border-color .25s var(--ease);
}
.reach__select:hover { border-color: var(--ivory-2); }
.reach__select:focus { outline: none; border-color: var(--accent); }
.reach__select option { background: var(--ink-soft); color: var(--ivory); }

/* margin: 0 matters. Chrome's UA sheet puts 2px of margin on a range input, so
   width:100% made the slider 4px wider than its own column and it sat 2px
   proud of the select stacked above it. */
.reach__range { width: 100%; margin: 0; background: transparent; appearance: none; height: 24px; cursor: pointer; }
.reach__range:focus { outline: none; }
.reach__range:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; }
.reach__range::-webkit-slider-runnable-track { height: 2px; background: var(--line-2); }
.reach__range::-webkit-slider-thumb {
  appearance: none; width: 20px; height: 20px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--ivory);
  margin-top: -9px;
}
.reach__range::-moz-range-track { height: 2px; background: var(--line-2); }
.reach__range::-moz-range-thumb {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--ivory);
}
.reach__ends {
  display: flex; justify-content: space-between; margin-top: .625rem;
  font-family: var(--util); font-weight: 500; font-size: .8125rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ivory-3);
}

/* The sourcing note lives in the left column under the slider: it fills the
   space the controls leave, and it sits beside the figures it explains. */
.reach__src {
  border-top: 1px solid var(--line);
  padding-top: 1.25rem; margin: 0;
  font-size: .8125rem; line-height: 1.65; color: var(--ivory-3);
}
.reach__src b { color: var(--ivory-2); font-weight: 600; }
.reach__src cite { font-style: normal; }

/* The results panel is the only lifted surface in the section, so the eye
   lands on the numbers before the controls. */
.reach__panel { background: var(--ink-soft); border: 1px solid var(--line-2); padding: clamp(1.75rem, 3vw, 2.5rem); }
.reach__k {
  font-family: var(--util); font-weight: 600; font-size: .8125rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ivory-3);
  margin: 0;
}
.reach__big {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(2.75rem, 6vw, 4.5rem); line-height: .9;
  letter-spacing: -.05em; font-variant-numeric: tabular-nums;
  margin: .875rem 0 .625rem;
}
.reach__mid {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(1.75rem, 3.6vw, 2.75rem); line-height: .95;
  letter-spacing: -.045em; font-variant-numeric: tabular-nums;
  margin: .75rem 0 .5rem;
}
.reach__mid--accent { color: var(--accent); }
.reach__sub { font-size: .875rem; color: var(--ivory-3); margin: 0; }
.reach__cell { border-top: 1px solid var(--line); margin-top: 1.75rem; padding-top: 1.5rem; }
.reach__go { width: 100%; margin-top: 2rem; }

@media (max-width: 900px) {
  .reach { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   14. Process
   -------------------------------------------------------------------------- */
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gutter); margin-top: clamp(2.5rem, min(7vw, 7vh), 5rem); }
.step { border-top: 1px solid var(--line); padding-top: 1.5rem; }
.section--ivory .step { border-color: rgba(10,10,10,.16); }
.step__n { font-family: var(--util); font-weight: 700; font-size: 1.0625rem; letter-spacing: .1em; color: var(--accent); }
.step__t {
  font-family: var(--display); font-weight: 800;
  font-size: clamp(1.0625rem, 1.7vw, 1.375rem);
  text-transform: uppercase; letter-spacing: -.025em;
  margin-top: 1.25rem; line-height: 1.05;
}

/* --------------------------------------------------------------------------
   15. Map: unchanged in behaviour, dressed to match
   -------------------------------------------------------------------------- */
.map-shell { position: relative; border: 1px solid var(--line); overflow: hidden; margin-top: clamp(2rem, min(6vw, 5.5vh), 4rem); }
.map-layout { display: grid; grid-template-columns: 340px 1fr; min-height: 600px; }

.map-list { border-right: 1px solid var(--line); background: var(--ink-soft); max-height: 600px; overflow-y: auto; }
.map-list__head { padding: 1.75rem; border-bottom: 1px solid var(--line); position: sticky; top: 0; background: var(--ink-soft); z-index: 2; }
/* Both, because the map heading is an h3 under a section heading on the
   homepage but has to be an h2 on the network page, where the page title is
   the h1 and the board names below it are h2s. */
.map-list__head h2, .map-list__head h3 { font-size: 1.375rem; letter-spacing: -.03em; }
.map-list__head p { font-family: var(--util); font-weight: 600; font-size: .8125rem; letter-spacing: .14em; text-transform: uppercase; color: var(--ivory-3); margin: .75rem 0 0; }

.map-item {
  display: block; width: 100%; text-align: left;
  padding: 1.5rem 1.75rem;
  background: none; border: 0; border-bottom: 1px solid var(--line);
  border-left: 2px solid transparent;
  color: inherit; cursor: pointer;
  transition: background .3s var(--ease), border-color .3s var(--ease);
}
.map-item:hover { background: var(--ink-lift); }
.map-item.is-active { background: var(--ink-lift); border-left-color: var(--accent); }
.map-item__name { display: block; font-family: var(--display); font-weight: 800; font-size: 1.1875rem; text-transform: uppercase; letter-spacing: -.025em; line-height: 1.15; }
.map-item__city { display: block; font-family: var(--util); font-weight: 700; font-size: .8125rem; letter-spacing: .14em; text-transform: uppercase; color: var(--accent); margin-top: .5rem; }
.map-item__imp { display: block; font-family: var(--util); font-weight: 500; font-size: .9375rem; color: var(--ivory-2); margin-top: .625rem; font-variant-numeric: tabular-nums; }

#tnb-map { width: 100%; height: 100%; min-height: 600px; background: var(--ink-lift); z-index: 1; }

/* Neutral dark base so the pins are the only colour on it */
.leaflet-tile-pane { filter: invert(1) grayscale(1) brightness(.86) contrast(1.05); }
.leaflet-container { background: var(--ink-lift) !important; font-family: var(--body) !important; }
.leaflet-control-attribution { background: rgba(10,10,10,.9) !important; color: var(--ivory-3) !important; font-size: 11px !important; }
.leaflet-control-attribution a { color: var(--ivory-2) !important; }
.leaflet-bar a { background: var(--ink-soft) !important; color: var(--ivory) !important; border-color: var(--line-2) !important; }
.leaflet-bar a:hover { background: var(--ink-edge) !important; }

/* Unnumbered by design. A number on a pin implies a ranking or a legend the
   visitor then has to go and find; the list beside the map already names them. */
.tnb-pin {
  display: grid; place-items: center;
  width: 30px; height: 30px;
  background: var(--accent);
  border: 2px solid var(--ivory);
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  box-shadow: 0 4px 16px rgba(0,0,0,.7);
  transition: background .25s var(--ease), transform .25s var(--ease);
}
.tnb-pin::after {
  content: ''; width: 8px; height: 8px; border-radius: 50%;
  background: var(--ivory);
  transition: background .25s var(--ease);
}
.tnb-pin.is-active {
  background: var(--ivory);
  transform: rotate(-45deg) scale(1.18);
}
.tnb-pin.is-active::after { background: var(--accent); }

.leaflet-popup-content-wrapper {
  background: var(--ink-soft) !important; color: var(--ivory) !important;
  border: 1px solid var(--line-2) !important; border-radius: 0 !important;
  box-shadow: 0 24px 60px -20px rgba(0,0,0,.95) !important;
}
.leaflet-popup-tip { background: var(--ink-soft) !important; border: 1px solid var(--line-2) !important; }
.leaflet-popup-content { margin: 16px 18px !important; line-height: 1.5 !important; }
.leaflet-popup-close-button { color: var(--ivory-3) !important; }

.pop__coords { font-family: var(--util); font-weight: 700; font-size: .75rem; letter-spacing: .14em; color: var(--accent); text-transform: uppercase; }
.pop__name { font-family: var(--display); font-weight: 900; font-size: 1.25rem; text-transform: uppercase; margin: .5rem 0 .25rem; letter-spacing: -.03em; }
.pop__city { color: var(--ivory-3); font-size: .875rem; }
.pop__imp { font-family: var(--util); font-weight: 500; font-size: .875rem; color: var(--ivory); margin-top: .75rem; font-variant-numeric: tabular-nums; }
.pop__status { margin-top: .875rem; }
.pop__link {
  display: inline-block; margin-top: .875rem;
  font-family: var(--display); font-size: .8125rem; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; color: var(--accent);
  border-bottom: 1px solid var(--accent); padding-bottom: 2px;
}

.map-fallback { padding: 2rem; text-align: center; color: var(--ivory-3); font-family: var(--util); font-weight: 500; font-size: .9375rem; }

/* Scroll-to-zoom is armed on hover, so the map says so until it is armed.
   Without the hint the first scroll over the map looks like a page bug. */
.map-hint {
  position: absolute; left: 50%; bottom: 1.25rem; transform: translateX(-50%);
  z-index: 500; pointer-events: none;
  padding: .625rem 1.125rem;
  background: rgba(10,10,10,.88);
  border: 1px solid var(--line-2);
  font-family: var(--util); font-weight: 600; font-size: .8125rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ivory-2);
  opacity: 0; transition: opacity .35s var(--ease);
}
.map-hint.is-shown { opacity: 1; }

/* --------------------------------------------------------------------------
   16. Location detail pages
   -------------------------------------------------------------------------- */
/* The render and the headline figures are one composition, not two sections.
   The wrapper takes 96% of the screen: the render still owns the first view,
   with a sliver left under the figures so they do not sit flush on the bottom
   edge and the page reads as continuing. The strip takes the height it needs
   and the render absorbs the remainder, which is what keeps the figures above
   the fold on a 13-inch laptop and a 27-inch monitor alike. */
.board-top { min-height: 96svh; display: flex; flex-direction: column; }
.board-top .spec-strip { flex: none; }

.detail-hero {
  position: relative;
  flex: 1 1 auto; min-height: 300px;
  display: flex; align-items: flex-end;
  overflow: hidden; padding-top: var(--nav-h);
}
.detail-hero__img { position: absolute; inset: 0; }
.detail-hero__img img { width: 100%; height: 100%; object-fit: cover; filter: grayscale(.28) contrast(1.14) brightness(.6); }
.detail-hero__img::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to top, var(--ink) 1%, rgba(10,10,10,.6) 42%, rgba(10,10,10,.3) 100%);
}
.detail-hero__over { position: relative; z-index: 2; width: 100%; padding-bottom: clamp(2rem, 4vw, 3.75rem); }
.detail-hero__label { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.25rem; }
.detail-hero__label .status { margin-left: .25rem; }
.detail-hero__latlng { color: var(--ivory-3); }
.detail-hero__title { font-size: clamp(2.5rem, min(7.5vw, 9vh), 6.5rem); letter-spacing: -.055em; line-height: .86; }
/* Wide enough to hold the longest of the five on one line at desktop widths. */
.detail-hero__sub { margin-top: 1.25rem; color: var(--ivory-2); max-width: 82ch; font-size: clamp(1.0625rem, 1.5vw, 1.375rem); }

.spec-strip { display: grid; grid-template-columns: repeat(4, 1fr); border-bottom: 1px solid var(--line); }
.spec-strip__cell { padding: clamp(1.25rem, 2.2vw, 1.875rem) var(--gutter); border-left: 1px solid var(--line); }
.spec-strip__cell:first-child { border-left: 0; }
.spec-strip__v {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(1.375rem, 2.9vw, 2.25rem);
  line-height: .95; letter-spacing: -.045em; font-variant-numeric: tabular-nums;
  text-wrap: balance;
}
.spec-strip__v em { font-style: normal; color: var(--accent); }
.spec-strip__k { margin-top: .625rem; }

.detail-cols { display: grid; grid-template-columns: 1.2fr .8fr; gap: clamp(3rem, 7vw, 6rem); align-items: start; }

.prose p { color: var(--ivory-2); font-size: clamp(1.0625rem, 1.4vw, 1.3125rem); line-height: 1.6; }
.prose strong { color: var(--ivory); font-weight: 600; }

.reasons { list-style: none; margin: clamp(2rem, 4vw, 3rem) 0 0; padding: 0; }
.reasons li {
  padding: 1.1875rem 0;
  border-top: 1px solid var(--line);
  color: var(--ivory);
  font-size: 1.0625rem;
  display: flex; gap: 1rem;
}
.reasons li::before { content: ''; flex: none; width: 6px; height: 6px; background: var(--accent); margin-top: .5rem; }

.spec-table { width: 100%; border-collapse: collapse; border: 1px solid var(--line); }
.spec-table caption {
  text-align: left; padding: 1.375rem 1.5rem;
  font-family: var(--display); font-weight: 800; font-size: 1.0625rem;
  text-transform: uppercase; letter-spacing: -.01em;
  border-bottom: 1px solid var(--line);
}
.spec-table th, .spec-table td { padding: 1.0625rem 1.5rem; text-align: left; border-bottom: 1px solid var(--line); font-size: .9375rem; vertical-align: top; }
.spec-table tr:last-child th, .spec-table tr:last-child td { border-bottom: 0; }
.spec-table th { font-family: var(--util); font-weight: 600; font-size: .8125rem; letter-spacing: .12em; text-transform: uppercase; color: var(--ivory-3); width: 42%; }
.spec-table td { font-family: var(--body); color: var(--ivory); font-variant-numeric: tabular-nums; }

/* The spec sheet is the single most-wanted asset on a board page, so it gets
   the weight of a primary control and sits above the table, not under it. */
.spec-dl {
  display: flex; align-items: center; gap: 1.25rem; width: 100%;
  margin-bottom: 2rem; padding: 1.625rem 1.75rem;
  background: var(--ink-soft);
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--accent);
  text-align: left; cursor: pointer;
  color: inherit; font: inherit;
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.spec-dl:hover { border-color: var(--ivory); border-left-color: var(--accent); background: var(--ink-lift); }
.spec-dl__icon { width: 26px; height: 26px; color: var(--accent); flex: none; }
.spec-dl__go { width: 20px; height: 20px; color: var(--ivory-3); flex: none; margin-left: auto; transition: transform .3s var(--ease), color .3s var(--ease); }
.spec-dl:hover .spec-dl__go { color: var(--ivory); transform: translateX(4px); }
.spec-dl span { min-width: 0; }
.spec-dl b { display: block; font-family: var(--display); font-weight: 800; font-size: 1.125rem; text-transform: uppercase; letter-spacing: -.01em; }
.spec-dl i { display: block; font-style: normal; font-family: var(--util); font-weight: 600; font-size: .8125rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ivory-3); margin-top: .5rem; }

/* PDF viewer overlay */
.sheet { position: fixed; inset: 0; z-index: 200; display: none; }
.sheet.is-open { display: block; }
.sheet__scrim { position: absolute; inset: 0; background: rgba(5,5,5,.86); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.sheet__box {
  position: absolute; inset: clamp(1rem, 4vw, 3rem);
  display: flex; flex-direction: column;
  background: var(--ink-soft); border: 1px solid var(--line-2);
  box-shadow: 0 40px 120px -30px rgba(0,0,0,.95);
}
.sheet__bar { display: flex; align-items: center; gap: 1rem; padding: 1.125rem 1.375rem; border-bottom: 1px solid var(--line); flex: none; }
.sheet__title { font-family: var(--display); font-weight: 800; font-size: 1.0625rem; text-transform: uppercase; letter-spacing: -.02em; margin-right: auto; }
.sheet__act {
  font-family: var(--util); font-weight: 600; font-size: .8125rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ivory-2); border-bottom: 1px solid var(--line-2); padding-bottom: 3px;
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.sheet__act:hover { color: var(--accent); border-color: var(--accent); }
.sheet__close {
  width: 40px; height: 40px; flex: none;
  background: none; border: 1px solid var(--line-2); color: var(--ivory-2);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.sheet__close:hover { color: var(--ivory); border-color: var(--ivory); }
.sheet__close svg { width: 16px; height: 16px; }
.sheet__frame { flex: 1 1 auto; min-height: 0; border: 0; width: 100%; background: var(--ink-lift); }
body.sheet-open { overflow: hidden; }

.anchors { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: clamp(1.5rem, 3vw, 2.25rem); }
.anchor {
  font-family: var(--util); font-weight: 600; font-size: .875rem; letter-spacing: .06em;
  padding: .5625rem .875rem; border: 1px solid var(--line); color: var(--ivory-2);
}

.mini-map { height: 360px; border: 1px solid var(--line); overflow: hidden; margin-top: 1rem; }
.mini-map > div { height: 100%; width: 100%; }

.board-nav { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; margin-top: clamp(2.5rem, min(8vw, 9vh), 7rem); background: var(--line); border-block: 1px solid var(--line); }
.board-nav__item { padding: clamp(1.75rem, 3.5vw, 2.5rem); background: var(--ink); transition: background .3s var(--ease); }
.board-nav__item:hover { background: var(--ink-soft); }
.board-nav__item--next { text-align: right; }
.board-nav__k { font-family: var(--util); font-weight: 600; font-size: .8125rem; letter-spacing: .14em; text-transform: uppercase; color: var(--ivory-3); }
.board-nav__v { font-family: var(--display); font-weight: 900; font-size: clamp(1.25rem, 2.6vw, 1.9375rem); text-transform: uppercase; margin-top: .875rem; letter-spacing: -.04em; }

/* --------------------------------------------------------------------------
   17. Forms
   -------------------------------------------------------------------------- */
.form-layout { display: grid; grid-template-columns: 1.1fr .9fr; gap: clamp(3rem, 7vw, 6rem); align-items: start; }

.field { margin-bottom: 1.75rem; }
.field label { display: block; font-family: var(--util); font-weight: 600; font-size: .875rem; letter-spacing: .12em; text-transform: uppercase; color: var(--ivory-2); margin-bottom: .75rem; }
.field .req { color: var(--accent-text); }

.field input, .field select, .field textarea {
  width: 100%;
  background: transparent;
  border: 0; border-bottom: 1px solid var(--line-2);
  color: var(--ivory);
  font-family: var(--body); font-size: 1.0625rem;
  padding: .875rem 0;
  min-height: 52px;
  transition: border-color .3s var(--ease);
}
.field textarea { min-height: 120px; resize: vertical; line-height: 1.6; }
.field select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F2EFE9' stroke-opacity='.5' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .25rem center; background-size: 18px;
  padding-right: 2.5rem;
  color: var(--ivory);
}
.field select option { background: var(--ink-soft); color: var(--ivory); }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--ivory-2); }
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--accent); }
.field input::placeholder, .field textarea::placeholder { color: var(--ivory-3); }

.field__help { font-size: .8125rem; color: var(--ivory-3); margin-top: .625rem; }
.field__err { display: none; font-size: .8125rem; color: var(--accent-text); margin-top: .625rem; font-weight: 500; }
.field.is-bad input, .field.is-bad select, .field.is-bad textarea { border-color: var(--accent); }
.field.is-bad .field__err { display: block; }

.form-note { font-size: .8125rem; color: var(--ivory-3); margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid var(--line); }

.form-status { display: none; padding: 1.25rem 1.5rem; margin-bottom: 1.75rem; font-size: .9375rem; border: 1px solid transparent; }
.form-status.is-shown { display: block; }
.form-status--ok { border-color: var(--ivory); color: var(--ivory); background: var(--ink-soft); }
.form-status--bad { border-color: var(--accent); color: var(--accent-text); background: var(--ink-soft); }

.error-summary { display: none; padding: 1.25rem 1.5rem; border: 1px solid var(--accent); margin-bottom: 1.75rem; background: var(--ink-soft); }
.error-summary.is-shown { display: block; }
.error-summary h2 { font-size: .875rem; color: var(--accent-text); margin-bottom: .875rem; letter-spacing: .02em; }
.error-summary ul { margin: 0; padding-left: 1.125rem; }
.error-summary li { font-size: .875rem; margin-bottom: .375rem; }
.error-summary a { color: var(--accent-text); text-decoration: underline; }

.contact-card { border-top: 1px solid var(--line); padding: 1.75rem 0; }
.contact-card__k { font-family: var(--util); font-weight: 600; font-size: .875rem; letter-spacing: .12em; text-transform: uppercase; color: var(--ivory-3); margin-bottom: 1rem; }
.contact-card__v { font-family: var(--display); font-weight: 800; font-size: 1.375rem; letter-spacing: -.03em; word-break: break-word; }
.contact-card__v a { border-bottom: 1px solid var(--line-2); }
.contact-card__v a:hover { color: var(--accent); border-color: var(--accent); }

/* --------------------------------------------------------------------------
   18. Final CTA
   -------------------------------------------------------------------------- */
.cta { position: relative; overflow: hidden; border-top: 1px solid var(--line); }
/* The headline is left and the copy plus buttons sit at the bottom right, so
   the close uses the full width instead of stacking down one edge. Baselines
   align at the foot of the headline. */
.cta__inner {
  padding-block: var(--pad);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 26rem);
  gap: clamp(1.75rem, 4vw, 4.5rem);
  align-items: end;
}
.cta__aside { padding-bottom: .375rem; }
.cta__aside .lede { max-width: none; }
/* In a narrow column the two buttons wrap to different widths, which reads as
   an accident. Stacked and filled, they line up as a pair. */
.cta__aside .btn-row { flex-direction: column; }
.cta__aside .btn { width: 100%; }
.cta__title { font-size: clamp(3rem, min(14vw, 16vh), 12rem); line-height: .84; letter-spacing: -.06em; }


/* --------------------------------------------------------------------------
   19. Footer: minimal
   -------------------------------------------------------------------------- */
.foot { border-top: 1px solid var(--line); padding-block: var(--join) 1.5rem; }

/* A wordmark on one edge and links on the other left the middle of every page
   ending in empty black. The brand block now carries the contact details under
   it and shares one wrapping row with the two link columns, so nothing is left
   as the short column. Flex, not grid: the columns are sized by their content
   and wrap on their own, which is why there are no track definitions here. */
/* space-between split the free space into two equal gaps, which threw the two
   link columns to opposite ends of the footer and made them read as unrelated.
   An auto margin after the brand AND after the last column splits the slack in
   two instead: Network and Company stay together as one pair with a single
   deliberate gap, and the leftover space sits either side of that pair rather
   than piling up in one hole in the middle. */
.foot__top {
  display: flex; justify-content: flex-start; flex-wrap: wrap;
  column-gap: clamp(2.5rem, 5vw, 5rem);
  row-gap: clamp(2rem, 4vw, 3.5rem);
  padding-bottom: clamp(2rem, 3.5vw, 3rem);
}
.foot__id { margin-right: auto; }
.foot__col:last-child { margin-right: auto; }

/* The illustrated mark used to sit to the left of this block. It is gone, so
   the type starts at the column edge and the wordmark carries the brand here
   the same way it does in the header. */
.foot__id { max-width: 30rem; }
/* The same lockup as the header: both lines at one size and one cap height,
   the width difference made by opening up TRUE NORTH, BILLBOARDS centred under
   it. max-content keeps the block itself flush left in the footer column while
   the two lines centre against each other, which is what the flex container in
   the header gets for free by being a flex item. */
.foot__brand {
  display: flex; flex-direction: column; align-items: center;
  width: max-content;
  font-family: var(--display); font-weight: 900;
  font-size: clamp(1.5rem, 2.6vw, 2rem);
  letter-spacing: -.035em; text-transform: uppercase; line-height: .9;
  margin: 0;
}
.foot__brand span:first-child { letter-spacing: .037em; }
/* Same treatment as the header wordmark: the second line carries the accent,
   so the brand reads identically at the top and the bottom of every page.
   :last-child, not a bare span selector. Both lines are wrapped now, so an
   unqualified rule turns TRUE NORTH red as well. */
.foot__brand span:last-child { color: var(--accent); }

.foot__mail { margin: 0 0 1.5rem; }
/* inline-block plus padding for the same reason as the footer nav links: as a
   bare inline link this measured 21px tall, under the 24px pointer-target
   minimum, and it is one of the two ways to actually make contact. */
.foot__mail a {
  display: inline-block; padding-block: 3px;
  font-family: var(--display); font-weight: 700; font-size: 1rem;
  letter-spacing: -.015em; color: var(--ivory);
  border-bottom: 1px solid var(--line-2); word-break: break-word;
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.foot__mail a:hover { color: var(--accent); border-color: var(--accent); }
.foot__btn { width: 100%; max-width: 17rem; min-height: 50px; padding: 1rem 1.25rem; font-size: .875rem; gap: 1.25rem; }

@media (max-width: 1100px) {
  .foot__top { row-gap: clamp(2rem, 4vw, 3rem); }
}
/* h3, not h4. The last content heading on every page is an h2, so an h4 here
   skipped a level for anyone navigating by heading. */
.foot__col h3, .foot__k { font-family: var(--util); font-weight: 700; font-size: .875rem; letter-spacing: .14em; color: var(--ivory-3); margin-bottom: 1.125rem; text-transform: uppercase; }
/* A label belongs to the value under it, so it sits tight to the email and the
   whole pair gets its air above instead. Previously the label was 28px below
   the wordmark and 24px above its own email, so it read as floating between
   two things rather than belonging to one. */
.foot__k { margin: 2rem 0 .625rem; }
.foot__col ul { list-style: none; margin: 0; padding: 0; }
.foot__col li { margin-bottom: .5625rem; }
/* inline-block plus the padding takes the tap target from 20px to 31.6px, past
   the 24px minimum on its own rather than leaning on the spacing exception.
   It costs about 25px of footer height, which is the trade. */
.foot__col a { display: inline-block; padding-block: 3px; font-size: 1rem; color: var(--ivory-2); transition: color .25s var(--ease); }
.foot__col a:hover { color: var(--accent); }
.foot__bottom { border-top: 1px solid var(--line); padding-top: 1.75rem; display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; font-family: var(--util); font-weight: 500; font-size: .8125rem; letter-spacing: .1em; color: var(--ivory-3); text-transform: uppercase; }

/* --------------------------------------------------------------------------
   19b. Booking bar
   Appears once the hero is behind you and retires when the closing CTA
   arrives, so it never competes with the page's own call to action.
   -------------------------------------------------------------------------- */
.bookbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
  background: rgba(10,10,10,.92);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border-top: 1px solid var(--line-2);
  transform: translateY(101%);
  transition: transform .5s var(--ease);
}
.bookbar.is-up { transform: none; }
html.bookbar-up { scroll-padding-bottom: 11rem; }

.bookbar__inner {
  width: 100%; max-width: var(--wrap); margin-inline: auto;
  padding: 1rem var(--gutter);
  display: flex; align-items: center; gap: 1.25rem;
}

.bookbar__txt { flex: none; }
.bookbar__k {
  font-family: var(--util); font-weight: 700; font-size: .875rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--ivory);
  margin: 0;
}
.bookbar__sub {
  font-size: .875rem; color: var(--ivory-3); margin: .25rem 0 0;
}

.bookbar__select {
  flex: 1 1 auto; min-width: 0; max-width: 30rem;
  background: transparent; color: var(--ivory);
  border: 1px solid var(--line-2);
  font-family: var(--body); font-size: 1rem;
  padding: .875rem 2.75rem .875rem 1rem;
  min-height: 52px;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F2EFE9' stroke-opacity='.5' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 1rem center; background-size: 18px;
  transition: border-color .25s var(--ease);
}
.bookbar__select:hover { border-color: var(--ivory-2); }
.bookbar__select:focus { outline: none; border-color: var(--accent); }
.bookbar__select option { background: var(--ink-soft); color: var(--ivory); }

.bookbar__go { flex: none; gap: 1.25rem; }

.bookbar__close {
  flex: none; width: 40px; height: 40px;
  background: none; border: 1px solid var(--line); color: var(--ivory-3);
  cursor: pointer; display: inline-flex; align-items: center; justify-content: center;
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.bookbar__close:hover { color: var(--ivory); border-color: var(--ivory); }
.bookbar__close svg { width: 14px; height: 14px; }

@media (max-width: 900px) {
  .bookbar__inner { flex-wrap: wrap; padding-block: .875rem; gap: .75rem; }
  .bookbar__txt { flex: 1 1 auto; }
  .bookbar__select { flex: 1 1 100%; max-width: none; order: 3; }
  .bookbar__go { flex: 1 1 100%; order: 4; width: 100%; justify-content: space-between; }
}
/* On a phone the bar was standing four rows tall and taking roughly a quarter
   of the screen for the whole scroll. The heading is dropped (the button says
   the same thing) and the picker shares its row with the dismiss control. */
@media (max-width: 640px) {
  .bookbar__inner { padding: .625rem var(--gutter) .75rem; gap: .5rem; }
  .bookbar__txt { display: none; }
  .bookbar__select { order: 1; flex: 1 1 auto; min-height: 46px; padding-block: .625rem; font-size: .9375rem; }
  .bookbar__close { order: 2; width: 46px; height: 46px; }
  .bookbar__go { order: 3; flex: 1 1 100%; min-height: 50px; padding-block: .875rem; font-size: .875rem; }
}

/* --------------------------------------------------------------------------
   20. Reveal
   -------------------------------------------------------------------------- */
/* Gated on the js class so the page degrades to fully visible content if
   the script never runs. Without the gate, a blocked or failed tnb.js
   leaves every animated block permanently at opacity 0. */
.js .reveal { opacity: 0; transform: translateY(28px); }
.js .reveal.is-in { opacity: 1; transform: none; transition: opacity .9s var(--ease), transform .9s var(--ease); }

/* Line-by-line type reveal for display headings.
   The padding/margin pair keeps tails (Q, J) from being clipped by overflow. */
.rise { display: block; overflow: hidden; padding-bottom: .09em; margin-bottom: -.09em; }
.rise > span { display: block; transition: transform 1s var(--ease); }
.js .rise > span { transform: translateY(105%); }
.js .is-in .rise > span, .js .rise.is-in > span { transform: none; }
.rise:nth-child(2) > span { transition-delay: .09s; }
.rise:nth-child(3) > span { transition-delay: .18s; }
.rise:nth-child(4) > span { transition-delay: .27s; }
.rise:nth-child(5) > span { transition-delay: .36s; }

/* --------------------------------------------------------------------------
   21. Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 1100px) {
  .detail-cols { grid-template-columns: 1fr; }
  .form-layout { grid-template-columns: 1fr; }
  .map-layout { grid-template-columns: 1fr; }
  .map-list { border-right: 0; border-bottom: 1px solid var(--line); max-height: 320px; }
  #tnb-map { min-height: 480px; }
  .steps { grid-template-columns: repeat(2, 1fr); row-gap: 2.5rem; }
}

@media (max-width: 1000px) {
  .cta__inner { grid-template-columns: 1fr; }
  .cta__aside { padding-bottom: 0; }
}

@media (max-width: 900px) {
  /* Phones cannot spare a 96px fixed header, so the bar and the name both
     come down a step. */
  :root { --nav-h: 76px; --nav-h-stuck: 62px; }
  .nav__wordmark { font-size: 1.3125rem; }
  .nav.is-stuck .nav__wordmark { font-size: 1.125rem; }

  .nav__links {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: flex-start;
    background: var(--ink); border-bottom: 1px solid var(--line);
    padding: 2rem var(--gutter) 2.5rem;
    gap: 1.5rem;
    display: none;
  }
  .nav__links.is-open { display: flex; }
  .nav__link { font-family: var(--display); font-weight: 800; font-size: 1.75rem; letter-spacing: -.04em; color: var(--ivory); }
  .nav__link::after { display: none; }
  .nav__toggle { display: inline-flex; }
  .nav__cta { display: none; }
  .nav.is-open-menu { background: var(--ink); }

  .figures { grid-template-columns: 1fr; row-gap: 2.5rem; }
  .ideas { grid-template-columns: 1fr; row-gap: 2.5rem; }
  .board-row { grid-template-columns: 1fr; gap: .5rem; }
  .board-row__i { display: none; }
  .board-row__fig { text-align: left; margin-top: 1rem; display: flex; align-items: baseline; gap: .75rem; }
  .board-row:hover .board-row__name { transform: none; }
  .spec-strip { grid-template-columns: repeat(2, 1fr); }
  .spec-strip__cell:nth-child(3) { border-left: 0; }
  .spec-strip__cell:nth-child(n+3) { border-top: 1px solid var(--line); }
}

/* Phones: the renders are wide landscape photographs. Cover-cropping them
   behind a tall portrait hero throws away the billboard, so give the image
   its own band and stand the type on solid ink beneath it. */
@media (max-width: 760px) {
  .hero {
    min-height: 0;
    display: block;
    padding-top: var(--nav-h);
  }
  .hero__media { position: relative; inset: auto; height: 46svh; min-height: 260px; }
  .hero__slide img { filter: grayscale(.2) contrast(1.12) brightness(.8); transform: none; }
  .hero__media::after {
    background: linear-gradient(to top, var(--ink) 1%, rgba(10,10,10,.25) 40%, rgba(10,10,10,.45) 100%);
  }
  .hero__body { padding-top: 2rem; padding-bottom: 3rem; }
  .hero__title { max-width: none; }
  .hero__foot { margin-top: 2rem; }

  .panel { min-height: 0; }
  .panel__img { position: relative; inset: auto; height: 42svh; min-height: 240px; }
  .panel__body { padding-top: 2rem; padding-bottom: 3rem; }

  /* Phones keep the render in its own band rather than cover-cropping a wide
     photograph behind tall type, but the band gives up height so the figures
     still land on the first screen. */
  .detail-hero { min-height: 0; display: block; }
  .detail-hero__img { position: relative; inset: auto; height: 30svh; min-height: 170px; }
  .detail-hero__over { padding-top: 1.5rem; padding-bottom: 1.75rem; }
  .detail-hero__title { font-size: clamp(2rem, 9vw, 3rem); }
  .detail-hero__label { margin-bottom: .875rem; }
  .detail-hero__sub { margin-top: .875rem; font-size: 1rem; }
}

@media (max-width: 640px) {
  .steps { grid-template-columns: 1fr; }
  .board-nav { grid-template-columns: 1fr; }
  .board-nav__item--next { text-align: left; }
  .btn { width: 100%; }
  .btn-row { flex-direction: column; }
  .hero__foot { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   22. Reduced motion
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  /* These have to carry the .js prefix. The base rules are `.js .reveal` and
     `.js .rise > span`, so an unprefixed override here loses on specificity and
     the block silently does nothing. */
  .js .reveal { opacity: 1; transform: none; }
  .js .rise > span { transform: none; }
  .hero__slot-fill { transform: scaleX(1); }
  .board-row:hover .board-row__name { transform: none; }
}

@media print {
  .nav, .cta, .map-shell { display: none; }
  body { background: #fff; color: #000; }
}
