/* Renate Marcus -- The Elsewhere Girl
   ---------------------------------------------------------------------------
   Ported from the approved prototype. Two things are resolved at request time
   rather than written here:

   --hero-img   the hero photograph, found by PHP in assets/hero/ and injected
                into the page head. It feeds the home hero AND the frosted strip
                behind the nav on gallery pages, so replacing that one file
                changes both. The value below is only a safety net for when the
                folder is empty.

   the img sizes attribute in lib/render.php restates the grid measurements from
                the .gallery rules further down. THE TWO ARE A PAIR -- change the
                columns or the gutters here and that constant must follow, or the
                browser will pick the wrong size thumbnail.
   --------------------------------------------------------------------------- */

/* Fonts are served from this site, not Google's: loading them from Google
   would hand every visitor's IP address over before they had been asked. */
@font-face{font-family:"Indie Flower";font-style:normal;font-weight:400;font-display:swap;
  src:url("../fonts/indie-flower-normal-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Indie Flower";font-style:normal;font-weight:400;font-display:swap;
  src:url("../fonts/indie-flower-normal-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Instrument Sans";font-style:italic;font-weight:400 700;font-display:swap;
  src:url("../fonts/instrument-sans-italic-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Instrument Sans";font-style:italic;font-weight:400 700;font-display:swap;
  src:url("../fonts/instrument-sans-italic-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"Instrument Sans";font-style:normal;font-weight:400 700;font-display:swap;
  src:url("../fonts/instrument-sans-normal-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Instrument Sans";font-style:normal;font-weight:400 700;font-display:swap;
  src:url("../fonts/instrument-sans-normal-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:400;font-display:swap;
  src:url("../fonts/ibm-plex-mono-400-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:400;font-display:swap;
  src:url("../fonts/ibm-plex-mono-400-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:500;font-display:swap;
  src:url("../fonts/ibm-plex-mono-500-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:500;font-display:swap;
  src:url("../fonts/ibm-plex-mono-500-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
:root{
  --hero-img:none;
  /* room kept under a lightbox photograph for its caption plus the gap above
     it. Generous enough for three wrapped lines; captions are normally one. */
  --lb-cap-space:clamp(70px,11vh,124px);
  /* breathing room around a lightbox photograph. Used by the overlay padding,
     the photograph's height cap and the counter, so they cannot drift apart. */
  --lb-pad:clamp(12px,3vw,48px);
  --ink:#3A3A38;
  --ink-soft:#6E6E6A;
  --paper:#FFFFFF;
  --placeholder:#D9D9D9;
  --nav-h:clamp(56px,9vh,84px);
  --pill-h:clamp(38px,6.4vh,52px);
  --gutter:clamp(14px,3.2vw,50px);
  --page-x:clamp(16px,4vw,76px);
  --hero-inset:clamp(14px,5.5vmin,96px);
  --radius-tile:clamp(12px,1.6vw,26px);
  --font-body:"Instrument Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Arial,sans-serif;
  --font-display:"Indie Flower",cursive;
  --font-mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
  /* home page: travel documents and the departures board */
  --ink-faint:rgba(58,58,56,.5);
  --paper-tint:#F6F4EF;          /* ticket stubs */
  --hairline:rgba(58,58,56,.16);
  --stamp:#B5412F;               /* rubber-stamp red */
  --board:#1D1D1B;               /* same near-black as the favicon */
  --flap-ink:#F2EFE6;
  --amber:#F2B53C;
  --radius-card:clamp(12px,1.6vw,22px);
  --ease:cubic-bezier(.22,.61,.36,1);
}
*,*::before,*::after{box-sizing:border-box}
html,body{margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{
  font-family:var(--font-body);color:var(--ink);background:var(--paper);
  font-optical-sizing:auto;font-variation-settings:"wdth" 100;
  font-size:clamp(15px,1.05vw,18px);line-height:1.5;
  overflow-x:hidden;
}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer}
:focus-visible{outline:2px solid #fff;outline-offset:3px;border-radius:4px}
body.is-gallery :focus-visible{outline-color:var(--ink)}
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ---------------------------------------------------------------- nav */
.nav{
  position:sticky;top:0;z-index:60;height:var(--nav-h);
  display:flex;align-items:center;justify-content:flex-end;
  padding-inline:max(0px, calc(var(--page-x) - 22px));
  isolation:isolate;
}
/* Frosted band over the photograph.
   This is what makes white nav text legible, so it is required rather than
   decorative. A flat scrim alone is not enough: it lightens along with whatever
   is behind it, and measured against a pale photograph the text fell to 2:1,
   well under the 4.5:1 the spec asks for. brightness() multiplies the backdrop
   instead of blending with it, so a bright sky is pulled down proportionally and
   the contrast holds whatever photograph is dropped into assets/hero/ later.
   Re-measure if you touch these numbers. */
.nav::before{
  content:"";position:absolute;inset:0;z-index:-2;
  background:rgba(20,20,18,.34);
  -webkit-backdrop-filter:blur(16px) saturate(1.1) brightness(.55);
  backdrop-filter:blur(16px) saturate(1.1) brightness(.55);
}
/* gallery: nav keeps its own frosted photographic strip over white content */
.nav::after{
  content:"";position:absolute;inset:0;z-index:-3;opacity:0;
  background-image:var(--hero-img);
  background-size:cover;background-position:center 32%;
  transition:opacity .3s var(--ease);
}
body.is-gallery .nav::after{opacity:1}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .nav::before{background:rgba(20,20,18,.72)}
}
.nav__list{
  display:flex;align-items:center;gap:clamp(14px,2.2vw,38px);
  list-style:none;margin:0;padding:0;
  min-width:0;overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
  scroll-snap-type:x proximity;
  /* fade hint gets its own gutter, so a nav item is never clipped when it fits */
  padding-inline:22px;
  mask-image:linear-gradient(90deg,transparent 0,#000 22px,#000 calc(100% - 22px),transparent 100%);
}
.nav__list::-webkit-scrollbar{display:none}
.nav__item{flex:0 0 auto;scroll-snap-align:end}
.nav__link{
  display:inline-flex;align-items:center;gap:.5em;
  color:#fff;white-space:nowrap;
  font-size:clamp(14px,1.05vw,19px);
  padding:.4em .1em;opacity:.82;
  transition:opacity .2s var(--ease);
}
.nav__link:hover{opacity:1}
.nav__link[aria-current]{opacity:1;font-weight:600}
.nav__link[aria-current]::after{
  content:"";position:absolute;left:.1em;right:.1em;bottom:.05em;
  height:1.5px;background:#fff;border-radius:2px;
}
.nav__link{position:relative}
.nav__map{
  flex:0 0 auto;height:1.5em;width:auto;max-width:2.2em;
  color:#fff;filter:drop-shadow(0 1px 2px rgba(0,0,0,.35));
}
.nav__map svg{height:100%;width:auto;max-width:2.2em;display:block}

/* ---------------------------------------------------------------- hero */
.hero{
  position:relative;width:100%;
  height:100vh;height:100svh;
  margin-top:calc(-1 * var(--nav-h));
  overflow:hidden;background:#2a2a28;
}
.hero__layer{position:absolute;inset:0;background-image:var(--hero-img);
  background-size:cover;background-position:center;background-origin:border-box;background-repeat:no-repeat}

/* everything outside the RM letterforms: blurred and slightly darkened */
.hero__blur{filter:blur(20px) brightness(.84) saturate(.95);transform:scale(1.08)}

/* The RM letterforms are the window — sharp image shows through them, frost everywhere else.
   The extra top padding is the nav height, so the shape sits optically centred below the bar. */
.hero__sharp,.hero__edge{
  padding:calc(var(--nav-h) + var(--hero-inset)) var(--hero-inset) var(--hero-inset);
  -webkit-mask-origin:content-box;mask-origin:content-box;
  -webkit-mask-size:contain;mask-size:contain;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
}
.hero__sharp{-webkit-mask-image:url("../logo/RM-logo-fill.svg");mask-image:url("../logo/RM-logo-fill.svg")}
/* 1px faint hairline along the inside edge of the shape's own path */
.hero__edge{
  position:absolute;inset:0;pointer-events:none;
  background:rgba(255,255,255,.55);
  -webkit-mask-image:url("../logo/RM-logo-outline.svg");mask-image:url("../logo/RM-logo-outline.svg");
}
/* Portrait screens and phones on their side.
   Above, the photograph covers the whole screen, which is right when the screen
   is roughly the photo's shape. On a tall screen, covering the full height blows
   the photo up to three times the width of the RM, and the letters show only a
   zoomed-in slice of it. So here the photo is sized to the RM instead -- the
   letters frame the same scene as on desktop -- and a second, softer copy
   covers the screen behind it. Desktop and tablet landscape never match this
   query, so they are untouched. */
@media (max-aspect-ratio:1/1),(max-height:540px){
  .hero{
    /* the RM's rendered width: its box is the padded area of .hero__sharp, and
       the logo (1627 x 642) is fitted into it with mask-size:contain */
    --rm-w:min(100vw - 2*var(--hero-inset), (100svh - var(--nav-h) - 2*var(--hero-inset)) * 2.534);
    /* photo width: a touch wider than the RM, as on desktop, and never narrower
       than the screen */
    --hero-pw:max(100vw, var(--rm-w) * 1.07);
    /* the hero photograph's width / height. Only used to feather the soft copy's
       top and bottom edges; update it if a much taller or wider photo goes in. */
    --hero-ratio:1.505;
  }
  .hero__sharp{background-size:var(--hero-pw) auto;background-origin:content-box}
  .hero__blur{filter:none;transform:none;background-image:none}
  .hero__blur::before,.hero__blur::after{
    content:"";position:absolute;inset:0;
    background-image:var(--hero-img);background-repeat:no-repeat;background-position:center;
  }
  /* fills the whole screen, softer and darker than the frost round the letters */
  .hero__blur::before{
    background-size:cover;
    filter:blur(40px) brightness(.8) saturate(.95);transform:scale(1.15);
  }
  /* the frost round the letters: the same framing as the sharp photo, so the
     picture runs on unbroken across the outline */
  .hero__blur::after{
    padding:calc(var(--nav-h) + var(--hero-inset)) var(--hero-inset) var(--hero-inset);
    background-size:var(--hero-pw) auto;background-origin:content-box;
    filter:blur(20px) brightness(.84) saturate(.95);
    /* fully solid from the top of the RM to its bottom, fading out beyond */
    -webkit-mask-image:linear-gradient(transparent,#000 27%,#000 73%,transparent);
    mask-image:linear-gradient(transparent,#000 27%,#000 73%,transparent);
    -webkit-mask-origin:content-box;mask-origin:content-box;
    -webkit-mask-size:var(--hero-pw) calc(var(--hero-pw) / var(--hero-ratio));
    mask-size:var(--hero-pw) calc(var(--hero-pw) / var(--hero-ratio));
    -webkit-mask-position:center;mask-position:center;
    -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  }
}
/* no mask support: keep the sharp photo rather than a blank hero */
@supports not ((mask-image:url(#a)) or (-webkit-mask-image:url(#a))){
  .hero__blur{display:none}
}

/* ---------------------------------------------------------------- home */
.home{
  padding:clamp(56px,9vw,150px) var(--page-x) clamp(40px,6vw,90px);
  display:grid;gap:clamp(44px,7vw,110px);
}
.intro__name{
  font-family:var(--font-display);font-weight:400;
  font-size:clamp(40px,6.4vw,86px);line-height:1.05;margin:0;
}
.intro__tagline{margin:clamp(10px,1.4vw,20px) 0 0;font-size:clamp(15px,1.25vw,21px)}

/* ----------------------------------------------------------------- ticket */
.ticket{
  --stub-w:clamp(230px,28%,320px);
  position:relative;overflow:hidden;
  display:grid;grid-template-columns:var(--stub-w) 1fr;
  max-width:1080px;
  background:var(--paper);border:1px solid var(--hairline);border-radius:var(--radius-card);
  box-shadow:0 1px 2px rgba(0,0,0,.04),0 18px 40px -22px rgba(0,0,0,.22);
}
.ticket__stub{
  position:relative;background:var(--paper-tint);
  padding:clamp(20px,2.4vw,34px);
  border-right:1.5px dashed var(--hairline);
  display:flex;flex-direction:column;gap:22px;justify-content:space-between;
}
/* the two punched half-circles where the stub tears off */
.ticket__stub::before,.ticket__stub::after{
  content:"";position:absolute;right:-12px;width:22px;height:22px;border-radius:50%;
  background:var(--paper);border:1px solid var(--hairline);
}
.ticket__stub::before{top:-12px}
.ticket__stub::after{bottom:-12px}

.fields{display:grid;grid-template-columns:1fr 1fr;gap:16px 14px;margin:0}
.fields .full{grid-column:1/-1}
.fields dt{font:500 10px/1 var(--font-mono);letter-spacing:.18em;text-transform:uppercase;color:var(--ink-faint)}
.fields dd{margin:6px 0 0;font:500 clamp(13px,1vw,15px)/1.25 var(--font-mono);text-transform:uppercase;letter-spacing:.04em}
.fields .full dd{font-size:clamp(15px,1.25vw,19px)}

.barcode{display:block;width:100%;height:44px;fill:var(--ink)}

.ticket__body{position:relative;padding:clamp(20px,2.8vw,44px) clamp(20px,3.4vw,56px) clamp(24px,3.2vw,48px)}
.ticket__head{
  font:500 11px/1.2 var(--font-mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ink-faint);
  display:flex;justify-content:space-between;gap:12px;
  padding-bottom:14px;margin-bottom:clamp(18px,2.4vw,32px);
  border-bottom:1.5px dashed var(--hairline);
}
.ticket__body p{margin:0 0 1em;max-width:62ch;font-size:clamp(15px,1.2vw,19px)}
.ticket__body p:last-child{margin-bottom:0}
.ticket__body .ticket__lead{
  font-size:clamp(19px,1.9vw,30px);line-height:1.3;margin-bottom:.8em;max-width:none;
}
.ticket__lead span{display:inline-block;margin-right:.35em}

/* layover: the mirror image, stub on the right */
.ticket--layover{grid-template-columns:1fr var(--stub-w);margin-left:auto}
.ticket--layover .ticket__stub{order:2;border-right:0;border-left:1.5px dashed var(--hairline)}
.ticket--layover .ticket__stub::before,.ticket--layover .ticket__stub::after{right:auto;left:-12px}
.ticket--layover .ticket__stub{justify-content:flex-start}

.stamp{
  position:absolute;right:clamp(16px,3vw,48px);top:clamp(52px,5vw,70px);
  display:grid;justify-items:center;gap:2px;padding:8px 14px 7px;
  color:var(--stamp);border:2px solid currentColor;border-radius:6px;
  outline:1px solid currentColor;outline-offset:3px;
  transform:rotate(-9deg);opacity:.78;mix-blend-mode:multiply;pointer-events:none;
  font-family:var(--font-mono);text-transform:uppercase;
}
.stamp b{font-size:18px;font-weight:500;letter-spacing:.22em}
.stamp span{font-size:9.5px;letter-spacing:.2em}
/* keep the lead clear of the stamp */
.ticket--layover .ticket__lead{padding-right:clamp(0px,14vw,170px)}

@media (max-width:640px){
  .ticket,.ticket--layover{grid-template-columns:1fr}
  .ticket__stub,.ticket--layover .ticket__stub{
    order:0;border:0;border-bottom:1.5px dashed var(--hairline);
  }
  .ticket__stub::before,.ticket__stub::after,
  .ticket--layover .ticket__stub::before,.ticket--layover .ticket__stub::after{
    top:auto;bottom:-12px;
  }
  .ticket__stub::before,.ticket--layover .ticket__stub::before{left:-12px;right:auto}
  .ticket__stub::after,.ticket--layover .ticket__stub::after{right:-12px;left:auto}
  .fields{grid-template-columns:1fr 1fr 1fr}
  .ticket__head{flex-wrap:wrap;row-gap:8px}
  .ticket__head span{white-space:nowrap}
  .barcode{height:36px}
  .stamp{top:auto;bottom:14px;right:14px;transform:rotate(-7deg) scale(.82);transform-origin:bottom right}
  .ticket--layover .ticket__lead{padding-right:0}
  .ticket--layover .ticket__body{padding-bottom:84px}
}
/* the narrowest phones: three stub columns would break words like SHANGRI-LA */
@media (max-width:400px){.fields{grid-template-columns:1fr 1fr}}

/* ------------------------------------------------------------- interlude
   Plain text between the cards and the board: no card, so the page breathes.
   Indented to line up with the text inside the tickets on wide screens. */
.interlude{max-width:62ch;margin-inline:clamp(0px,3vw,56px) 0}
.interlude p{margin:0 0 1em;font-size:clamp(15px,1.2vw,19px)}
.interlude p:last-child{margin-bottom:0}
.interlude__label{
  font:500 11px/1.2 var(--font-mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ink-faint);
}
.interlude .interlude__label{margin-bottom:clamp(14px,1.8vw,24px);font-size:11px}
.interlude .interlude__lead{font-size:clamp(19px,1.9vw,30px);line-height:1.3;margin-bottom:.8em}

/* ----------------------------------------------------------------- board */
.board__panel{
  /* sized so destination + status always fit a phone; --dest is the number of
     destination cells, set by render_departures() from the longest name */
  --cell:clamp(8px,calc(61vw / (var(--dest,10) + 10)),30px);
  --cell-gap:max(2px,calc(var(--cell) * .1));
  /* as wide as its rows, centred on the page */
  width:fit-content;max-width:100%;margin-inline:auto;
  background:var(--board);color:var(--flap-ink);border-radius:var(--radius-card);
  padding:clamp(18px,3vw,44px) clamp(14px,3vw,44px) clamp(20px,3vw,40px);
  box-shadow:0 22px 50px -26px rgba(0,0,0,.5);
}
.board__top{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:clamp(14px,2vw,26px)}
.board__top h2{
  margin:0;font:500 clamp(15px,1.5vw,22px)/1 var(--font-mono);letter-spacing:.32em;text-transform:uppercase;
  color:var(--amber);
}
.board__note{font:500 10.5px/1 var(--font-mono);letter-spacing:.18em;text-transform:uppercase;color:rgba(242,239,230,.45)}
.board__cols,.board__row{
  display:grid;align-items:center;
  grid-template-columns:auto auto auto;justify-content:start;
  column-gap:calc(var(--cell) * .9);
}
.board__cols{
  font:500 10px/1 var(--font-mono);letter-spacing:.18em;text-transform:uppercase;color:rgba(242,239,230,.45);
  padding:0 8px 10px;border-bottom:1px solid rgba(242,239,230,.12);margin-bottom:8px;
}
/* each column label is as wide as its run of cells */
.board__col-dest{width:calc(var(--dest,10) * var(--cell) + (var(--dest,10) - 1) * var(--cell-gap))}
.board__col-gate{width:calc(3 * var(--cell) + 2 * var(--cell-gap))}
.board__rows{list-style:none;margin:0;padding:0;display:grid;gap:calc(var(--cell) * .28)}
.board__row{padding:6px 8px;border-radius:8px;transition:background .2s var(--ease)}
a.board__row:hover,a.board__row:focus-visible{background:rgba(242,239,230,.06);outline:none}
/* the next trip: on the board, but nothing to open yet */
.board__row--next{cursor:default}
.board__cells{display:flex;gap:var(--cell-gap)}
.flap{
  position:relative;display:grid;place-items:center;
  width:var(--cell);height:calc(var(--cell) * 1.36);
  background:linear-gradient(#323230,#272725);border-radius:max(2px,calc(var(--cell) * .12));
  font:500 calc(var(--cell) * .74)/1 var(--font-mono);
  box-shadow:inset 0 -1px 0 rgba(0,0,0,.35);
}
/* the hinge every split-flap character turns on */
.flap::after{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:rgba(0,0,0,.55)}
.flap.is-turning{animation:flap .09s linear}
@keyframes flap{50%{transform:scaleY(.15)}}
.board__cells--status.is-boarding{color:var(--amber)}
.board__cells--status.is-boarding .flap{animation:blink 1.6s steps(1) infinite}
@keyframes blink{50%{color:rgba(242,239,230,.25)}}
a.board__row:hover .board__cells--dest{color:#fff}

/* on a phone the gate column goes, so destination and status both fit */
@media (max-width:640px){
  .board__col-gate,.board__cells--gate{display:none}
  .board__note{display:none}
  .board__row,.board__cols{padding-inline:4px}
}


/* ------------------------------------------------------------- viewfinder
   Full-width strip opening the content under the hero: the readout along the
   bottom of a camera viewfinder, printed faintly like a watermark -- the
   readout only a shade darker than its pale band. The items spread out across the
   strip with a minimum gap between them; when the screen is too narrow for all
   of them, the less important ones drop out, priority 3 first, then 2. */
.vf{
  background:#F7F7F5;color:#DEDED9;
  border-bottom:1px solid #EFEFEC;
  padding:clamp(8px,1.1vw,15px) var(--page-x);
  overflow:hidden;
}
.vf__row{
  --vf-size:clamp(12px,1.1vw,16px);
  display:flex;align-items:center;justify-content:space-between;
  gap:clamp(10px,1.6vw,28px);
  max-width:1400px;margin-inline:auto;
  font:500 var(--vf-size)/1 var(--font-mono);
}
.vf__i{display:inline-flex;align-items:flex-end;gap:.12em;white-space:nowrap;flex:0 0 auto}
.vf__i b{font-weight:500;letter-spacing:-.02em}
.vf__i small{font-size:.5em;letter-spacing:.06em;line-height:1.1;padding-bottom:.12em}
.vf__stack{display:inline-grid;gap:.15em;text-align:left}
.vf__icon{height:.62em;width:auto;fill:currentColor;align-self:center}
.vf__meter{align-items:center;gap:.25em}
.vf__meter svg{width:calc(var(--vf-size) * 3.6);height:.5em;fill:currentColor}
.vf__meter small{padding:0;font-size:.6em}

@media (max-width:820px){.vf--3{display:none}}
@media (max-width:520px){
  .vf--2{display:none}
  .vf__row{justify-content:space-around}
}

/* ---------------------------------------------------------------- pills */
.pills{
  position:sticky;top:var(--nav-h);z-index:50;background:var(--paper);
  padding:clamp(16px,2.6vw,40px) 0 clamp(12px,1.8vw,26px);
}
.pills__scroller{
  display:flex;gap:clamp(10px,1.8vw,32px);
  padding-left:var(--page-x);padding-right:max(var(--page-x),52px);
  overflow-x:auto;overflow-y:hidden;scrollbar-width:none;
  -webkit-overflow-scrolling:touch;scroll-snap-type:x proximity;
  mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 44px),transparent 100%);
}
.pills__scroller::-webkit-scrollbar{display:none}
.pill{
  flex:0 0 auto;scroll-snap-align:start;
  height:var(--pill-h);padding-inline:clamp(18px,2.2vw,42px);
  display:inline-flex;align-items:center;
  border-radius:999px;white-space:nowrap;
  background:var(--ink);color:#fff;opacity:.5;
  font-size:clamp(14px,1.05vw,19px);
  transition:opacity .22s var(--ease),transform .22s var(--ease);
}
.pill:hover{opacity:.72}
.pill[aria-current]{opacity:1}

/* ---------------------------------------------------------------- gallery */
.gallery{
  --gallery-top:clamp(16px,2.6vw,40px);
  /* the stagger lifts are transforms, so they reserve no space — the deepest one
     is added back as top padding, or the middle column clips under the pill bar */
  --lift-mid:0px;
  --lift-right:0px;
  padding:calc(var(--gallery-top) + var(--lift-mid)) var(--page-x) clamp(48px,7vw,120px);
  display:grid;grid-template-columns:repeat(2,1fr);
  column-gap:var(--gutter);row-gap:var(--gutter);
  align-items:start;
  transition:opacity .22s var(--ease);
}
@media (min-width:768px){
  .gallery{
    grid-template-columns:repeat(3,1fr);
    /* deliberate editorial stagger — middle column rides higher */
    --lift-mid:clamp(24px,4.5vw,92px);
    --lift-right:clamp(8px,1.4vw,28px);
  }
  .gallery > :nth-child(3n+2){transform:translateY(calc(-1 * var(--lift-mid)))}
  .gallery > :nth-child(3n+3){transform:translateY(calc(-1 * var(--lift-right)))}
}
.tile{
  position:relative;display:block;width:100%;
  aspect-ratio:3/4;overflow:hidden;
  border-radius:var(--radius-tile);background:var(--placeholder);
  opacity:0;animation:tile-in .45s var(--ease) forwards;
  cursor:zoom-in;
}
@keyframes tile-in{to{opacity:1}}
/* landscape sources are centre-cropped to portrait; portrait sources fill naturally */
.tile__img{
  width:100%;height:100%;object-fit:cover;object-position:center;
  opacity:0;transition:opacity .4s var(--ease);
}
.tile__img.is-loaded{opacity:1}
/* no long-press "Save to Photos" on iOS; see site.js for the desktop side */
.tile__img,.lb__img{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none}
.empty{padding:clamp(40px,8vw,120px) var(--page-x);color:var(--ink-soft)}

/* ---------------------------------------------------------------- lightbox */
.lb{
  position:fixed;inset:0;z-index:100;display:none;
  background:rgba(24,24,22,.94);
  place-items:center;
  padding:var(--lb-pad);
}
.lb[open],.lb.is-open{display:grid}
.lb__stage{
  position:relative;width:100%;height:100%;
  display:grid;place-items:center;
}
/* The caption is held to the photograph's own width, which is not the stage's
   width: object-fit:contain means a portrait photo in a wide window renders far
   narrower than the space it sits in, and the width changes with every photo.
   A column flex box shrink-wraps to its widest item, so if the caption
   contributes nothing to that measurement the figure ends up exactly as wide as
   the image -- see .lb__cap. No measuring in JavaScript. */
.lb__figure{
  margin:0;min-width:0;min-height:0;
  max-width:100%;max-height:100%;
  display:flex;flex-direction:column;align-items:flex-start;
}
/* the lightbox shows the full, uncropped frame -- contain, never cover.
   The height cap has to be written out in viewport units rather than as a
   percentage: the figure's height is decided by its contents, so a percentage
   here would have nothing to resolve against and would be ignored. Constraining
   the height with width:auto is what makes a tall photograph render narrow, and
   that narrower width is what the caption then matches. */
.lb__img{
  display:block;min-height:0;
  max-width:100%;width:auto;height:auto;
  max-height:calc(100svh - 2 * var(--lb-pad) - var(--lb-cap-space));
  object-fit:contain;border-radius:6px;
  box-shadow:0 24px 80px rgba(0,0,0,.5);
}
.lb__cap{
  /* width:0 keeps the text out of the figure's intrinsic width so the image
     alone decides it; min-width:100% then stretches the text back across
     whatever width that turned out to be, wrapping instead of widening it. */
  width:0;min-width:100%;
  margin-top:8px;
  text-align:left;color:#fff;
  font-size:clamp(13px,1.15vw,17px);line-height:1.4;
  padding-bottom:env(safe-area-inset-bottom);
}
.lb__cap-title{font-weight:600}
.lb__cap-sep{opacity:.55}
.lb__cap-desc{font-style:italic;opacity:.8}
.lb__count{
  /* anchored to the overlay, not the photograph, so it does not jump around as
     one picture gives way to a differently shaped one */
  position:absolute;top:var(--lb-pad);left:var(--lb-pad);margin:0;
  color:#fff;font-size:12px;opacity:.5;letter-spacing:.08em;
  line-height:clamp(40px,5vw,56px);
}
.lb__btn{
  position:absolute;top:50%;transform:translateY(-50%);
  width:clamp(40px,5vw,56px);height:clamp(40px,5vw,56px);
  border-radius:999px;background:rgba(255,255,255,.12);color:#fff;
  display:grid;place-items:center;transition:background .2s var(--ease);
}
.lb__btn:hover{background:rgba(255,255,255,.24)}
.lb__prev{left:0}
.lb__next{right:0}
.lb__close{position:absolute;top:0;right:0;transform:none;width:clamp(40px,5vw,56px);height:clamp(40px,5vw,56px)}
.lb__btn svg{width:45%;height:45%;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}

/* ---------------------------------------------------------------- footer */
.footer{
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:clamp(24px,3vw,48px) var(--page-x) calc(clamp(24px,3vw,48px) + env(safe-area-inset-bottom));
  color:var(--ink-soft);font-size:clamp(13px,1vw,17px);
}
.footer__links{display:flex;gap:clamp(16px,2vw,36px)}
.footer__links a{color:var(--ink);opacity:.85;transition:opacity .2s var(--ease)}
.footer__links a:hover{opacity:1}
.footer__links svg{height:clamp(17px,1.35vw,22px);width:auto;display:block}

/* ------------------------------------------------- switching between places */
/* The pill bar swaps the gallery in place instead of reloading the page. This
   fades the old grid out while the new one is fetched; without JavaScript the
   pills are ordinary links and none of this is ever applied. */
main.is-swapping .gallery{opacity:.25;pointer-events:none}

/* ---------------------------------------------------------------- consent */
/* Slides over the nav bar from the left, the same height, so it never covers
   the RM letters. The nav's own frost, but denser, so the menu underneath does
   not show through; white text keeps the nav's AA contrast. */
.consent{
  position:absolute;inset:0;z-index:999;
  display:flex;align-items:center;justify-content:space-between;gap:clamp(10px,2vw,32px);
  padding-inline:var(--page-x);color:#fff;
  background:rgba(20,20,18,.62);
  -webkit-backdrop-filter:blur(18px) saturate(1.1) brightness(.5);
  backdrop-filter:blur(18px) saturate(1.1) brightness(.5);
  transform:translateX(-100%);transition:transform .45s var(--ease);
}
.consent.is-in{transform:none}
.consent[hidden]{display:none}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .consent{background:rgba(20,20,18,.92)}
}
.consent__text{margin:0;font-size:clamp(12.5px,1vw,16px);line-height:1.3}
.consent__text a,.privacy a{text-decoration:underline;text-underline-offset:2px}
.consent__actions,.privacy__actions{display:flex;gap:8px;flex:0 0 auto}
.consent__btn{
  padding:.45em 1.1em;border-radius:999px;font-size:clamp(12.5px,.95vw,15px);font-weight:600;
  color:#fff;border:1px solid rgba(255,255,255,.7);transition:background .2s var(--ease);
}
.consent__btn:hover{background:rgba(255,255,255,.14)}
.consent__btn--yes{background:#fff;color:#1d1d1b;border-color:#fff}
.consent__btn--yes:hover{background:rgba(255,255,255,.85)}
.consent :focus-visible,.privacy :focus-visible{outline-color:#fff}

/* ---------------------------------------------------------------- privacy */
.footer__privacy{text-decoration:underline;text-underline-offset:2px}
.footer__privacy:hover{color:var(--ink)}
.privacy{
  width:min(560px,calc(100vw - 32px));max-height:min(80svh,720px);overflow:auto;
  padding:clamp(24px,4vw,44px);border:1px solid rgba(255,255,255,.14);border-radius:18px;
  color:#fff;background:rgba(20,20,18,.6);
  -webkit-backdrop-filter:blur(20px) saturate(1.1);backdrop-filter:blur(20px) saturate(1.1);
  box-shadow:0 20px 60px rgba(0,0,0,.35);
}
.privacy::backdrop{background:rgba(10,10,9,.45)}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .privacy{background:rgba(20,20,18,.95)}
}
.privacy h2{margin:0 0 .6em;font-size:clamp(20px,1.8vw,28px);font-weight:600}
.privacy h3{margin:1.4em 0 .3em;font-size:1em;font-weight:600}
.privacy p{margin:0 0 .6em;color:rgba(255,255,255,.86)}
.privacy code{font-size:.9em;color:#fff}
.privacy__actions{margin-top:.8em;flex-wrap:wrap}
.privacy__close{top:12px;right:12px;transform:none;width:40px;height:40px}

@media (max-width:600px){
  /* two short lines of text beside compact buttons */
  .consent{gap:10px;padding-inline:14px}
  .consent__btn{padding:.4em .85em}
}
@media (max-width:360px){
  .consent__text{font-size:11.5px}
}

/* No hero photograph in assets/hero/ -- keep a calm dark panel so the mark still
   reads, rather than a blank white screen. */
.hero{background:#2a2a28}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
  .board__cells--status.is-boarding .flap{animation:none}
  .tile{opacity:1;animation:none}
  main.is-swapping .gallery{opacity:1}
}
