/* ============================================================
   VICTORIA HAUS - four homes, Victoria Drive at East 23rd
   Japandi language: warm neutrals, generous air, one accent.
   Structure follows brockhouse.ca; unit selector follows the
   keyplan + named-unit pattern.
   ============================================================ */
:root{
  --ink:#1B1A17;
  --ink-2:#3E3C36;
  --paper:#F7F5F0;
  --sand:#EDE8DE;
  --sand-2:#E3DCCE;
  --line:#DAD3C4;
  --moss:#5A6650;
  --moss-lt:#7C876F;
  --clay:#B4714E;
  --muted:#7A756B;

  /* 1440 left ~590px dead on each side of a 27" 2560px display - nearly half
     the screen. 1680 keeps text columns readable while using the room. */
  --shell:1680px;
  --gutter:clamp(20px, 4vw, 72px);
  --band:clamp(64px, 9vw, 148px);
  --gap:clamp(18px, 2.2vw, 34px);
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{font-family:'Inter',system-ui,sans-serif;background:var(--paper);color:var(--ink);
  font-size:17px;line-height:1.65;-webkit-font-smoothing:antialiased;overflow-x:hidden}
img{max-width:100%;display:block}
/* The visible page background lives here, not on <body>: body now carries the
   Safari toolbar tint. Must stay in normal flow, not fixed. A fixed overlay
   the size of the viewport gets sampled instead of the body and the tint is
   lost (measured on an iPhone: a 1px fixed strip is ignored, a full-screen
   one is not). */
.page{background:var(--paper);position:relative;z-index:0}
/* Safari 26 takes the toolbar colour from a fixed layer the size of the
   viewport, and only from one that size: measured on an iPhone, a 1px fixed
   strip is ignored and the body is used instead, which then went white at
   scroll 0. This layer sits behind the opaque .page, so it is never seen,
   and it holds the colour steady wherever the page is scrolled. */
/* ---------- the two bars iOS tints ----------
   iOS 26 Safari ignores theme-color. It picks a fixed element that reaches a
   screen edge and is at least 80% of the viewport wide, reads its computed
   background-color, and decides from the alpha alone: alpha of exactly 1 gives
   a solid bar in that colour, any alpha between 0 and 1 gives glass, and alpha
   0 means skip this one and try the next.

   Build 038, correcting 037 on a real iPhone. 037 split this into a top
   sampler at 55vh and #chin at the bottom so the two bars could differ, and
   made the top solid at rest. Two things were wrong with that. The address bar
   sits at the bottom on a default iPhone and at the top only if you move it,
   so "solid at rest" was visible either way and is not what anyone wants over
   a full-bleed hero. And 55vh contradicts the measurement recorded directly
   above: a fixed layer that is not the size of the viewport is passed over and
   the opaque body is read instead, which is solid whatever alpha this carries.

   So the two bars no longer differ. This is back to inset:0, the geometry
   measured to be sampled, and it is glass in every state: same per-page colour
   as before at 96% alpha, which reads as glass because the alpha is a yes/no
   switch for "see through" rather than a dial. #chin is glass, .veil is glass
   at 42%, and every other candidate is out of the render tree, so whichever
   one Safari picks the answer is the same. That agreement is the whole point;
   which candidate wins is not predictable. */
.tint{position:fixed;inset:0;background-color:var(--tint-glass,var(--tint));
  z-index:-1;pointer-events:none}

/* The bottom sampler: real, sampled, and paints nothing. opacity:0 does not
   remove it from the render tree, which is exactly why it works. Do not give
   it a backdrop-filter (forces a compositing layer and renders a seam) and do
   not put it at z-index:-1 (it becomes page canvas and tints both bars). */
#chin{position:fixed;bottom:-14px;left:0;width:100%;height:14px;min-height:14px;
  z-index:5;margin:0;padding:0;pointer-events:none;opacity:0;display:none;
  background-color:rgba(255,255,255,.02)}
/* iPhone only. This @supports trio is the reliable sniff; nothing here can
   reach Android, iPad or the desktop.

   Build 042. Everything in this block exists to satisfy one line of
   CHIN-iOS-SAFARI.md: in the resting state, #chin must be the only element
   reaching the bottom edge. Builds 038 to 041 tried to satisfy a weaker rule I
   invented instead, that every candidate must merely agree on glass, and it
   does not hold. Four full-screen layers each at 96% alpha are each glass on
   their own and opaque once stacked, which is why the homepage was right and
   the four pages carrying .vh-ground were not: one layer there, two here.
   Giving .vh-ground a colour in 039 added a second dense layer rather than
   taking it off the edge, which is why that round made no difference.

   So the others leave the bottom edge instead of arguing over its colour.
   .tint keeps the top, where a solid bar is fine and wanted, and stops short.
   .veil leaves the render tree while the menu is shut, because
   visibility:hidden keeps a layout box and keeps it a candidate. */
@supports (-webkit-text-size-adjust:none) and (font:-apple-system-body) and (-webkit-touch-callout:none){
  @media(max-width:760px){
    #chin{display:block}
    /* so an absolutely positioned .vh-ground still covers the document */
    body{position:relative}
    .tint{bottom:auto;height:55vh}
    .veil{display:none}
    body.menu-open .veil{display:block}
  }
}

