/* IslandVia — shared public-site shell.
   Every public page links this and adds only page-specific rules after it.
   The masthead, footer, tokens, type scale and buttons live HERE and nowhere
   else: three hand-copied mastheads is what made the header jump 6px between
   pages, the CTA change size, and the wordmark lose its letter-spacing on one
   page. If a shell rule needs to differ per page, that is a bug in the rule.
*/

/* Self-hosted so no visitor IP reaches Google. Latin subsets only.
   Fraunces and Public Sans are variable fonts: one file each, several
   weight declarations pointing at it. */
/* latin */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
    font-display: swap;
  font-weight: 300;
  font-display: swap;
  src: url(/fonts/Fraunces-300.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
    font-display: swap;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/Fraunces-300.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
    font-display: swap;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/Fraunces-300.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin */
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
    font-display: swap;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/Fraunces-300.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
    font-display: swap;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/IBMPlexMono-400.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
    font-display: swap;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/IBMPlexMono-500.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin */
@font-face {
  font-family: 'Public Sans';
  font-style: normal;
    font-display: swap;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/PublicSans-400.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin */
@font-face {
  font-family: 'Public Sans';
  font-style: normal;
    font-display: swap;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/PublicSans-400.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin */
@font-face {
  font-family: 'Public Sans';
  font-style: normal;
    font-display: swap;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/PublicSans-400.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin */
@font-face {
  font-family: 'Public Sans';
  font-style: normal;
    font-display: swap;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/PublicSans-400.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* ---------- Tokens ---------- */
:root {
  --sand: #F7F3EC;
  --sand-deep: #EFE8D9;
  --ink: #16262B;
  --ink-soft: #3D4F54;
  --lagoon: #2F7D74;
  --lagoon-deep: #1F5C55;
  --brass: #B98A46;
  --coral: #E2694A;
  --line: #D9CFBB;
  --white: #FFFDF8;

  /* ---------- Measure, by role ----------
     Added 2026-09-08, as the foundation for the design pass.

     THE FAILURE THIS EXISTS TO FIX. Every text block on the site was capped
     in `ch`, and `ch` is relative to font size, and font size is a clamp with
     a vw middle. So the type reaches its maximum at about a 1137px viewport,
     19ch at 58px is 667px, and past that point NOTHING on the page responds
     to width at all. Measured at 1024, 1440 and 1728: the hero headline uses
     667 of 1120px, the body 521, the kicker 497. The page does not adapt to a
     wide screen, it just gets emptier — which is invisible on a phone, where
     container width and measure are the same number.

     A MEASURE CAP AND A COLUMN WIDTH ARE DIFFERENT THINGS, and the site only
     had the first. These four are the first half. The rule below is the half
     that was missing.

     Values are the ones the site already used where it used any; body is new,
     and it is the one that must not stretch — nine FAQ answers were running
     87 characters per line at 15px, the least readable combination available. */
     CALIBRATION, and it is the reason these are not the round numbers the
     roles suggest. `ch` is the width of a ZERO, not of an average character.
     In Public Sans a zero is ~0.61em while the average character is ~0.475em,
     so `66ch` renders 646px and fits EIGHTY-FIVE characters, not 66. Measured
     on a real answer, not assumed. Every value below is therefore set to the
     ch that produces the intended CHARACTER count, and the comment says which
     is which. If the body face ever changes, re-measure rather than convert. */
  --measure-display: 19ch;   /* headlines ~24 chars. short lines are the point */
  --measure-lede:    38ch;   /* ~48 chars: the sentence under a headline */
  --measure-body:    52ch;   /* ~66 chars: running prose, FAQ answers, step detail */
  --measure-caption: 40ch;   /* ~50 chars: figure notes, data annotations */

  /* THE RULE, and it is a rule about LAYOUT rather than about type:

       a column never exceeds its role's measure, and when the available
       width exceeds that measure by more than --measure-slack, the LAYOUT
       must change — narrow the container deliberately, split it into
       columns, or pair the text with a figure. Dead space is allowed only
       when it was chosen.

     Three legitimate answers, picked by role rather than by habit. NARROW is
     what the sub-pages do today, and why they read thin at 780px in a 1440px
     window. SPLIT keeps the measure right and uses the width. PAIR is why the
     ViaCube section is the best-working part of the home page on a laptop.

     And the useful consequence: A BREAKPOINT IS NOW DERIVED, NOT CHOSEN. The
     layout changes at the width where the container outgrows what the row
     needs. --nav-h's neighbour below is the worked example — that crossover
     has moved three times (720 -> 860 -> 760 -> 810), each time re-measured
     from what the row actually needs rather than reasoned from the last
     number. Do the same for any block this rule is applied to. */
  --measure-slack: 1.4;
}

/* ---------- Base ---------- */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
body {
  margin: 0;
  background: var(--sand);
  color: var(--ink);
  font-family: 'Public Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3 { font-family: 'Fraunces', Georgia, serif; font-weight: 500; margin: 0; color: var(--ink); }
a { color: inherit; }
img { max-width: 100%; }
.mono { font-family: 'IBM Plex Mono', ui-monospace, monospace; }
.eyebrow {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--lagoon-deep);
}
a:focus-visible, button:focus-visible {
  outline: 2px solid var(--lagoon); outline-offset: 2px;
}

/* ---------- Masthead: one definition, all pages ----------
   --nav-h is the masthead's rendered height: 16px padding twice, a 44px CTA,
   and the 1px bottom border. It is the same at every width — the CTA's
   min-height decides it, not the text — and /concierge subtracts it to size a
   hero that must end exactly at the fold. One home for the number, so a
   change to the padding or the CTA cannot silently push a headline off screen. */
:root { --nav-h: 79px; }
nav {
  position: sticky; top: 0; z-index: 50;
  background: rgba(247,243,236,0.92);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--line);
}
.nav-inner {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 24px; max-width: 1120px; margin: 0 auto;
}
.brand { font-family: 'Fraunces', Georgia, serif; font-size: 20px; font-weight: 600; letter-spacing: 0.01em; }
.brand span { color: var(--lagoon); }
.brand a { color: inherit; text-decoration: none; }
.nav-links { display: flex; gap: 16px; font-size: 14px; font-weight: 500; }
.nav-links a { text-decoration: none; color: var(--ink-soft); transition: color 0.15s; }
.nav-links a:hover { color: var(--lagoon-deep); }
.nav-links a[aria-current="page"] { color: var(--lagoon-deep); }
.nav-cta {
  background: var(--ink); color: var(--white); padding: 12px 16px; border-radius: 3px;
  font-size: 13.5px; font-weight: 600; text-decoration: none; white-space: nowrap;
  /* 44px min tap target (Apple HIG); was 40px tall */
  min-height: 44px; display: inline-flex; align-items: center;
}
/* The way back in for somebody who already has an account. Deliberately the
   quiet half of the pair: plain text against the CTA's filled block, so it is
   findable without competing with it. Wrapping the two keeps the row's
   space-between from stranding it mid-nav. */
.nav-end { display: flex; align-items: center; gap: 14px; }
.nav-signin {
  font-size: 13.5px; font-weight: 500; color: var(--ink-soft); text-decoration: none;
  white-space: nowrap; min-height: 44px; display: inline-flex; align-items: center;
  transition: color 0.15s;
}
.nav-signin:hover { color: var(--lagoon-deep); }
/* Below the crossover it moves into the hamburger — one door, not two side by
   side. Same breakpoint as .nav-links, so there is never a width with neither. */
@media (max-width: 770px) { .nav-signin { display: none; } }
/* Seven items since /proof was added. Between 720 and 900px the row wrapped
   and collided with the brand and CTA, so it tightens before it hides.
   Crossover moved 720 -> 860 on 2026-09-04, when Sign in joined the row: with
   the tightened gap the row needs 796px of content and had 673 at 721px, so it
   wrapped to three lines and the masthead grew from 78px to 99px. Measured, not
   guessed — and the band was already marginal before Sign in existed (the links
   took two rows at 721px on their own). Everything the row holds is in the menu
   below the crossover, so nothing is lost by hiding it earlier.

   Then 860 -> 760, same day, when "Why IslandVia" came out of the nav (the owner:
   seven items was already crowded enough to have forced the move above). Five
   links instead of six drops the row's requirement from 796px to 709px, so the
   band it needed is smaller again. Re-measured on the rendered page rather than
   reasoned backwards from the first number. 760 keeps ~50px of slack; going all
   the way back to 720 would restore the marginal state, which is what this
   comment exists to stop somebody doing.

   Then 760 -> 810 on 2026-09-08, when Duty joined the nav. Six links need
   756px, which "fits" inside 760 by FOUR PIXELS — the marginal state the
   paragraph above exists to warn against, arrived at from the other direction.
   Measured, not assumed: 810 restores ~54px of slack, the same air 760 gave
   five links. The rule this follows is in the desktop-pass document: the
   crossover is DERIVED from what the row needs, so adding or removing a nav
   item means re-measuring rather than hoping.

   Then 810 -> 770 the same evening, when FAQ LEFT the nav: the questions moved
   off the home page onto the two pages they belong to, so /#faq pointed at an
   anchor that no longer existed and a split FAQ has no single home to repoint
   at. Five links again, 713px needed, 770 gives ~57px of slack. Fourth move,
   same method every time — measure the row, then set the number. */
@media (max-width: 900px) { .nav-links { gap: 12px; } }
@media (max-width: 770px) { .nav-links { display: none; } }

/* ---------- Mobile menu ----------
   The nav links have been display:none under 720px since the first deploy,
   with no menu ever built in their place — phone visitors had no way between
   pages. Found by the owner on a phone, 2026-09-03. A <details> menu needs no
   JavaScript, so it cannot fail the way the contact form did. */
.nav-menu { display: none; }
.nav-menu > summary { list-style: none; cursor: pointer; min-height: 44px; min-width: 44px; display: inline-flex; align-items: center; justify-content: center; margin-left: 4px; }
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu .bars, .nav-menu .bars::before, .nav-menu .bars::after {
  display: block; width: 22px; height: 2px; background: var(--ink); border-radius: 1px;
}
.nav-menu .bars { position: relative; }
.nav-menu .bars::before, .nav-menu .bars::after { content: ''; position: absolute; left: 0; }
.nav-menu .bars::before { top: -7px; }
.nav-menu .bars::after { top: 7px; }
.nav-menu[open] .bars { background: transparent; }
.nav-menu[open] .bars::before { top: 0; transform: rotate(45deg); }
.nav-menu[open] .bars::after { top: 0; transform: rotate(-45deg); }
.menu-panel { position: absolute; left: 0; right: 0; top: 100%; background: var(--sand); border-bottom: 1px solid var(--line); box-shadow: 0 1px 0 var(--line); }
.menu-panel a { display: block; padding: 15px 24px; font-size: 16px; font-weight: 500; color: var(--ink); text-decoration: none; border-top: 1px solid var(--line); }
.menu-panel a[aria-current="page"] { color: var(--lagoon-deep); }
/* Last in the panel, quieter than the pages above it — same job as .nav-signin. */
.menu-panel a.menu-signin { color: var(--ink-soft); font-weight: 500; }
@media (max-width: 770px) { .nav-menu { display: block; } }

/* ---------- Shared buttons ---------- */
.btn-stamp {
  background: var(--coral); color: var(--ink); text-decoration: none;
  padding: 13px 24px; border-radius: 3px; font-weight: 600; font-size: 15px;
  display: inline-block;
}

/* ---------- Footer: one definition, all pages ---------- */
/* Phone and email links sat at 17px tall, under the 24x24 minimum. Padding
   rather than a bigger font, so the sentence they live in still reads. */
a[href^="tel:"], a[href^="mailto:"] { display: inline-block; padding: 4px 0; }

footer { border-top: 1px solid var(--line); padding: 34px 24px; }
.footer-inner {
  max-width: 1120px; margin: 0 auto;
  display: flex; justify-content: space-between; align-items: center;
  gap: 16px; flex-wrap: wrap;
}
.footer-inner .brand { font-size: 16px; }
footer p { font-size: 13.5px; color: var(--ink-soft); margin: 0; }
footer p a { display: inline-block; padding: 6px 2px; }

/* ---------- Shared mobile tightening (§43) ----------
   Both subpages use .page for the intro block and <section> for the body.
   On a phone the desktop padding spends most of the first viewport on
   whitespace before the headline. */
@media (max-width: 720px) {
  .page { padding: 28px 18px 20px !important; }
  .page h1 { font-size: 30px !important; line-height: 1.12; }
  .page .lede { font-size: 16.5px; }
  section { padding: 0 18px; }
  .sec-head { margin: 40px 0 16px !important; padding-top: 22px !important; }
  .close { padding: 44px 18px !important; }
}

/* X25, 2026-10-14. A standalone secondary ask must be tappable on a phone.
   Measured at 375 before the fix: "Ask about a project" 25px, "Questions
   about cost" 18px, "Questions about the journey" 43px, the container-cost
   door 19px, concierge's "Or talk to us about the project" 32px.

   IT TARGETS THE ASK CLASSES, NOT LINKS IN PROSE, AND THAT IS DELIBERATE.
   47 further anchors measure under 44px site-wide and every one of them sits
   inside a sentence — "the FAQ", "hello@islandvia.com", "The full breakdown
   is here" mid-paragraph. WCAG 2.5.8 exempts a target "in a sentence or
   block of text", and padding them to 44px would wreck the line rhythm of
   every page to satisfy a rule that does not apply to them. */
@media (max-width: 760px) {
  .quiet-link,
  .second-ask,
  .cube-more > a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}
