/* ------------------------------------------------------------------
   vibelystudio.com — shared stylesheet for index.html and venues.html.

   This lived inline in both pages until the two copies drifted: the
   venue hand-off rules existed only in index.html, and nothing would
   have caught that. One file, one place to change, and the second page
   a reader opens costs nothing to style.

   privacy.html is deliberately NOT on this sheet. It is a different
   design system — its own palette names (--sand/--accent/--gold rather
   than --cream/--brand/--sun), a sticky bar rather than the floating
   pill, and coloured links. Linking it here would silently restyle it.
   Reconciling the two is a separate job.
------------------------------------------------------------------- */

/* Cross-document view transitions. Moving between index.html and venues.html
   (and privacy.html) is a real page load, but because every page shares this
   sheet they all opt in, so the browser cross-fades between them instead of
   hard-cutting to a white flash — it reads as one continuous site, not a jump.
   Browsers without support (Firefox, for now) just navigate as before, and
   every browser skips the animation entirely under prefers-reduced-motion. */
@view-transition { navigation: auto; }
/* The floating nav pill is the same element in the same place on every page,
   so pinning it holds it still while the page behind it fades — the bar reads
   as persistent chrome rather than something that reloads on each click. */
@media (prefers-reduced-motion: no-preference){
  header{ view-transition-name: site-header; }
}