a{color:inherit}
::selection{background:var(--moss);color:#fff}
.display{font-family:'Jost',var(--fallback),sans-serif;font-weight:300;letter-spacing:-.015em}
.wrap{width:100%;max-width:var(--shell);margin-inline:auto;padding-inline:var(--gutter)}
body{animation:pagein .6s ease both}
@keyframes pagein{from{opacity:0}to{opacity:1}}

/* ---------- NAV ---------- */
/* body > nav, not nav: the drawer now carries its own <nav> and the unscoped
   rule would pin it to the top of the viewport. */
/* Build 038: the 2% white is not decoration, and it is not visible either. The
   header is fixed, full width and touching the top edge, which makes it one of
   the elements iPhone Safari may sample for the toolbar colour, and at rest it
   declared no background-color at all. An undeclared colour is the one case
   that does not politely pass to the next candidate: it resolves against the
   opaque body and gives a solid bar. Two percent is enough to carry an alpha,
   which is all Safari reads, and it agrees with .tint and #chin. */
body > nav{position:fixed;inset:0 0 auto 0;z-index:90;color:#fff;
  background-color:rgba(255,255,255,.02);
  transition:background .45s ease,box-shadow .45s ease}

/* viewport-fit:cover lets the page run under the notch, so anything fixed to
   the top has to add the inset back or it sits beneath the status bar. */
body > nav{padding-top:env(safe-area-inset-top)}
body > nav .nav-in{max-width:var(--shell);margin-inline:auto;padding:26px var(--gutter);
  display:flex;align-items:center;justify-content:space-between;gap:26px;transition:padding .45s ease}
body > nav.solid{background:rgba(247,245,240,.94);backdrop-filter:blur(14px);color:var(--ink);
  box-shadow:0 1px 0 rgba(0,0,0,.07)}
body > nav.solid .nav-in{padding-block:16px}

/* Scrim behind the header only. Measured on the hero video, the brightest sky
   under the wordmark read 3.35:1 against white, below the 4.5:1 minimum. The
   hero's own shade is too soft at the top, and darkening the whole thing would
   dull the image, so this is a short gradient that dies inside the header band
   and lifts away the moment the nav goes solid. */
body > nav::before{content:"";position:absolute;left:0;right:0;top:0;height:190%;
  z-index:-1;pointer-events:none;transition:opacity .45s ease;
  background:linear-gradient(to bottom,rgba(12,14,16,.5) 0%,rgba(12,14,16,.28) 45%,rgba(12,14,16,0) 100%)}
body > nav.solid::before{opacity:0}

/* RK: the wordmark read small and thin against the hero. Up two steps in
   size and from 300 to 500, with the tracking eased off so the extra
   weight does not make it sprawl. */
.logo{font-family:'Jost',sans-serif;font-weight:500;font-size:clamp(20px,1.8vw,26px);
  letter-spacing:.16em;text-transform:uppercase;text-decoration:none;white-space:nowrap;line-height:1.12}
.logo b{display:block;font-weight:500}
/* RK: the two projects navigated identically. Victoria Haus is four homes, so
   it drops the written menu at every width and keeps only the mark and the
   button. The links are not lost, they move into a full-screen drawer that has
   room to carry the register call and the contact details as well. */
body > nav ul{display:none}
body > nav a.nl{text-decoration:none;font-size:12px;font-weight:500;letter-spacing:.16em;
  text-transform:uppercase;position:relative;padding:4px 0;white-space:nowrap}
body > nav a.nl::after{content:"";position:absolute;left:0;bottom:0;width:0;height:1px;background:currentColor;
  transition:width .4s cubic-bezier(.7,0,.3,1)}
body > nav a.nl:hover::after,body > nav a.nl.active::after{width:100%}
body > nav a.reg{text-decoration:none;font-size:11.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  border:1px solid currentColor;padding:11px 24px;transition:background .35s,color .35s,border-color .35s;
  white-space:nowrap}
body > nav a.reg:hover{background:var(--moss);border-color:var(--moss);color:#fff}

.burger{display:grid;place-items:center;width:56px;height:56px;border:1px solid transparent;
  border-radius:50%;transition:border-color .4s ease,background .4s ease;border:0;background:transparent;cursor:pointer;
  position:relative;color:inherit;flex-shrink:0;margin-right:-10px}
.burger:hover{border-color:currentColor}
.burger i{position:absolute;left:17px;width:22px;height:1.4px;background:currentColor;
  transition:transform .38s cubic-bezier(.2,.7,.2,1),opacity .2s}
.burger i:nth-child(1){top:23px}.burger i:nth-child(2){top:29px}.burger i:nth-child(3){top:35px}
body.menu-open .burger i:nth-child(1){transform:translateY(6px) rotate(45deg)}
body.menu-open .burger i:nth-child(2){opacity:0}
body.menu-open .burger i:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
/* ---------- MENU: side panel ----------
   Not a full-screen takeover. It slides in from the right over a soft veil, so
   the project stays visible behind it, and the top of the panel carries a
   photograph that changes with the page you are on: the menu is one more place
   the project is sold rather than a list of four words. */
.veil{position:fixed;inset:0;z-index:84;background:rgba(27,26,23,.42);backdrop-filter:blur(2px);
  opacity:0;visibility:hidden;transition:opacity .5s ease,visibility .5s}
body.menu-open .veil{opacity:1;visibility:visible}

.drawer{position:fixed;top:0;right:0;bottom:0;z-index:86;width:min(460px,78vw);
  background:var(--paper);color:var(--ink);display:flex;flex-direction:column;overflow:auto;
  transform:translateX(100%);transition:transform .55s cubic-bezier(.2,.75,.2,1);
  box-shadow:-30px 0 70px rgba(27,26,23,.18)}
body.menu-open .drawer{transform:none}
body.menu-open{overflow:hidden}

.d-pic{position:relative;height:40%;min-height:210px;flex-shrink:0;overflow:hidden;background:var(--sand)}
.d-pic img{width:100%;height:100%;object-fit:cover;transform:scale(1.07);
  transition:transform 1.5s cubic-bezier(.2,.7,.2,1)}
body.menu-open .d-pic img{transform:none}
.d-pic::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,rgba(15,14,12,.55),transparent 58%)}
.d-pic span{position:absolute;left:clamp(20px,2.4vw,30px);bottom:16px;z-index:2;color:#fff;
  font-family:'Jost',sans-serif;font-weight:300;font-size:19px}

.d-body{padding:clamp(24px,3vw,38px);display:flex;flex-direction:column;justify-content:center;flex:1}
.drawer a{display:flex;align-items:baseline;gap:14px;text-decoration:none;color:inherit;
  font-family:'Jost',sans-serif;font-weight:300;font-size:clamp(24px,3vw,30px);
  padding:14px 0;border-bottom:1px solid var(--line);
  opacity:0;transform:translateX(14px);
  transition:opacity .45s ease,transform .45s cubic-bezier(.2,.7,.2,1),color .3s}
body.menu-open .drawer a{opacity:1;transform:none}
body.menu-open .d-body a:nth-of-type(1){transition-delay:.14s}
body.menu-open .d-body a:nth-of-type(2){transition-delay:.2s}
body.menu-open .d-body a:nth-of-type(3){transition-delay:.26s}
body.menu-open .d-body a:nth-of-type(4){transition-delay:.32s}
.drawer a:hover{color:var(--clay)}
.d-num{font-family:'Inter',sans-serif;font-size:10.5px;font-weight:600;letter-spacing:.2em;
  color:var(--muted)}

.drawer a.d-go{display:inline-block;align-self:flex-start;margin-top:26px;border-bottom:0;
  background:var(--clay);color:#fff;font-family:'Inter',sans-serif;font-size:11px;font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;padding:14px 26px;
  transition:background .35s,color .35s,opacity .45s,transform .45s}
body.menu-open .drawer a.d-go{transition-delay:.38s}
.drawer a.d-go:hover{background:var(--ink);color:var(--paper)}
.drawer .d-meta{margin-top:28px;font-size:13.5px;line-height:1.85;color:var(--muted);
  opacity:0;transition:opacity .5s .44s}
body.menu-open .drawer .d-meta{opacity:1}
.drawer a.d-mail{display:inline;font-family:inherit;font-size:13.5px;padding:0;border:0;
  color:var(--muted);opacity:1;transform:none}
.drawer a.d-mail:hover{color:var(--ink)}

/* The panel covers the header, so the burger underneath cannot close it. The
   close button lands exactly where the burger was, reading as the same control. */
.d-close{position:fixed;top:calc(env(safe-area-inset-top) + 26px);right:var(--gutter);z-index:96;
  width:56px;height:56px;border:1px solid var(--line);border-radius:50%;background:var(--paper);
  color:var(--ink);font-size:19px;cursor:pointer;display:none;place-items:center;
  transition:background .3s,color .3s,border-color .3s}
.d-close:hover{background:var(--ink);border-color:var(--ink);color:var(--paper)}
body.menu-open .d-close{display:grid}
@media(max-width:520px){.d-pic{height:32%;min-height:160px}}
@media(max-width:960px){
  nav .nav-in{padding-block:18px}nav.solid .nav-in{padding-block:14px}
}
body > nav{z-index:95}
body.menu-open > nav{background:transparent;box-shadow:none;color:var(--paper)}

/* ---------- HERO ---------- */
.hero{position:relative;height:clamp(560px,100svh,1020px);overflow:hidden;display:flex;
  align-items:flex-end;color:#fff;background:var(--ink)}
.hero.sub{height:clamp(420px,66svh,700px)}
/* isolate matters here. The master layer carries z-index:2 so it stacks over
   the opener, but .media had no stacking context of its own, so that 2 was
   competing in the header's own context and the video was painting over the
   gradient and the title. The h1 only appeared while the video was faded out,
   which is exactly what it looked like: a still with the title on it. */
.hero .media{position:absolute;inset:0;overflow:hidden;isolation:isolate}
.hero .media img,.hero .media video{position:absolute;top:-12%;left:0;width:100%;height:124%;
  object-fit:cover;will-change:transform}
.hero .media img{animation:heroZoom 2.6s cubic-bezier(.2,.6,.2,1) both}
.hero .media video{opacity:0;transition:opacity 1.1s}
.hero .media video.playing{opacity:1}

/* Two-layer hero. The opener sits under the master; the master is transparent
   until it has been seeked into position, so a slow connection simply never
   reveals it and the visitor keeps watching the light version instead of a
   still. Both are the same clip and the same length, so the swap is invisible. */
.hero .media video.v-hq{opacity:0;transition:opacity .5s ease;z-index:2}
.hero .media video.v-hq.playing{opacity:1}

/* Replay dissolve. The clip's last frame does not match its first, so a plain
   loop cuts. Fading out over the tail lands on the still underneath, which is
   the video's own first frame, so restarting from there is invisible: the only
   transition anyone sees is the end dissolving into the beginning. */
video.fading{opacity:0 !important;transition:opacity .7s ease}


/* In-page video: sits over the still inside .frame, same box, and fades in once
   it plays. pointer-events:none so the frame keeps opening the lightbox. */
.frame{position:relative}
/* No z-index on purpose: DOM order alone puts the video above the still and
   below the block's ::after scrim and its text. Giving it z-index:1 lifted it
   over the scrim and the caption lost itsbacking. */
.frame .fig-vid{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity 1s ease;pointer-events:none}
.frame .fig-vid.playing{opacity:1}
.frame .fig-vid.fading{opacity:0 !important}


@keyframes heroZoom{from{transform:scale(1.09)}to{transform:scale(1.01)}}

/* The still under a video hero has to be that video's own first frame, or the
   fade-in is a dissolve between two different photographs: measured at 83% of
   pixels changing on the homes header. For the same reason the still cannot
   keep its zoom while the video sits static underneath, so the animation is
   dropped wherever a video is present. */
.hero .media:has(video) img{animation:none;transform:scale(1.02)}
.hero .shade{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to top,rgba(15,14,12,.66) 0%,rgba(15,14,12,.08) 52%,rgba(15,14,12,.30) 100%)}
.hero-inner{position:relative;width:100%;max-width:var(--shell);margin-inline:auto;
  padding:0 var(--gutter) clamp(52px,7vh,92px)}