/* ---------------------------------------------------------------
     LIGHT ONLY — deliberately single-theme. This is a Cape Town
     lifestyle company; a dark variant made it read moody and closed.
     Palette sampled from the photographs themselves: golden-hour sun,
     Camps Bay sea, and the brand maroon (AppColors.primary).
  ---------------------------------------------------------------- */
  :root{
    --paper:#FFFDFC;
    --surface:#FFFFFF;
    --cream:#FFF6EC;
    --ink:#1A1315;
    --ink-2:#63565B;
    --ink-3:#6E6169;   /* darkened from #93868B: the old value was 3.44:1 on
                          paper, below WCAG AA. #6E6169 is 5.79:1 and stays
                          lighter than --ink-2, so the hierarchy holds. */
    --line:#EFE6E2;

    --brand:#921B58;
    --brand-deep:#751445;
    --sun:#EE9A34;
    --sun-soft:#FDF0DC;
    --sea:#1F8FAD;
    --sea-soft:#E4F4F8;
    --night:#2A0B2E;

    --display:"Plus Jakarta Sans","Segoe UI Variable Display",-apple-system,
              BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
    --body:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
    --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
    --maxw:1160px;
    --r:24px; --r-s:16px;

    /* One spacing scale. Every vertical gap below is a step on it, so the
       page has a rhythm instead of thirty hand-picked numbers. */
    --s1:8px; --s2:14px; --s3:22px; --s4:34px;
    --s5:56px; --s6:88px; --s7:128px;
  }

  *,*::before,*::after{box-sizing:border-box}

  /* Nav links glide to their section instead of jumping. scroll-padding-top
     keeps the target clear of the floating nav pill (top:14px + pill height),
     so a heading never lands hidden underneath it — this also fixes cross-page
     anchors like venues.html -> index.html#day, which otherwise land too high.
     Smooth only when the reader hasn't asked for reduced motion. */
  html{scroll-padding-top:88px}
  @media (prefers-reduced-motion:no-preference){
    html{scroll-behavior:smooth}
  }

  body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--body);
       font-size:17px;line-height:1.65;-webkit-font-smoothing:antialiased}
  h1,h2,h3{font-family:var(--display);font-weight:800;letter-spacing:-.025em;
       line-height:1.1;margin:0;text-wrap:balance}
  p{margin:0}
  a{color:inherit;text-decoration:none}
  img{max-width:100%;display:block}
  /* <picture> is inline by default, which would break the height:100% chain
     between a fixed-ratio figure and the img inside it. */
  picture{display:block}
  .slot figure picture{width:100%;height:100%}
  :focus-visible{outline:2px solid var(--brand);outline-offset:3px;border-radius:4px}
  .wrap{max-width:var(--maxw);margin:0 auto;padding:0 26px}
  .eyebrow{font-family:var(--mono);font-size:11.5px;letter-spacing:.14em;
       text-transform:uppercase;color:var(--brand)}

  .btn{display:inline-flex;align-items:center;gap:8px;border:2px solid transparent;
       border-radius:999px;padding:13px 26px;font-weight:600;font-size:15.5px;
       cursor:pointer;transition:background .18s,border-color .18s,transform .12s,box-shadow .18s}
  .btn:active{transform:translateY(1px)}
  .btn-solid{background:var(--brand);color:#fff;box-shadow:0 6px 18px rgba(146,27,88,.22)}
  .btn-solid:hover{background:var(--brand-deep);box-shadow:0 8px 24px rgba(146,27,88,.3)}
  .btn-ghost{border-color:var(--line);color:var(--ink);background:var(--surface)}
  .btn-ghost:hover{border-color:var(--sun);background:var(--sun-soft)}
  .btn-white{background:#fff;color:var(--brand)}
  .btn-white:hover{background:var(--sun-soft)}

  /* ---------- The day ----------
     The page is lit by the real hour in Cape Town, not by how far you have
     scrolled. Open it at 07:00 and it's morning; open it at 22:00 and it's
     night. Two things carry it — this wash, and the clock in the nav pill.

     It was scroll-driven first. Two problems with that: a clock counting
     05:30 to 22:00 as you scroll is decoration, and a decorative clock in a
     sticky header just spends chrome — whereas the real time is information,
     and it is the same claim the app makes ("what's open, what's on, now").
     It also means nothing recalculates while you scroll, which is the
     cheapest possible answer on a budget Android.

     The gradient covers a full 24 hours and is positioned once, then once a
     minute. z-index sits above the sections and below the header. */
  .daylight{position:fixed;inset:0;z-index:5;overflow:hidden;pointer-events:none}
  .daylight i{display:block;position:absolute;left:0;right:0;top:0;height:700vh;
       background:linear-gradient(to bottom,
         rgba(42,11,46,.17)    0%,     /* 00:00 — night */
         rgba(42,11,46,.16)    19%,    /* 04:30 */
         rgba(96,132,190,.12)  23%,    /* 05:30 — blue before the sun clears the ridge */
         rgba(255,214,163,.08) 27%,    /* 06:30 — first light */
         rgba(255,255,255,0)   37%,    /* 09:00 — plain daylight */
         rgba(255,255,255,0)   54%,    /* 13:00 — high sun, no cast at all */
         rgba(238,154,52,.085) 75%,    /* 18:00 — the gold everyone photographs */
         rgba(146,27,88,.10)   83%,    /* 20:00 — dusk going pink */
         rgba(42,11,46,.17)    92%,    /* 22:00 — night */
         rgba(42,11,46,.17)    100%)}  /* 24:00 */

  /* Screen-reader-only, for text that would be noise on screen but is needed
     to make a label make sense when read aloud. */
  .vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
       clip-path:inset(50%);white-space:nowrap;border:0}

  /* The clock. Tabular figures so the pill doesn't twitch as digits change. */
  .hour{font-family:var(--mono);font-size:12px;letter-spacing:.08em;
       color:rgba(255,255,255,.66);font-variant-numeric:tabular-nums;
       padding:5px 11px;border-radius:999px;background:rgba(255,255,255,.10);
       border:1px solid rgba(255,255,255,.14);margin-right:auto;margin-left:14px;
       transition:color .25s,background .25s,border-color .25s}
  .hour i{font-style:normal;opacity:.62;margin-right:1px}
  header.solid .hour{color:var(--ink-3);background:rgba(26,19,21,.04);
       border-color:rgba(26,19,21,.07)}
  /* The clock costs the pill ~70px, which is enough to break "Talk to us"
     onto two lines on a phone. The button must never shrink or wrap. */
  .nav-links .btn{flex:none;white-space:nowrap}
  @media (max-width:560px){
    .nav{gap:10px;padding-left:15px}
    .hour{margin-left:9px;padding:4px 8px;font-size:11px;letter-spacing:.05em}
  }

  /* ---------- Header — floating pill ----------
     A detached pill rather than a full-width bar: it matches the owner
     portal's nav, which is what makes the site, the email and the app
     read as one company. Two glass states — smoked glass over the
     photograph so white text holds, then light glass once the page
     scrolls onto paper. */
  header{position:fixed;top:14px;left:0;right:0;z-index:30;padding:0 20px;
       pointer-events:none}
  .nav{pointer-events:auto;
       display:flex;align-items:center;justify-content:space-between;gap:20px;
       max-width:var(--maxw);margin:0 auto;
       padding:9px 9px 9px 20px;border-radius:999px;
       background:rgba(20,12,15,.46);
       -webkit-backdrop-filter:blur(20px) saturate(1.4);
       backdrop-filter:blur(20px) saturate(1.4);
       border:1px solid rgba(255,255,255,.16);
       box-shadow:0 10px 34px rgba(20,12,15,.22);
       transition:background .3s,border-color .3s,box-shadow .3s,transform .3s}
  header.solid .nav{background:rgba(255,253,252,.985);
       border-color:rgba(26,19,21,.07);
       box-shadow:0 10px 30px rgba(72,40,20,.10)}

  /* The real wordmark asset — the looped V and "ibely" drawn as one piece in
     the brand letterform. Compositing the V mark against Plus Jakarta Sans
     read as two things, because they're two different alphabets. */
  .mark{display:flex;align-items:center;gap:5px}
  /* Ships as the brand purple→magenta gradient — right on paper, invisible on
     the smoked-glass pill and the dark footer, so those knock it to white. */
  .mark img{height:22px;width:auto;display:block;
       filter:brightness(0) invert(1);transition:filter .25s}
  header.solid .mark img{filter:none}
  /* "Studio" is a small-cap label beside the 22px wordmark. It reads best
     sitting on the wordmark's baseline — which is a little below the box
     centre — so it's bottom-aligned in a logo-height box, lifted 3px to land
     on the letters' baseline rather than the image's bottom edge. */
  .mark-txt{display:flex;align-items:flex-end;height:22px;line-height:1;
       padding-bottom:5px;font-family:var(--display);font-weight:800;
       letter-spacing:-.03em;color:#fff;transition:color .25s}
  .mark-txt em{font-style:normal;color:rgba(255,255,255,.62);font-weight:600;
       font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
       transition:color .25s}
  header.solid .mark-txt{color:var(--ink)}
  header.solid .mark-txt em{color:var(--ink-3)}

  .nav-links{display:flex;align-items:center;gap:6px}
  /* Links get their own inner pill on hover, so the bar has one shape
     language instead of underlines inside a rounded container. */
  .nav-links a:not(.btn){font-size:14.5px;font-weight:500;
       color:rgba(255,255,255,.88);padding:8px 14px;border-radius:999px;
       transition:color .2s,background .2s}
  .nav-links a:not(.btn):hover{color:#fff;background:rgba(255,255,255,.14)}
  header.solid .nav-links a:not(.btn){color:var(--ink-2)}
  header.solid .nav-links a:not(.btn):hover{color:var(--brand);background:var(--sun-soft)}
  /* "You are here" — the current page keeps a filled pill so the shared bar
     tells you which page of the same site you're on. */
  .nav-links a.here:not(.btn){color:#fff;background:rgba(255,255,255,.18)}
  header.solid .nav-links a.here:not(.btn){color:var(--brand);background:var(--sun-soft)}
  /* The CTA is the pill's right cap — slightly tighter than a body button. */
  .nav-links .btn{padding:11px 22px;font-size:15px}

  /* The logo mark reads white-on-photo, brand-gradient once solid. */

  /* ---------- Hero ----------
     Copy sits inside the photograph. The scrim is weighted to the
     bottom-left, where the mountain is already in shadow, so the sky
     and the lit rock stay bright and the page still reads warm. */
  /* Full viewport, not a capped band — the photograph is the argument, so it
     should own the first screen rather than stop short of it. svh (not vh) so
     the mobile URL bar doesn't push the bottom of the copy out of view; the vh
     line is the fallback for anything that doesn't know svh. */
  .hero{position:relative;isolation:isolate;overflow:hidden;
       min-height:100vh;min-height:100svh;
       display:flex;align-items:flex-end;background:var(--cream)}
  /* The image lives in an oversized, positioned <picture> so it can drift on
     scroll (parallax, added in the motion section) without ever opening a gap
     at an edge. The load-settle scale stays on the <img>, so the two transforms
     compose — parent translates, child scales — instead of fighting. */
  /* Oversized just enough for the parallax drift to never open an edge — kept
     tighter (110% not 116%) so the image isn't scaled up more than it must be,
     which was costing sharpness on large displays. */
  .hero picture{position:absolute;left:0;right:0;top:-5%;height:110%;z-index:-2}
  .hero-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
       object-position:center 58%;
       animation:settle 1.4s cubic-bezier(.2,.7,.3,1) both}
  @keyframes settle{from{transform:scale(1.08)}to{transform:scale(1)}}
  /* Two scrims: one from the base (where the mountain is already in shadow)
     and one from the left, so the copy column keeps contrast while the sky
     and lit rock stay bright. The vertical stop is carried further up than
     the copy needs, because the headline sits over cloud. */
  .hero::after{content:"";position:absolute;inset:0;z-index:-1;
       background:
         linear-gradient(to top,rgba(20,12,15,.90) 0%,rgba(20,12,15,.66) 30%,
                         rgba(20,12,15,.30) 58%,rgba(20,12,15,.06) 80%,transparent 92%),
         linear-gradient(to right,rgba(20,12,15,.62) 0%,rgba(20,12,15,.22) 42%,
                         rgba(20,12,15,.04) 62%,transparent 76%)}

  .hero-copy{position:relative;max-width:var(--maxw);width:100%;margin:0 auto;
       padding:var(--s7) 26px var(--s6);color:#fff}
  .hero .eyebrow{color:rgba(255,255,255,.9);font-size:12px}
  .hero h1{font-size:clamp(40px,6.4vw,74px);margin-top:var(--s2);max-width:17ch;
       text-shadow:0 2px 28px rgba(0,0,0,.35)}
  /* An underline rather than a filled slab. A maroon block behind a whole
     phrase at headline size dominates the first screen — it reads as the
     loudest thing on the page rather than as emphasis. This keeps the phrase
     marked without shouting. skip-ink lets the tail of the "y" through
     instead of being struck by the rule. */
  .hero h1 mark{background:none;color:inherit;
       text-decoration:underline;text-decoration-color:var(--brand);
       text-decoration-thickness:.085em;text-underline-offset:.13em;
       text-decoration-skip-ink:auto}
  .hero .lede{margin-top:var(--s3);font-size:19.5px;color:rgba(255,255,255,.93);
       max-width:50ch;text-shadow:0 1px 16px rgba(0,0,0,.4)}
  .hero-cta{margin-top:var(--s4);display:flex;flex-wrap:wrap;gap:12px;align-items:center}
  .hero-note{margin-top:var(--s3);font-size:14.5px;color:rgba(255,255,255,.76);
       max-width:46ch}
  .btn-onphoto{border-color:rgba(255,255,255,.5);color:#fff;background:rgba(255,255,255,.08);
       backdrop-filter:blur(6px)}
  .btn-onphoto:hover{background:rgba(255,255,255,.18);border-color:#fff}

  /* ---------- Sections ---------- */
  section{padding:var(--s7) 0}
  .sec-head{max-width:60ch}
  .sec-head h2{font-size:clamp(29px,4vw,44px);margin-top:var(--s2)}
  .sec-head p{margin-top:var(--s3);color:var(--ink-2);font-size:18px}

  /* ---------- Four questions ---------- */
  /* Exactly three questions on venues.html — three across, so there's no orphan
     card in a 2-col grid. Collapses to one column at the 960px breakpoint. */
  .qa{margin-top:var(--s5);display:grid;grid-template-columns:repeat(3,1fr);gap:var(--s3)}
  .q{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
       padding:var(--s4) 34px;transition:box-shadow .2s,border-color .2s,transform .2s}
  .q:hover{border-color:var(--sun);box-shadow:0 12px 34px rgba(72,40,20,.09);
       transform:translateY(-2px)}
  .q .num{font-family:var(--mono);font-size:12px;color:var(--sun);font-weight:600;
       letter-spacing:.1em}
  .q h3{font-size:19.5px;margin-top:var(--s1)}
  .q p{margin-top:var(--s2);color:var(--ink-2);font-size:16px}
  .q p a{color:var(--brand);font-weight:600;text-decoration:underline;
       text-underline-offset:3px}

  /* ---------- Day arc ---------- */
  .band-cream{background:var(--cream);border-top:1px solid var(--line);
       border-bottom:1px solid var(--line)}
  .day{margin-top:var(--s5);display:grid;grid-template-columns:repeat(4,1fr);
       gap:var(--s3)}
  .slot{background:var(--surface);border-radius:var(--r);overflow:hidden;
       border:1px solid var(--line);display:flex;flex-direction:column;
       transition:transform .22s,box-shadow .22s}
  .slot:hover{transform:translateY(-5px);box-shadow:0 18px 40px rgba(72,40,20,.15)}
  /* Square, not 4:3 — these four photographs are the argument that Vibely
     covers a whole day, so they get room to be looked at. */
  .slot figure{margin:0;overflow:hidden;aspect-ratio:1/1}
  .slot img{width:100%;height:100%;object-fit:cover;transition:transform .5s ease}
  .slot:hover img{transform:scale(1.05)}
  /* Per-image crop: each photo has its subject in a different place. */
  /* The morning-mountain and pilates cards are pre-cropped square, so they need
     no framing nudge; only the full-frame cocktail shot does. */
  .slot img.pos-high{object-position:center 32%}
  .slot .body{padding:var(--s3) 24px 26px}
  /* The hour sits on the photograph rather than above the heading: it ties the
     picture to the words instead of floating between them, and the body then
     opens on the label itself. */
  /* The time badge marks text the same way the hero headline does: a maroon
     underline, not a fill. A fill is the button/CTA language, and a static
     timestamp shouldn't impersonate a button. Sitting on a photograph it needs
     a legible ground, so it's smoked glass (the same material as the nav pill)
     rather than nothing. The filled maroon is reserved for the active hour
     below — so on the page, an underline is a mark and a fill is "now". */
  .slot time{position:absolute;left:15px;bottom:14px;z-index:2;
       font-family:var(--mono);font-size:12.5px;color:#fff;
       font-variant-numeric:tabular-nums;letter-spacing:.04em;
       background:rgba(20,12,15,.42);
       -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
       padding:5px 12px;border-radius:999px;display:inline-block;
       text-decoration:underline;text-decoration-color:var(--brand);
       text-decoration-thickness:.14em;text-underline-offset:.18em;
       box-shadow:0 4px 14px rgba(20,12,15,.35)}
  .slot h3{font-size:18.5px}
  /* The hour it currently is in Cape Town. Calm treatment: a soft lift and only
     a hint of maroon in the border — not a full outline — so the card reads as
     gently current, not selected. The other three are left untouched (dimming
     them reads as content that failed to load). */
  .slot.is-now{border-color:color-mix(in srgb,var(--brand) 30%,var(--line));
       box-shadow:0 14px 34px rgba(146,27,88,.14)}
  /* The pill keeps its glass + underline; a small maroon dot and a "now" label
     are appended instead of the old solid-maroon fill, which read as a button.
     The dot is lightened so it holds on the smoked-glass ground. */
  .slot.is-now time::after{content:"now";margin-left:9px;padding-left:15px;
       font-size:11px;letter-spacing:.05em;text-transform:lowercase;
       text-decoration:none;color:rgba(255,255,255,.92);
       background:radial-gradient(circle 3.5px at 5px 52%,
         color-mix(in srgb,var(--brand) 62%,#fff) 0 3.5px,transparent 3.6px) no-repeat}
  .slot time{transition:background .3s,transform .3s}
  .slot p{margin-top:var(--s1);font-size:15px;color:var(--ink-2)}

  /* ---------- Video: the city ---------- */
  .city{position:relative;isolation:isolate;color:#fff;overflow:hidden}
  .city video,.city .poster{position:absolute;inset:0;width:100%;height:100%;
       object-fit:cover;z-index:-2}
  /* object-fit lands on the <img>, not on the <picture> wrapping it. */
  .city .poster img{width:100%;height:100%;object-fit:cover}
  /* The video sits on the still and fades in only once it is genuinely
     playing, so a reader never sees a black rectangle waiting for frames. */
  .city video{opacity:0;transition:opacity .7s ease}
  .city video.playing{opacity:1}
  .city::after{content:"";position:absolute;inset:0;z-index:-1;
       background:linear-gradient(100deg,rgba(42,11,46,.86) 0%,rgba(42,11,46,.55) 55%,
                 rgba(146,27,88,.42) 100%)}
  .city-in{max-width:var(--maxw);margin:0 auto;padding:var(--s7) 26px}
  .city .eyebrow{color:rgba(255,255,255,.78)}
  .city h2{font-size:clamp(30px,4.4vw,46px);margin-top:var(--s2);max-width:17ch}
  .city p{margin-top:var(--s3);font-size:18px;color:rgba(255,255,255,.9);max-width:50ch}
  .stats{margin-top:var(--s5);display:grid;
       grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:var(--s3);max-width:760px}
  .stat b{display:block;font-family:var(--display);font-size:34px;font-weight:800;
       font-variant-numeric:tabular-nums;letter-spacing:-.02em}
  .stat span{font-size:14.5px;color:rgba(255,255,255,.78)}

  /* ---------- Venues strip ---------- */
  .strip{display:grid;grid-template-columns:1.05fr .95fr;gap:var(--s6);
       align-items:center}
  .strip figure{margin:0;aspect-ratio:4/3;overflow:hidden;border-radius:var(--r);
       box-shadow:0 20px 48px rgba(72,40,20,.16)}
  .strip img{width:100%;height:100%;object-fit:cover;object-position:center 55%}
  .strip ul{list-style:none;margin:var(--s4) 0 0;padding:0;display:flex;
       flex-direction:column;gap:var(--s2)}
  .strip li{display:flex;gap:13px;align-items:flex-start;font-size:16.5px}
  .tick{flex:none;width:22px;height:22px;border-radius:50%;background:var(--sun-soft);
       color:var(--sun);display:grid;place-items:center;font-size:12px;font-weight:700;
       margin-top:2px}

  /* ---------- Venue hand-off ---------- */
  .handoff{display:flex;align-items:center;justify-content:space-between;
       gap:var(--s5);flex-wrap:wrap}
  /* Without a basis the copy claims the whole row and drops the button onto a
     line of its own, stranded in white space. */
  .handoff > div{flex:1 1 520px}
  .handoff p{margin-top:var(--s3);font-size:16.5px;color:var(--ink-2);max-width:56ch}
  .handoff .btn{flex:none}

  /* ---------- Full-bleed photo band ----------
     A wide cinematic strip that breaks up the text stretches and doubles as a
     scroll moment (the image parallaxes, see the motion section). Oversized,
     positioned <picture> so the drift never opens an edge; a short display-type
     caption sits in the lower-left with a legibility scrim. */
  /* Full-bleed again: these are wide, high-res landscapes (3200px+), so they fill
     the band edge-to-edge and stay sharp on big screens — no letterbox needed. */
  .photoband{position:relative;isolation:isolate;overflow:hidden;
       height:clamp(320px,54vh,600px);display:flex;align-items:flex-end;color:#fff}
  .photoband picture{position:absolute;inset:0;z-index:-2}
  .photoband img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
       object-position:center 50%}
  /* Scrim weighted to the bottom-left, under the caption, so white text holds
     without dimming the sky. */
  .photoband::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
       background:
       linear-gradient(to top,rgba(20,12,15,.6),rgba(20,12,15,.06) 44%,rgba(20,12,15,.2)),
       linear-gradient(to right,rgba(20,12,15,.46),rgba(20,12,15,0) 42%)}
  /* Caption anchored to the band's bottom-left corner (flush to the viewport
     margin, not the centred content column) — so on a wide screen it sits over
     the image edge instead of floating mid-frame. */
  .photoband .cap{max-width:640px;width:100%;margin:0;
       padding:0 clamp(24px,5vw,64px) var(--s5)}
  .photoband .cap .eyebrow{color:rgba(255,255,255,.86)}
  .photoband .cap p{font-family:var(--display);font-weight:800;letter-spacing:-.025em;
       font-size:clamp(24px,3.6vw,40px);line-height:1.08;margin-top:var(--s2);max-width:20ch;
       text-shadow:0 2px 30px rgba(0,0,0,.42)}

  /* ---------- Video band: full-width clip behind a caption ---------- */
  /* Reuses .photoband's frame, scrim and caption. The poster <picture> drops to
     -3 so the video can sit above it (-2) yet still below the scrim (-1); the
     video fades in only once it's genuinely playing (mirrors .city). */
  .videoband picture{z-index:-3}
  .videoband video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
       object-position:center 50%;z-index:-2;opacity:0;transition:opacity .7s ease}
  .videoband video.playing{opacity:1}

  /* ---------- Founders ---------- */
  .founders{display:grid;grid-template-columns:1fr 1fr;gap:var(--s3);margin-top:var(--s5)}
  .person{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
       padding:var(--s4);display:flex;gap:var(--s3);align-items:flex-start;
       transition:transform .22s,box-shadow .22s,border-color .22s}
  /* Same lift language as the question and contact cards, so every card on the
     site responds to the cursor the same way. */
  .person:hover{transform:translateY(-4px);border-color:rgba(146,27,88,.2);
       box-shadow:0 16px 38px rgba(72,40,20,.12)}
  .person .avatar img{transition:transform .5s cubic-bezier(.2,.7,.3,1)}
  .person:hover .avatar img{transform:scale(1.05)}
  .avatar{flex:none;width:104px;height:104px;border-radius:var(--r-s);overflow:hidden;
       background:var(--sea-soft);border:1px solid var(--line);
       box-shadow:0 6px 18px rgba(20,12,15,.10)}
  .avatar img{width:100%;height:100%;object-fit:cover;display:block}
  .person h3{font-size:18px}
  .person .role{font-size:14px;color:var(--brand);margin-top:2px;font-weight:600}
  .person p{margin-top:9px;font-size:15px;color:var(--ink-2)}

  .pledge{margin-top:var(--s3);padding:var(--s5) 40px;background:var(--sun-soft);
       border-radius:var(--r)}
  .pledge p{font-family:var(--display);font-weight:600;font-size:clamp(19px,2.4vw,24px);
       line-height:1.45;letter-spacing:-.015em;max-width:48ch}
  .pledge .who{margin-top:var(--s3);font-family:var(--body);font-weight:400;font-size:15px;
       color:var(--ink-2)}

  /* ---------- Contact ---------- */
  .routes{display:grid;grid-template-columns:repeat(auto-fit,minmax(238px,1fr));
       gap:var(--s3);margin-top:var(--s5)}
  .route{background:var(--surface);border:1px solid var(--line);border-radius:var(--r-s);
       padding:var(--s4) 26px;transition:border-color .2s,box-shadow .2s}
  .route:hover{border-color:var(--sea);box-shadow:0 10px 26px rgba(31,143,173,.12)}
  .route h3{font-size:15.5px}
  .route a{display:inline-block;margin-top:8px;font-weight:600;color:var(--brand);
       font-size:15.5px;word-break:break-word}
  .route a:hover{text-decoration:underline}
  .route p{margin-top:8px;font-size:13.5px;color:var(--ink-3);line-height:1.5}

  /* ---------- Footer ---------- */
  footer{background:var(--night);color:rgba(255,255,255,.68);padding:56px 0 40px;
       font-size:14.5px}
  footer .mark-txt{color:#fff;font-size:18px}
  footer .mark-txt em{color:rgba(255,255,255,.55)}
  footer p{margin-top:13px;max-width:48ch;line-height:1.6}
  .f-row{display:flex;flex-wrap:wrap;justify-content:space-between;gap:24px;
       margin-top:34px;padding-top:24px;border-top:1px solid rgba(255,255,255,.16)}
  .f-links{display:flex;flex-wrap:wrap;gap:22px}
  /* padding-block lifts each link to a >=24px tap target (WCAG 2.2 SC 2.5.8);
     negative margin keeps the row's visual height unchanged. */
  .f-links a{color:#fff;padding-block:4px;margin-block:-4px}
  .f-links a:hover{text-decoration:underline}
  .todo{color:var(--sun);font-family:var(--mono);font-size:12px}

  @media (max-width:960px){
    .hero-in,.strip{grid-template-columns:1fr;gap:36px}
    .day{grid-template-columns:1fr 1fr}
    .qa,.founders{grid-template-columns:1fr}
    .nav-links a:not(.btn){display:none}
    section{padding:64px 0}
    .city-in{padding:76px 26px}
  }
  @media (max-width:560px){.day{grid-template-columns:1fr}}

  /* ---------- For people going out ----------
     The one section addressed to a consumer rather than a venue owner.
     It uses the sea accent instead of brand maroon so it reads as a
     different door without leaving the palette — the sea band and the paper
     venue section either side of it are what separate the two audiences. */
  .band-sea{background:var(--sea-soft);border-top:1px solid #CFE9F0;
       border-bottom:1px solid #CFE9F0}
  .band-sea .eyebrow{color:var(--sea)}
  .going{display:grid;grid-template-columns:1.05fr .95fr;gap:var(--s6);
       align-items:center}
  .going ul{list-style:none;margin:var(--s4) 0 0;padding:0;display:flex;
       flex-direction:column;gap:var(--s2)}
  .going li{display:flex;gap:13px;align-items:flex-start;font-size:16.5px}
  .going .dot{flex:0 0 auto;width:22px;height:22px;border-radius:999px;
       background:#fff;border:1px solid #CFE9F0;color:var(--sea);
       display:grid;place-items:center;font-size:12px;font-weight:700;margin-top:2px}
  .btn-sea{background:var(--sea);color:#fff;box-shadow:0 6px 18px rgba(31,143,173,.24)}
  .btn-sea:hover{background:#17738A;box-shadow:0 8px 24px rgba(31,143,173,.32)}
  /* The clock: the day restated as a four-step arc, colour-coded from cool dawn
     through golden midday and maroon dusk to deep night — so "the whole day" is
     something you see, not only read. A coloured left edge carries the time-of-
     day; the rest stays quiet so the copy still leads. */
  .clock{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--s2)}
  .clock div{background:#fff;border:1px solid #CFE9F0;
       border-left:3px solid #CFE9F0;border-radius:var(--r-s);
       padding:15px 18px;transition:transform .2s ease,box-shadow .2s ease}
  .clock div:hover{transform:translateY(-3px);
       box-shadow:0 12px 26px rgba(31,143,173,.15)}
  .clock time{font-family:var(--mono);font-size:13px;font-weight:600;
       font-variant-numeric:tabular-nums;letter-spacing:.05em;display:block}
  .clock p{margin-top:6px;font-size:14.5px;color:var(--ink-2);line-height:1.5}
  .clock div:nth-child(1){border-left-color:var(--sea)}
  .clock div:nth-child(1) time{color:var(--sea)}          /* 06:00 dawn */
  .clock div:nth-child(2){border-left-color:var(--sun)}
  .clock div:nth-child(2) time{color:#B87A12}             /* 13:00 midday */
  .clock div:nth-child(3){border-left-color:var(--brand)}
  .clock div:nth-child(3) time{color:var(--brand)}        /* 18:00 dusk */
  .clock div:nth-child(4){border-left-color:var(--night)}
  .clock div:nth-child(4) time{color:var(--night)}        /* 22:00 night */
  @media (max-width:960px){.going{grid-template-columns:1fr;gap:36px}}

  /* ---------- Photography ----------
     The photographs are the argument this page makes — that we actually
     know this city. These rules make them behave like a set rather than
     seven unrelated stock images.

     1. Reveal: fade + rise into view. opacity/transform only, so it stays
        on the compositor.
     2. Hover: the card lifts, the photo pushes in slightly past the frame,
        and a warm brand wash comes up from the bottom — the photo reacts,
        not just the container. */
  /* Scroll-driven in CSS, not JS. A JS reveal that sets opacity:0 and waits
     for an observer can strand content invisible if the callback never runs
     (background tab, odd embedding, blocked script) — an unacceptable failure
     on a page whose entire job is looking credible. With animation-timeline
     the hidden state only exists where the browser can also animate it out;
     everywhere else the content simply renders. */
  @supports (animation-timeline: view()){
    /* One vocabulary, extended: everything that enters gets the same gentle
       fade-and-lift the day cards already used. Scroll-driven in CSS, so no JS
       and no scroll-jacking; grouped rows get a small per-item range offset so
       they cascade instead of snapping in together. */
    .day .slot,.strip figure,
    .sec-head,.qa .q,.routes .route,.founders .person,.stats .stat,
    .going > div:first-child,.clock > div,.handoff{
         animation:rise-in linear both;
         animation-timeline:view();animation-range:entry 0% entry 50%}
    .day .slot:nth-child(2),.qa .q:nth-child(2),.routes .route:nth-child(2),
    .founders .person:nth-child(2),.stats .stat:nth-child(2),.clock > div:nth-child(2){
         animation-range:entry 7% entry 57%}
    .day .slot:nth-child(3),.routes .route:nth-child(3),.stats .stat:nth-child(3),
    .clock > div:nth-child(3){animation-range:entry 14% entry 64%}
    .day .slot:nth-child(4),.routes .route:nth-child(4),.clock > div:nth-child(4){
         animation-range:entry 21% entry 71%}

    /* Hero parallax: the photograph drifts a touch slower than the page as you
       scroll off it, so leaving the hero has depth. It's on the oversized
       <picture> (see hero block), so the drift never opens an edge; the range
       is the whole time the hero is on screen. reduced-motion opts out. */
    @media (prefers-reduced-motion:no-preference){
      .hero picture{animation:hero-par linear both;
           animation-timeline:view();animation-range:cover 0% cover 100%}
    }
  }
  /* A little more travel and a hair of scale, so the lift reads as a considered
     settle rather than a flat fade. Still opacity+transform only — compositor. */
  @keyframes rise-in{from{opacity:0;transform:translateY(28px) scale(.985)}
                     to{opacity:1;transform:none}}
  @keyframes hero-par{from{transform:translateY(-4%)}to{transform:translateY(4%)}}

  /* Hero copy: a one-time staggered entrance on load. The hero image is the LCP
     element and settles on its own; this is only the text, so animating opacity
     costs nothing measurable. The hidden state lives only in the keyframe, so
     reduced-motion (which drops the animation) leaves the text fully visible. */
  .hero-copy > *{animation:fade-up .55s cubic-bezier(.2,.7,.3,1) both}
  .hero-copy > :nth-child(1){animation-delay:.05s}
  .hero-copy > :nth-child(2){animation-delay:.12s}
  .hero-copy > :nth-child(3){animation-delay:.19s}
  .hero-copy > :nth-child(4){animation-delay:.26s}
  .hero-copy > :nth-child(5){animation-delay:.33s}
  @keyframes fade-up{from{opacity:0;transform:translateY(14px)}
                     to{opacity:1;transform:none}}

  .slot figure{position:relative}
  .slot figure::after{content:"";position:absolute;inset:0;pointer-events:none;
       background:linear-gradient(to top,rgba(146,27,88,.22),rgba(146,27,88,0) 58%);
       opacity:0;transition:opacity .4s ease}
  .slot:hover figure::after{opacity:1}
  .slot:hover{transform:translateY(-6px);box-shadow:0 22px 48px rgba(72,40,20,.18)}
  .slot:hover img{transform:scale(1.07)}

  /* The venue showcase carries more weight than a plain image: a soft
     warm shadow so it sits on the page rather than in it. */
  .strip figure{box-shadow:0 24px 60px rgba(72,40,20,.16)}
  .strip img{transition:transform .6s cubic-bezier(.2,.7,.3,1)}
  .strip figure:hover img{transform:scale(1.04)}

  @media (prefers-reduced-motion:reduce){
    *{transition:none!important;animation:none!important}
    .city video{display:none}
    /* Never leave revealed content stuck invisible. */
    .reveal{opacity:1!important;transform:none!important}
    /* Safe now that the still is its own element: hiding the video leaves the
       photograph behind it, not an empty band. */
    /* The daylight wash stays: it is set once from the clock and never moves
       again, so there is no motion here to opt out of. */
  }