.hero h1{font-size:clamp(38px,6.4vw,88px);line-height:1.04;font-weight:300}
/* The .ln mask that drives the line-by-line reveal was clipping descenders:
   a line-height under 1 makes the line box shorter than the glyphs, so the
   tails of g, y, q and the comma fell outside overflow:hidden. The padding
   gives them room and the matching negative margin gives the space back, so
   the line spacing is unchanged. */
.hero h1 .ln{display:block;overflow:hidden;padding-bottom:.18em;margin-bottom:-.12em}
.hero h1 .ln span{display:block;transform:translateY(112%);
  animation:lineUp 1.05s cubic-bezier(.2,.7,.2,1) forwards}
.hero h1 .ln:nth-child(2) span{animation-delay:.13s}
@keyframes lineUp{to{transform:translateY(0)}}
.hero .sub-copy{margin-top:22px;font-size:clamp(15px,1.15vw,17.5px);max-width:46ch;line-height:1.65;
  opacity:0;animation:fadeUp 1s .5s ease forwards;color:#EDEAE3}
@keyframes fadeUp{from{opacity:0;transform:translateY(22px)}to{opacity:1;transform:none}}
.hero .scrollcue{position:absolute;right:var(--gutter);bottom:clamp(52px,7vh,92px);font-size:10.5px;
  letter-spacing:.24em;text-transform:uppercase;writing-mode:vertical-rl;opacity:0;
  animation:fadeUp 1s .8s ease forwards}
.hero .scrollcue::after{content:"";display:block;width:1px;height:52px;background:#fff;margin:14px auto 0;
  animation:cue 1.9s ease infinite}
@keyframes cue{0%{transform:scaleY(0);transform-origin:top}45%{transform:scaleY(1);transform-origin:top}
  55%{transform:scaleY(1);transform-origin:bottom}100%{transform:scaleY(0);transform-origin:bottom}}

/* dark page head */
.page-head{background:var(--ink);color:var(--paper);position:relative;overflow:hidden;
  padding:calc(96px + clamp(56px,7vw,104px)) 0 clamp(52px,6vw,88px)}
.page-head h1{font-size:clamp(34px,5.4vw,74px);line-height:1.05;font-weight:300}
/* The .ln mask that drives the line-by-line reveal was clipping descenders:
   a line-height under 1 makes the line box shorter than the glyphs, so the
   tails of g, y, q and the comma fell outside overflow:hidden. The padding
   gives them room and the matching negative margin gives the space back, so
   the line spacing is unchanged. */
.page-head h1 .ln{display:block;overflow:hidden;padding-bottom:.18em;margin-bottom:-.12em}
.page-head h1 .ln span{display:block;transform:translateY(112%);
  animation:lineUp 1.05s cubic-bezier(.2,.7,.2,1) forwards}
.page-head h1 .ln:nth-child(2) span{animation-delay:.13s}
.page-head p{margin-top:20px;color:#B0AAA0;font-size:clamp(15px,1.15vw,17.5px);max-width:56ch;line-height:1.7}

/* ---------- SECTIONS ---------- */
section{padding-block:var(--band)}
.page-head + section{padding-top:clamp(46px,6vw,92px)}
.kicker{display:flex;align-items:center;gap:14px;color:var(--moss);font-size:11px;font-weight:600;
  letter-spacing:.26em;text-transform:uppercase;margin-bottom:24px}
.kicker::before{content:"";width:38px;height:1px;background:var(--moss);flex-shrink:0}
h2.title{font-size:clamp(28px,4vw,58px);line-height:1.1;max-width:17ch;font-weight:300}
.lead{margin-top:24px;font-size:clamp(15.5px,1.2vw,18px);line-height:1.8;color:var(--ink-2);max-width:58ch}
.note{font-size:13px;color:var(--muted);line-height:1.7}

.reveal{opacity:0;transform:translateY(30px);
  transition:opacity 1s cubic-bezier(.2,.7,.2,1),transform 1s cubic-bezier(.2,.7,.2,1)}
.reveal.in{opacity:1;transform:none}
.reveal.d1{transition-delay:.12s}.reveal.d2{transition-delay:.24s}.reveal.d3{transition-delay:.36s}
@media(prefers-reduced-motion:reduce){
  .reveal{opacity:1;transform:none;transition:none}
  *{animation-duration:.01ms !important;animation-iteration-count:1 !important}
}

.frame{overflow:hidden;position:relative;background:var(--sand)}
.frame > img{width:100%;height:100%;object-fit:cover}
.frame img{transition:transform 1.3s cubic-bezier(.2,.7,.2,1);will-change:transform}
.frame:hover img{transform:scale(1.045)}
.cap{position:absolute;left:18px;bottom:16px;background:rgba(20,19,16,.55);color:#fff;font-size:11.5px;
  letter-spacing:.06em;padding:7px 14px;backdrop-filter:blur(6px)}
.bleed{position:relative;overflow:hidden}
.bleed img{width:100%;height:100%;object-fit:cover}

/* stats */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--gap);margin-top:clamp(46px,5vw,78px)}
.stat{border-top:1px solid var(--line);padding-top:24px}
.stat b{font-family:'Jost',sans-serif;font-size:clamp(32px,3.4vw,52px);font-weight:300;display:block;line-height:1}
.stat small{display:block;margin-top:10px;font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
@media(max-width:820px){.stats{grid-template-columns:repeat(2,1fr)}}

/* buttons */
.btn{display:inline-flex;align-items:center;gap:12px;text-decoration:none;font-weight:600;font-size:12px;
  letter-spacing:.14em;text-transform:uppercase;padding:17px 32px;border:1px solid var(--ink);
  transition:background .35s,color .35s,border-color .35s;cursor:pointer;font-family:inherit;background:transparent;color:var(--ink)}
.btn .arr{transition:transform .35s}
.btn:hover .arr{transform:translateX(5px)}
.btn:hover{background:var(--ink);color:var(--paper)}
.btn-solid{background:var(--ink);color:var(--paper)}
.btn-solid:hover{background:var(--moss);border-color:var(--moss);color:#fff}
.btn-light{border-color:var(--paper);color:var(--paper)}
.btn-light:hover{background:var(--paper);color:var(--ink)}

/* ---------- REGISTER ---------- */
.register{background:var(--ink);color:var(--paper);position:relative;overflow:hidden}
.register .inner{display:grid;grid-template-columns:1.05fr 1fr;gap:clamp(34px,5vw,90px);
  padding-block:var(--band);align-items:start}
.register h2{font-size:clamp(28px,3.8vw,54px);line-height:1.1;font-weight:300}
.register p{margin-top:20px;color:#ADA79D;line-height:1.8;max-width:44ch}
.register form{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-content:start}
.register input,.register select{width:100%;padding:16px 18px;border:1px solid rgba(255,255,255,.2);
  font-size:15px;font-family:inherit;background:rgba(255,255,255,.05);color:#fff;
  transition:border-color .3s,background .3s;border-radius:0}
.register input::placeholder{color:#8E887E}
.register select{color:#8E887E}
.register input:focus,.register select:focus{outline:none;border-color:var(--moss-lt);background:rgba(255,255,255,.09)}
.register .full{grid-column:1/-1}
.register button{grid-column:1/-1;background:var(--paper);color:var(--ink);border:0;padding:18px;
  font-weight:600;font-size:12px;letter-spacing:.14em;text-transform:uppercase;cursor:pointer;
  font-family:inherit;transition:background .3s,color .3s}
.register button:hover{background:var(--moss);color:#fff}
.register .consent{grid-column:1/-1;font-size:11.5px;line-height:1.7;color:#8E887E;margin-top:2px}
@media(max-width:900px){.register .inner{grid-template-columns:1fr;gap:38px}.register form{grid-template-columns:1fr}}

/* ---------- FOOTER ---------- */
/* ============================================================
   FOOTER
   RK: it read as a WordPress strip. Three bands now: brand and navigation, the
   credits with both studio marks, then the legal line. The project mark is the
   same two-line Jost lockup as the header, because it cannot change between the
   two, which is what it was doing.
   ============================================================ */
footer{background:#100F0D;color:#8A857C;font-size:14px;line-height:1.7;
  padding-block:clamp(56px,7vw,96px) clamp(26px,3vw,40px)}
footer a{color:#CFC9BE;text-decoration:none;transition:color .3s}
footer a:hover{color:#fff}

.f-top{display:grid;grid-template-columns:1.1fr 1.7fr;gap:clamp(36px,5vw,90px)}
.f-mark{display:block;font-family:'Jost',sans-serif;font-weight:500;
  font-size:clamp(24px,2.4vw,32px);letter-spacing:.16em;text-transform:uppercase;
  color:#fff;line-height:1.14}
.f-mark b{display:block;font-weight:500}
.f-brand p{margin-top:20px;max-width:46ch;color:#8A857C}

.f-cols{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(22px,3vw,44px)}
.f-cols h4{font-size:10.5px;font-weight:700;letter-spacing:.22em;text-transform:uppercase;
  color:#615D55;margin-bottom:16px}
.f-cols a,.f-cols span{display:block;padding:5px 0;font-size:14px}
.f-cols span{color:#8A857C}
.f-cta{margin-top:10px;font-weight:600;color:var(--clay) !important}
.f-cta:hover{color:#fff !important}

/* Both marks are sized off their wordmark, not their box: Twinlines carries
   STUDIO underneath, so equal box heights would leave its name a third smaller
   than Dreamlife's. Measured on the artwork, its box is 1.619x its wordmark, and
   Dreamlife needs 1.35x on top of that to balance against a bold serif. */
.f-credits{--mark:22px;
  margin-top:clamp(44px,5vw,72px);padding-top:clamp(26px,3vw,38px);
  border-top:1px solid rgba(255,255,255,.1);
  display:flex;align-items:center;gap:clamp(28px,5vw,72px);flex-wrap:wrap}
.credit{display:flex;align-items:center;gap:14px}
.credit small{font-size:10.5px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;
  color:#615D55;white-space:nowrap}
.credit .mk{display:block;width:auto;opacity:.92;transition:opacity .3s}
.credit a:hover .mk{opacity:1}
.credit .mk.dl{height:calc(var(--mark) * 1.35)}
.credit .mk.tl{height:calc(var(--mark) * 1.619)}
.f-demo{margin-left:auto}

.f-legal{margin-top:clamp(26px,3vw,38px);padding-top:22px;
  border-top:1px solid rgba(255,255,255,.1);
  display:flex;justify-content:space-between;align-items:baseline;gap:14px 40px;
  flex-wrap:wrap;font-size:11.5px;line-height:1.7;color:#615D55}
.f-legal p{max-width:none;flex:1 1 auto}
.f-copy{white-space:nowrap}

@media(max-width:900px){
  .f-top{grid-template-columns:1fr;gap:34px}
  .f-cols{grid-template-columns:1fr 1fr}
}
@media(max-width:560px){
  .f-cols{grid-template-columns:1fr}
  .f-credits{--mark:19px;gap:22px}
  .f-demo{margin-left:0}
}

@media(max-width:700px){footer .f-in{flex-direction:column}}

/* ---------- LIGHTBOX ---------- */
.lb{position:fixed;inset:0;z-index:200;background:rgba(16,15,13,.95);backdrop-filter:blur(6px);
  display:none;align-items:center;justify-content:center;opacity:0;transition:opacity .3s}
.lb.open{display:flex}.lb.show{opacity:1}
.lb-stage{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center;
  padding:clamp(56px,8vh,90px) clamp(16px,6vw,96px);overflow:hidden}
.lb-stage img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
  box-shadow:0 30px 90px rgba(0,0,0,.5);cursor:zoom-in;transform-origin:center;user-select:none;
  transition:transform .34s cubic-bezier(.2,.7,.2,1),opacity .28s}
.lb-stage video{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
  display:block;background:#000}
/* The hint belongs to stills. A clip arrives with its own controls, and telling
   someone to click it to zoom would be a lie. */
.lb.is-video .lb-zoomhint{display:none}
.lb-stage img.zoomed{cursor:grab;transition:transform .18s ease-out}
.lb-stage img.zoomed.grabbing{cursor:grabbing;transition:none}
.lb-close,.lb-prev,.lb-next{position:absolute;z-index:3;border:0;cursor:pointer;color:#fff;
  background:rgba(255,255,255,.12);backdrop-filter:blur(8px);border-radius:50%;display:grid;
  place-items:center;transition:background .3s,transform .3s}
.lb-close{top:clamp(14px,2.4vh,26px);right:clamp(14px,2.4vw,30px);width:48px;height:48px;font-size:18px}
.lb-close:hover{background:var(--clay);transform:rotate(90deg)}
.lb-prev,.lb-next{top:50%;margin-top:-28px;width:56px;height:56px;font-size:22px}
.lb-prev{left:clamp(10px,1.8vw,26px)}.lb-next{right:clamp(10px,1.8vw,26px)}
.lb-prev:hover,.lb-next:hover{background:var(--moss)}
.lb-bar{position:absolute;left:0;right:0;bottom:0;z-index:3;
  padding:0 clamp(14px,3vw,30px) clamp(14px,2.4vh,26px);
  display:flex;justify-content:space-between;align-items:flex-end;gap:16px;color:#fff;pointer-events:none}
.lb-cap{font-size:13.5px;line-height:1.5;max-width:56ch;pointer-events:auto;
  background:rgba(18,17,15,.88);backdrop-filter:blur(10px);padding:14px 20px}
.lb-cap b{display:block;font-family:'Jost',sans-serif;font-weight:400;font-size:18px;margin-bottom:4px}
.lb-count{font-size:11.5px;letter-spacing:.16em;white-space:nowrap;pointer-events:auto;
  background:rgba(18,17,15,.88);backdrop-filter:blur(10px);padding:11px 17px;color:#CFC9BE}
.lb-zoomhint{position:absolute;top:clamp(14px,2.4vh,26px);left:clamp(14px,2.4vw,30px);z-index:3;
  font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:#CFC9BE;
  background:rgba(255,255,255,.09);padding:9px 16px;backdrop-filter:blur(8px);transition:opacity .25s}
.lb.is-zoomed .lb-bar,.lb.is-zoomed .lb-zoomhint,
.lb.is-zoomed .lb-prev,.lb.is-zoomed .lb-next{opacity:0;pointer-events:none}
.lb-prev,.lb-next,.lb-bar{transition:opacity .25s}
@media(max-width:700px){
  .lb-prev,.lb-next{width:44px;height:44px;margin-top:-22px;font-size:18px}
  .lb-zoomhint{display:none}.lb-cap b{font-size:16px}.lb-cap{font-size:12.5px}
}

/* ---------- SMALL SCREENS ---------- */
@media(max-width:900px){
  .hero .scrollcue{display:none}
  .hero .sub-copy{max-width:none}
  h2.title{max-width:none}
}

/* ---------- interactive map ----------
   The map lives in an iframe because it is a self-contained page. The frame
   gives it the site's picture-frame treatment; the height is set from the
   parent once the map has drawn itself. */
.mapframe{position:relative;margin-top:clamp(30px,4vw,52px);background:#fff;
  border:1px solid var(--line);box-shadow:0 24px 60px rgba(27,26,23,.09);overflow:hidden}
.mapframe iframe{display:block;width:100%;height:820px;border:0;background:#fff}
.map-wait{position:absolute;inset:0;display:grid;place-items:center;pointer-events:none;
  background:#fff;color:var(--muted);font-size:13px;letter-spacing:.18em;text-transform:uppercase;
  transition:opacity .6s ease}
@media(max-width:700px){.mapframe iframe{height:900px}}

/* ---------- page headers carry a picture, not a flat panel ----------
   A solid colour block with a line of type in it is the thing that reads as a
   template. The photograph sits well under the surface here: low opacity, under
   a gradient of the same base colour, so the type keeps its contrast and the
   header stops being an empty rectangle. It drifts on scroll with everything
   else, and it is oversized past the drift so no edge can appear. */
.page-head .ph-media{position:absolute;top:-12%;left:0;right:0;bottom:-12%;
  overflow:hidden;pointer-events:none;will-change:transform}
.page-head .ph-media img{width:100%;height:100%;object-fit:cover;opacity:.38;
  animation:phZoom 16s cubic-bezier(.2,.6,.2,1) both}
.page-head .ph-media::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to bottom,rgba(27,26,23,.40) 0%,rgba(27,26,23,.70) 55%,rgba(27,26,23,.93) 100%)}
@keyframes phZoom{from{transform:scale(1.09)}to{transform:scale(1)}}
.page-head .wrap{position:relative;z-index:1}

/* The full-bleed block moves as one piece, so the still and the video that
   replaces it stay in exactly the same frame through the handover. */
.bleed-media{position:absolute;top:-12%;left:0;right:0;bottom:-12%;will-change:transform}
.bleed-media img,.bleed-media .fig-vid{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}

/* ---------- demo sales assistant ----------
   Sits above everything except the menu drawer. It inherits the project palette
   through the variables rather than carrying colours of its own, so dropping it
   into another project is a copy of two files. */
.cb{position:fixed;right:clamp(14px,2vw,28px);bottom:clamp(14px,2vw,28px);z-index:120;
  font-family:var(--cb-sans);display:flex;flex-direction:column;align-items:flex-end;gap:12px}
.cb-launch{display:flex;align-items:center;gap:11px;border:0;cursor:pointer;
  background:var(--cb-accent);color:var(--cb-on-accent);
  padding:14px 22px 14px 18px;border-radius:var(--cb-radius);
  font-family:inherit;font-size:12px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  box-shadow:0 14px 34px rgba(0,0,0,.20);
  transition:transform .4s cubic-bezier(.2,.7,.2,1),box-shadow .4s,padding .4s,gap .4s}
.cb-launch:hover{transform:translateY(-2px);box-shadow:0 20px 44px rgba(0,0,0,.26)}
.cb-ico{display:grid;place-items:center;flex-shrink:0}
.cb-label{white-space:nowrap;max-width:260px;overflow:hidden;
  transition:max-width .45s cubic-bezier(.2,.7,.2,1),opacity .3s}
.cb.cb-tight .cb-label,.cb.open .cb-label{max-width:0;opacity:0}
.cb.cb-tight .cb-launch,.cb.open .cb-launch{padding:16px;gap:0;border-radius:50%}

/* The panel is a plain div and its padding is zeroed on purpose. It used to
   be a <section>, which picked up section{padding-block:var(--band)} from
   this stylesheet and opened with a band of dead space above the header and
   below the note. The widget is meant to drop into any client site, so it
   cannot inherit the host's element defaults. */
.cb-panel{padding:0;position:absolute;right:0;bottom:0;width:min(384px,calc(100vw - 28px));
  background:var(--cb-paper);color:var(--cb-ink);border:1px solid var(--cb-line);
  border-radius:var(--cb-radius);box-shadow:0 30px 80px rgba(0,0,0,.24);
  display:flex;flex-direction:column;overflow:hidden;
  opacity:0;visibility:hidden;transform:translateY(14px) scale(.98);transform-origin:100% 100%;
  transition:opacity .38s,transform .42s cubic-bezier(.2,.75,.2,1),visibility .38s}
.cb.open .cb-panel{opacity:1;visibility:visible;transform:none;
  bottom:calc(100% + 12px)}
.cb-head{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:16px 18px;background:var(--cb-accent);color:var(--cb-on-accent)}
.cb-head b{display:block;font-family:var(--cb-display);font-weight:400;font-size:17px;letter-spacing:.01em}
.cb-head span{font-size:10px;letter-spacing:.18em;text-transform:uppercase;opacity:.72}
/* Build 027: 30px with a 15px glyph is a target you have to aim at. A real
   close control, with a drawn stroke rather than a text character so it does
   not shift with the font. */
.cb-x{display:flex;align-items:center;justify-content:center;flex:none;
  background:transparent;border:1px solid rgba(255,255,255,.22);color:inherit;
  cursor:pointer;width:44px;height:44px;border-radius:50%;margin-right:-4px;
  transition:background .3s,border-color .3s,transform .3s}
.cb-x:hover{background:rgba(255,255,255,.16);border-color:rgba(255,255,255,.4)}
.cb-x:active{transform:scale(.94)}
.cb-x svg{display:block}

/* Build 027: the fastest thing a visitor can do here is register, so it is a
   green strip across the top of the panel rather than a line of copy they
   have to reach the end of a conversation to find. */
.cb-reg{display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:13px 18px;background:#5A6650;color:#F4F1EA;text-decoration:none;
  border-bottom:1px solid rgba(0,0,0,.16);
  transition:background .35s ease}
.cb-reg:hover{background:#4C5843}
.cb-reg-t{display:block;min-width:0}
.cb-reg-t b{display:block;font-family:var(--cb-display);font-weight:400;font-size:14px;
  letter-spacing:.01em}
.cb-reg-t i{display:block;margin-top:2px;font-style:normal;font-size:11px;
  line-height:1.4;color:rgba(244,241,234,.72)}
.cb-reg-a{flex:none;font-size:16px;transition:transform .35s cubic-bezier(.2,.7,.2,1)}
.cb-reg:hover .cb-reg-a{transform:translateX(4px)}
@media(prefers-reduced-motion:reduce){
  .cb-reg-a,.cb-x{transition:none}
  .cb-reg:hover .cb-reg-a{transform:none}}

.cb-log{padding:18px;display:flex;flex-direction:column;gap:11px;
  max-height:min(46vh,380px);overflow-y:auto;overscroll-behavior:contain}
.cb-msg{font-size:14.5px;line-height:1.6;padding:11px 14px;max-width:88%;
  animation:cbIn .38s cubic-bezier(.2,.7,.2,1) both}
@keyframes cbIn{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
.cb-bot{background:var(--cb-sand);align-self:flex-start;border-radius:var(--cb-bubble) var(--cb-bubble) var(--cb-bubble) 2px}
.cb-me{background:var(--cb-accent);color:var(--cb-on-accent);align-self:flex-end;
  border-radius:var(--cb-bubble) var(--cb-bubble) 2px var(--cb-bubble)}
.cb-msg a{color:inherit;text-underline-offset:3px}
.cb-cta{display:inline-block;margin-top:7px;font-weight:600;font-size:12px;
  letter-spacing:.1em;text-transform:uppercase;text-decoration:none;color:var(--cb-accent)}
.cb-typing{display:inline-flex;gap:4px;align-items:center;height:14px}
.cb-typing i{width:5px;height:5px;border-radius:50%;background:currentColor;opacity:.35;
  animation:cbDot 1.1s infinite}
.cb-typing i:nth-child(2){animation-delay:.16s}
.cb-typing i:nth-child(3){animation-delay:.32s}
@keyframes cbDot{0%,60%,100%{opacity:.22;transform:translateY(0)}30%{opacity:.85;transform:translateY(-3px)}}

.cb-chips{display:flex;gap:7px;flex-wrap:wrap;padding:0 18px 14px}
.cb-chip{background:transparent;border:1px solid var(--cb-line);color:var(--cb-muted);
  font-family:inherit;font-size:11.5px;padding:7px 12px;border-radius:var(--cb-bubble);
  cursor:pointer;transition:border-color .3s,color .3s}
.cb-chip:hover{border-color:var(--cb-accent);color:var(--cb-accent)}

.cb-form{display:flex;gap:0;border-top:1px solid var(--cb-line)}
.cb-in{flex:1;border:0;background:transparent;padding:15px 18px;font-family:inherit;
  font-size:14.5px;color:inherit;outline:0}
.cb-in::placeholder{color:var(--cb-muted)}
.cb-send{border:0;background:transparent;color:var(--cb-accent);font-size:19px;
  width:52px;cursor:pointer;transition:transform .3s}
.cb-send:hover{transform:translateX(2px)}
.cb-note{margin:0;padding:0 18px 14px;font-size:10.5px;line-height:1.55;color:var(--cb-muted)}

/* The drawer owns the screen when it is open; the assistant steps aside. */
body.menu-open .cb,body.locked .cb{opacity:0;pointer-events:none}
@media(max-width:520px){
  .cb-label{display:none}
  .cb-launch{padding:16px;border-radius:50%}
  .cb.open .cb-panel{bottom:calc(100% + 10px)}
}
@media(prefers-reduced-motion:reduce){
  .cb-msg,.cb-typing i{animation:none}
}

.cb{--cb-sans:'Inter',system-ui,sans-serif;--cb-display:'Jost',sans-serif;
  --cb-accent:#1B1A17;--cb-on-accent:#F7F5F0;--cb-paper:#F7F5F0;--cb-ink:#1B1A17;
  --cb-sand:#EDE8DE;--cb-line:#DAD3C4;--cb-muted:#7A756B;--cb-radius:0px;--cb-bubble:0px}
.cb-chip:hover{border-color:#B4714E;color:#B4714E}
.cb-cta{color:#B4714E}
.cb-send{color:#B4714E}

/* ---------- THE MARK ----------
   The V of towers from the brand board, traced from the artwork. It spans the
   two lines of the lockup and inherits the text color, so the same asset works
   over the hero, on paper and in the footer. */
.logo,.f-mark{display:inline-flex;align-items:center;gap:.5em}
.logo span b,.f-mark span b{display:block}
.lmk{height:2.15em;width:auto;flex:none}
