/* ============================================================
   VICTORIA HAUS - the house style, second edition

   The homepage rebuilt itself as a deck of plates. These are the rules
   that carry the same language onto the pages that cannot be a deck,
   because a floor plan, a map and a wall of photographs all need more
   room than one screen gives.

   What travels: the header that never puts a bar across the picture,
   type that arrives out of soft focus, one serif italic per headline,
   and a registration that asks one thing at a time.

   Loaded after site.css and anim.css, so everything here is an
   override and the base sheet stays the single source for layout.
   ============================================================ */

:root{
  --fog:#E9E7E1;
  --fog-2:#DCD9D1;
  --void:#0C0B0A;
  --mist:#8E8A81;
  --glass:rgba(20,19,17,.55);
  --ease:cubic-bezier(.2,.75,.2,1);
}
body{background:var(--fog);overflow-x:clip}
.page{background:var(--fog)}

/* one serif italic per headline, and nowhere else */
h1 em,h2 em,h3 em,.display em{
  font-family:'Newsreader',Georgia,serif;font-style:italic;font-weight:200}

/* ---------- the header ----------
   Build 004. Build 003 moved this block to assets/vh.css "because every page
   shares it" - but index.html does not load vh.css. It never has: the homepage
   is deliberately self-contained. So the whole header rebuild landed in a file
   this page cannot see, which is why the pill had no pill and the label stacked
   on top of the icon. It lives here again, and in vh.css for the other pages.

   The scrolled state: site.js adds .solid past 40px, and site.css turns that
   into a cream bar. On a page that is nothing but full-bleed pictures, a cream
   bar is a shelf sitting on top of the photograph. It stays a floating header
   the whole way down - a hair shorter once you are moving, over a light scrim
   that carries white type across any plate underneath. */
body > nav{transition:background .5s var(--ease),box-shadow .5s var(--ease),
  transform .55s var(--ease),opacity .45s ease}
body > nav.solid{background:none;backdrop-filter:none;-webkit-backdrop-filter:none;
  color:#F2EFE8;box-shadow:none}

/* the scrim: off on the hero, light once moving */
body > nav::before{opacity:0;height:210%;
  background:linear-gradient(to bottom,
    rgba(10,9,8,.40) 0%,rgba(10,9,8,.20) 40%,rgba(10,9,8,.06) 70%,rgba(10,9,8,0) 100%)}
body > nav.solid::before{opacity:1}

/* the mark: large on the hero, one step down once you are moving */
.logo{gap:0;font-size:clamp(26px,2.5vw,35px);letter-spacing:.18em;line-height:1.14;
  transition:font-size .55s var(--ease)}
.logo span{display:inline-block;white-space:nowrap}
.logo .lmk{display:none}
body > nav .nav-in{padding-block:clamp(20px,2.4vw,28px);transition:padding .5s var(--ease)}
body > nav.solid .logo{font-size:clamp(18px,1.5vw,22px);filter:none}
body > nav.solid .nav-in{padding-block:11px}

body > nav.away{transform:translateY(-104%);opacity:0;pointer-events:none}
body.menu-open > nav.away{transform:none;opacity:1;pointer-events:auto}

/* ---------- the menu button ----------
   Build 004. It said "MenuClose" - both labels rendered because the grid that
   was meant to stack them lived in a stylesheet this page does not load. The
   swap is gone entirely: the word is "Menu", it does not change, and the icon
   carries the open/closed state on its own.

   The icon is two rules rather than three. Three stacked bars next to a word
   is a lot of horizontal line for one control; two read as a mark, morph to a
   clean X, and sit at the cap height of the word beside them so the pair reads
   as one object instead of a label with a graphic bolted on. */
.burger{width:auto;height:auto;border-radius:999px;
  display:inline-flex;align-items:center;justify-content:center;gap:10px;
  padding:15px 19px 15px 21px;margin-right:0;
  border:1px solid rgba(255,255,255,.32);background:rgba(255,255,255,.10);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  font-family:'Inter',sans-serif;font-size:11px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;color:inherit;line-height:1;
  transition:background .4s var(--ease),border-color .4s var(--ease)}
.burger:hover,.burger:focus-visible{background:rgba(255,255,255,.2);
  border-color:rgba(255,255,255,.55)}
/* the label says what the button will do next. Both words share one grid cell
   so the pill does not resize as they cross-fade. */
.burger .bl{display:grid;line-height:1}
.burger .bl > span{grid-area:1/1;transition:opacity .3s ease}
.burger .w-b{opacity:0}
body.menu-open .burger .w-a{opacity:0}
body.menu-open .burger .w-b{opacity:1}
/* the icon box is sized off the label, so the two scale together */
.burger .bx{position:relative;display:block;width:1.45em;height:.72em;flex:none}
/* site.css positions three bars at top:23/29/35px inside a 56px circle. Those
   rules still match, and an absolutely positioned box with BOTH top and height
   set ignores bottom - so the second rule kept site.css's top:29px and landed
   below a pill only 12px tall. That is the line sitting outside the button.
   Every inherited offset is reset here explicitly rather than fought. */
.burger i{position:absolute;left:0;right:auto;top:auto;bottom:auto;
  height:1.5px;width:100%;background:currentColor;border-radius:2px;
  transition:transform .5s var(--ease),width .5s var(--ease)}
.burger i:nth-child(1){top:0;bottom:auto;width:100%}
.burger i:nth-child(2){top:auto;bottom:0;width:62%}
.burger:hover i:nth-child(2){width:100%}
/* site.css hides the SECOND bar when the menu opens - in its three-bar design
   that is the middle one, and dropping it is how the X is made. With two bars
   it left a single slash. opacity is forced back on, which is the whole fix. */
body.menu-open .burger i:nth-child(1){top:50%;bottom:auto;width:100%;opacity:1;
  transform:translateY(-50%) rotate(45deg)}
body.menu-open .burger i:nth-child(2){top:50%;bottom:auto;width:100%;opacity:1;
  transform:translateY(-50%) rotate(-45deg)}
@media(max-width:520px){
  .burger{padding:13px 15px 13px 17px;gap:8px;font-size:10px;letter-spacing:.14em}
}

.ax-prog{height:1px;opacity:.6}

/* ============================================================
   THE OPENING PLATE
   Every inner page opens on one picture held out of focus, which
   resolves once the page has settled. Same move as the deck, minus
   the stacking.
   ============================================================ */
.page-head,.hero.sub{position:relative;overflow:hidden;
  min-height:clamp(430px,74svh,760px);display:flex;align-items:flex-end;
  padding:calc(96px + clamp(56px,7vw,104px)) 0 clamp(52px,6vw,90px)}
.page-head .ph-media{inset:-8%;top:-8%;bottom:-8%}
.page-head .ph-media img,.hero.sub .media img{opacity:1;animation:none}
/* the hero video headers stay sharp: the clip is the point of them */
.hero.sub .media img{filter:brightness(.94)}
.page-head .ph-media::after{
  background:linear-gradient(100deg,rgba(14,13,11,.66) 0%,rgba(14,13,11,.26) 42%,rgba(14,13,11,0) 74%),
             linear-gradient(to top,rgba(14,13,11,.36),rgba(14,13,11,0) 32%)}

.page-head h1,.hero.sub h1{font-weight:200;letter-spacing:-.022em;
  color:rgba(247,245,240,.76);text-wrap:balance}
.page-head h1 em,.hero.sub h1 em{color:#FBF8F2}
/* Build 026: 60% cream is fine over a still. Over a moving aerial with a bright
   sky in it, the line disappears every time the video passes something pale.
   The copy carries its own contrast now, and the header's scrim is deeper at
   the foot, where the text actually sits. */
.page-head p,.hero.sub .sub-copy{color:rgba(250,248,244,.94);max-width:44ch;
  text-shadow:0 1px 22px rgba(10,9,8,.62),0 1px 3px rgba(10,9,8,.42)}
.hero.sub .shade,.page-head .shade{
  background:linear-gradient(to top,rgba(15,14,12,.82) 0%,rgba(15,14,12,.52) 26%,
    rgba(15,14,12,.10) 58%,rgba(15,14,12,.34) 100%)}
.hero.sub h1{text-shadow:0 2px 30px rgba(10,9,8,.44)}

/* the one line of hard numbers each page can put under its title */
.vh-facts{margin-top:26px;display:flex;flex-wrap:wrap;align-items:center;gap:10px 20px;
  font-family:'Inter',sans-serif;font-size:10.5px;letter-spacing:.24em;text-transform:uppercase;
  color:rgba(247,245,240,.6);font-variant-numeric:tabular-nums}
.vh-facts span{display:flex;align-items:center;gap:20px}
.vh-facts span+span::before{content:"";width:1px;height:11px;background:rgba(247,245,240,.3)}

/* ============================================================
   SECTIONS - more air, less ink
   ============================================================ */
section{padding-block:clamp(72px,10vw,150px)}
.kicker{color:var(--mist);font-weight:500;letter-spacing:.28em;font-size:10px}
.kicker::before{background:var(--clay);width:26px}
h2.title{font-weight:200;letter-spacing:-.02em;text-wrap:balance}
.lead{color:#4A473F}

/* a picture that arrives soft and resolves, anywhere on the page */
.frame img,.g img,.card img{transition:transform 1.3s var(--ease)}

/* the shared reveal, softened and given depth */
.reveal{opacity:0;transform:translate3d(0,26px,0);
  transition:opacity .95s var(--ease),transform 1.05s var(--ease)}
.reveal.in{opacity:1;transform:none}
.reveal.d1{transition-delay:.1s}
.reveal.d2{transition-delay:.2s}
.reveal.d3{transition-delay:.3s}
.reveal.d4{transition-delay:.4s}

/* ============================================================
   GALLERY - a fan first, the wall after
   ============================================================ */
.gal-tools{gap:4px}
.gfilter{border-bottom:0;border-radius:999px;padding:10px 18px;
  border:1px solid var(--line);color:var(--muted);font-size:11.5px;letter-spacing:.14em;
  transition:background .35s,color .35s,border-color .35s,transform .35s}
.gfilter:hover{border-color:var(--ink);transform:translateY(-1px)}
.gfilter.on{background:var(--ink);border-color:var(--ink);color:var(--paper)}

/* ============================================================
   THE FAN - one axis, real perspective. Any block marked
   data-coverflow gets it; the cards are its direct children.
   ============================================================ */
.vh-fan{position:relative;background:#14130F;color:#F2EFE8;overflow:hidden;
  padding:clamp(56px,7vw,96px) 0 clamp(40px,5vw,64px)}
.vh-fan .fan-bg{position:absolute;inset:0;z-index:0}

.vh-fan .fan-bg::after{content:"";position:absolute;inset:0;
  background:radial-gradient(72% 62% at 50% 46%,rgba(12,11,10,.08),rgba(12,11,10,.86))}
.fan-head{position:relative;z-index:2;text-align:center;padding-inline:var(--gutter)}
.fan-head h2{font-family:'Jost',sans-serif;font-weight:200;letter-spacing:-.02em;
  font-size:clamp(24px,3vw,42px);line-height:1.1;color:rgba(242,239,232,.82)}
.fan-head h2 em{color:#F7F4ED}
.fan-head .sub{margin-top:11px;font-family:'Inter',sans-serif;font-size:10px;letter-spacing:.28em;
  text-transform:uppercase;color:rgba(242,239,232,.45)}

.stage{position:relative;z-index:2;perspective:1500px;perspective-origin:50% 44%;
  display:grid;place-items:center;touch-action:pan-y;user-select:none;
  margin-top:clamp(30px,4vw,54px)}
.rail{position:relative;width:min(360px,72vw);height:min(520px,54svh);transform-style:preserve-3d}
@media(max-width:520px){.rail{width:min(290px,78vw);height:min(430px,48svh)}}
.slide{position:absolute;inset:0;display:block;text-decoration:none;color:inherit;
  border-radius:20px;overflow:hidden;cursor:pointer;background:#191713;
  border:1px solid rgba(255,255,255,.14);
  box-shadow:0 40px 90px rgba(0,0,0,.6),0 4px 14px rgba(0,0,0,.4);
  transition:transform .9s var(--ease),opacity .9s ease,box-shadow .9s ease;
  will-change:transform}
.rail:not(.live) .slide{transform:translateZ(-300px) scale(.92) !important;opacity:0 !important}
.slide img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform 1.4s var(--ease)}
.slide:not(.is-cur) img{transform:scale(1.05)}
.slide::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:rgba(10,9,8,.46);transition:opacity .9s ease}
.slide.is-cur::after{opacity:0}
.slide .plate{position:absolute;left:12px;right:12px;bottom:12px;z-index:2;
  padding:16px 18px 17px;border-radius:13px;
  background:linear-gradient(rgba(38,34,29,.66),rgba(18,17,15,.78));
  border:1px solid rgba(255,255,255,.16);color:#F5F2EB;
  transition:transform .9s var(--ease),opacity .9s ease}
.slide:not(.is-cur) .plate{transform:translateY(10px);opacity:.72}
.slide .nm{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.slide .nm b{font-family:'Jost',sans-serif;font-weight:300;font-size:24px}
.slide .nm i{font-style:normal;font-family:'Inter',sans-serif;font-size:9.5px;letter-spacing:.22em;
  text-transform:uppercase;color:rgba(245,242,235,.6)}
.slide .adr{margin-top:8px;font-family:'Inter',sans-serif;font-size:12.5px;line-height:1.55;
  color:rgba(245,242,235,.8)}
.slide .fig{margin-top:10px;display:flex;flex-wrap:wrap;gap:6px 14px;
  font-family:'Inter',sans-serif;font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;
  color:rgba(245,242,235,.52);font-variant-numeric:tabular-nums}
.slide .go{margin-top:12px;display:inline-flex;align-items:center;gap:9px;
  font-family:'Inter',sans-serif;font-size:10px;font-weight:600;letter-spacing:.2em;
  text-transform:uppercase;color:#F5F2EB;opacity:0;transition:opacity .6s .15s}
.slide.is-cur .go{opacity:1}
.slide.is-cur{box-shadow:0 60px 130px rgba(0,0,0,.72),0 0 0 1px rgba(255,255,255,.2)}
.slide:focus-visible{outline:2px solid var(--clay);outline-offset:4px}

.fan-foot{position:relative;z-index:3;display:flex;align-items:center;justify-content:center;
  gap:14px;padding:26px var(--gutter) 0}
.dh-nav{width:42px;height:42px;flex:none;display:grid;place-items:center;cursor:pointer;
  border-radius:50%;border:1px solid rgba(242,239,232,.28);background:rgba(20,19,17,.62);
  color:#F2EFE8;font-size:17px;
  line-height:1;transition:background .35s,border-color .35s,color .35s,transform .35s}
.dh-nav:hover{background:#F2EFE8;color:#14130F;border-color:#F2EFE8;transform:scale(1.06)}
.dots{display:flex;gap:9px}
.dots button{width:7px;height:7px;padding:0;border-radius:50%;cursor:pointer;border:0;
  background:rgba(242,239,232,.3);transition:background .35s,transform .35s}
.dots button[aria-current="true"]{background:#F2EFE8;transform:scale(1.4)}

/* ============================================================
   REGISTER - Build 014
   This was still the 003-era block: a live receipt, a form padded to a fixed
   190px, a legend that could never move because it was not floated, and an
   18px radius. Build 013 gave these pages the homepage's markup and engine
   but left this CSS underneath it, so two generations were fighting and the
   newer rules only won where they happened to come later in the file.
   Replaced wholesale with the homepage's. One register, one stylesheet.
   ============================================================ */

/* ---------- register ----------
   Build 003. Three changes. It is no longer the darkest block on the page -
   a warm charcoal with a single lit corner, so the one place that asks the
   visitor to do work does not look like the place the page gave up. The live
   receipt down the left is gone; the left column now carries the reason to
   register rather than an echo of what you just typed. And the summary moved
   to where a summary belongs: after submit, once, checkable. */
.vh-reg{position:relative;color:#EDEAE3;overflow:hidden;background:transparent;
  padding:clamp(64px,7.5vw,104px) 0 clamp(60px,7vw,96px)}
/* the ground, cut by the setback step, coursed like the brick */
.vh-reg .lap-g{background-color:#2A2621;
  background-image:
    repeating-linear-gradient(0deg,rgba(255,255,255,.016) 0 1px,transparent 1px 10px),
    repeating-linear-gradient(90deg,rgba(255,255,255,.010) 0 1px,transparent 1px 34px),
    linear-gradient(to bottom,rgba(25,22,20,0) 90%,#191614 100%),
    linear-gradient(168deg,#332E28 0%,#2A2621 54%,#242019 100%)}
.rg-glow{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(74% 60% at 82% 12%,rgba(206,132,88,.30),transparent 64%),
             radial-gradient(64% 54% at 4% 94%,rgba(126,146,120,.18),transparent 66%)}
.rg-in{position:relative;z-index:2;display:grid;grid-template-columns:1fr 1.02fr;
  gap:clamp(32px,4.4vw,72px);align-items:center}
@media(max-width:900px){.rg-in{grid-template-columns:1fr;gap:44px}}

.rg-eyebrow{font-family:'Inter',sans-serif;font-size:10.5px;letter-spacing:.32em;
  text-transform:uppercase;color:var(--clay)}
/* Build 014: this is the headline of the one section that asks for something,
   and it was set smaller than the plate headlines it sits between. Up to the
   same scale as those, and the eyebrow above it given room. */
.rg-say h2{margin-top:20px;font-family:'Jost',sans-serif;font-weight:200;letter-spacing:-.025em;
  font-size:clamp(36px,5vw,68px);line-height:1.02;color:#F7F4EE}
.rg-say h2 em{font-family:'Newsreader',Georgia,serif;font-style:italic;font-weight:200}
.rg-say > p{margin-top:16px;font-size:15px;line-height:1.75;
  color:rgba(237,234,227,.66);max-width:38ch}

/* what the list actually buys you - the argument the receipt was occupying */
/* Build 004: three short facts, not three sentences. A rule and four words
   each - the form beside it is where the reading effort belongs. */
/* Build 014: three short facts set in the body face directly under a large
   Jost headline read as two unrelated voices. They take the headline's family
   at a small size instead, so the column is one piece of typography - and the
   rules that mark them line up with the headline's left edge. */
.rg-why{list-style:none;margin:clamp(26px,3vw,38px) 0 0;padding:0;display:grid;gap:2px}
.rg-why li{position:relative;padding:11px 0 11px 34px;
  font-family:'Jost',sans-serif;font-weight:300;
  font-size:clamp(16px,1.5vw,19px);letter-spacing:.005em;line-height:1.3;
  color:rgba(240,236,228,.88);
  border-bottom:1px solid rgba(240,236,228,.10)}
.rg-why li:last-child{border-bottom:0}
.rg-why li::before{content:"";position:absolute;left:0;top:1.05em;
  width:20px;height:1px;background:var(--clay)}

/* Build 005: a bare underlined mailto in a field of empty space read as an
   afterthought. It is a quiet outlined control now, sized to the copy. */
.rg-contact{margin-top:clamp(26px,3vw,38px)}
/* Build 014: a real button, the same shape and weight as Continue, so the two
   ways of getting in touch look like two ways of getting in touch. */
.rg-contact a{position:relative;overflow:hidden;isolation:isolate;
  display:inline-flex;align-items:center;gap:12px;text-decoration:none;
  font-family:'Inter',sans-serif;font-size:11.5px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;
  color:#F7F4EE;padding:15px 28px;border-radius:999px;
  border:1px solid rgba(240,236,228,.42);
  transition:color .45s var(--ease),border-color .45s var(--ease)}
.rg-contact a::before{content:"";position:absolute;inset:0;z-index:-1;
  background:#F4F1EA;transform:scaleX(0);transform-origin:left center;
  transition:transform .55s var(--ease)}
.rg-contact a:hover::before,.rg-contact a:focus-visible::before{transform:scaleX(1)}
.rg-contact a:hover,.rg-contact a:focus-visible{color:#1B2724;border-color:#F4F1EA}

/* the form itself */
.rg-form{position:relative;border:1px solid rgba(237,234,227,.16);border-radius:4px;
  background:rgba(255,255,255,.055);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  box-shadow:0 40px 90px rgba(10,9,8,.4);
  padding:clamp(26px,3vw,40px);display:grid;gap:20px;align-content:start}
/* the plain-language position, for anyone who does not read a progress rail */
.rg-count{margin:-4px 0 -2px;font-family:'Inter',sans-serif;font-size:10px;letter-spacing:.22em;
  text-transform:uppercase;color:rgba(237,234,227,.45)}
.rg-rail{display:flex;gap:6px}
.rg-rail i{flex:1;height:2px;border-radius:2px;background:rgba(237,234,227,.16);
  transition:background .55s var(--ease)}
.rg-rail i.on{background:var(--clay)}

.rg-steps{display:grid;min-height:0}
.rg-done[hidden],.rg-acts[hidden],.rg-err[hidden]{display:none}
.rg-step{grid-area:1/1;border:0;padding:0;margin:0;min-width:0;display:grid;gap:clamp(30px,3.4vw,46px);align-content:start;
  opacity:0;visibility:hidden;transform:translateY(14px);
  transition:opacity .5s ease,transform .55s var(--ease),visibility .55s}
.rg-step.is-on{opacity:1;visibility:visible;transform:none}
/* Build 011: I raised this gap three times and it never moved, because a
   <legend> is not a grid item - the browser lays it out specially against the
   fieldset border, so `gap` on the fieldset never applies between the question
   and the fields under it. Floating it makes it an ordinary block in the flow,
   and then its own margin is what does the work. */
.rg-step legend{float:left;width:100%;margin-bottom:clamp(30px,3.6vw,48px);
  padding:0;font-family:'Jost',sans-serif;font-weight:200;letter-spacing:-.01em;
  font-size:clamp(21px,2.2vw,30px);line-height:1.2;color:#F4F1EA}
.rg-hint{font-size:12.5px;color:rgba(237,234,227,.5);margin:-18px 0 0}
.rg-two{clear:both;display:grid;grid-template-columns:1fr 1fr;gap:14px}
@media(max-width:520px){.rg-two{grid-template-columns:1fr}}
.rg-form input{clear:both;width:100%;background:none;border:0;border-bottom:1px solid rgba(237,234,227,.3);
  color:#F4F1EA;font-family:'Inter',sans-serif;font-size:16px;padding:2px 2px 13px;
  transition:border-color .4s ease}
.rg-form input::placeholder{color:rgba(237,234,227,.34)}
.rg-form input:focus{outline:0;border-bottom-color:var(--clay)}

.chips{clear:both;display:flex;flex-wrap:wrap;gap:9px}
.chips button{font-family:'Inter',sans-serif;font-size:12px;letter-spacing:.08em;
  padding:11px 18px;border-radius:999px;cursor:pointer;
  border:1px solid rgba(237,234,227,.26);background:none;color:rgba(237,234,227,.8);
  transition:background .35s,color .35s,border-color .35s,transform .35s}
.chips button:hover{border-color:rgba(237,234,227,.7);transform:translateY(-1px)}
.chips button[aria-pressed="true"]{background:#F4F1EA;border-color:#F4F1EA;color:var(--ink)}

.rg-err{min-height:17px;margin:-8px 0 0;font-size:12.5px;color:#E0916F;
  opacity:0;transition:opacity .3s}
.rg-err.on{opacity:1}
.rg-acts{display:flex;align-items:center;gap:14px;margin-top:4px}
.rg-back{font-family:'Inter',sans-serif;font-size:11px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;background:none;border:0;cursor:pointer;padding:12px 2px;
  color:rgba(237,234,227,.5);opacity:0;pointer-events:none;transition:opacity .4s,color .3s}
.rg-back.on{opacity:1;pointer-events:auto}
.rg-back:hover{color:#F4F1EA}
.rg-go{margin-left:auto;display:inline-flex;align-items:center;gap:12px;cursor:pointer;
  font-family:'Inter',sans-serif;font-size:11.5px;font-weight:600;letter-spacing:.18em;
  text-transform:uppercase;padding:15px 30px;border-radius:999px;border:1px solid #F4F1EA;
  background:#F4F1EA;color:var(--ink);transition:background .35s,color .35s,border-color .35s}
.rg-go:hover{background:var(--moss);border-color:var(--moss);color:#fff}
.rg-go .arr{transition:transform .35s}
.rg-go:hover .arr{transform:translateX(5px)}
.rg-consent{margin:0;font-size:11.5px;line-height:1.65;color:rgba(237,234,227,.38)}

.rg-done{grid-area:1/1;display:grid;gap:18px;align-content:center;justify-items:start;
  min-height:280px;animation:rgIn .8s var(--ease) both}
.rg-done h3{font-family:'Jost',sans-serif;font-weight:200;font-size:clamp(26px,3vw,40px);
  line-height:1.12;color:#F4F1EA}
.rg-done p{font-size:15px;line-height:1.75;color:rgba(237,234,227,.62);max-width:38ch}
.rg-done .tick{width:46px;height:46px;border-radius:50%;display:grid;place-items:center;
  border:1px solid var(--clay);color:var(--clay);font-size:19px}
/* the summary: shown once, after submit, so it can be checked rather than
   watched being filled in */
.rg-sum{margin:4px 0 0;display:grid;gap:1px;width:100%;
  background:rgba(237,234,227,.12);border-block:1px solid rgba(237,234,227,.12)}
.rg-sum > div{display:grid;grid-template-columns:11ch 1fr;gap:16px;align-items:baseline;
  background:#232019;padding:12px 2px}
.rg-sum dt{font-family:'Inter',sans-serif;font-size:9.5px;letter-spacing:.24em;
  text-transform:uppercase;color:rgba(237,234,227,.42)}
.rg-sum dd{margin:0;font-size:14.5px;color:#F4F1EA}
.rg-edit{background:none;border:0;padding:6px 2px;cursor:pointer;
  font-family:'Inter',sans-serif;font-size:11.5px;letter-spacing:.04em;
  color:rgba(237,234,227,.5);text-decoration:underline;text-underline-offset:4px;
  transition:color .3s}
.rg-edit:hover{color:#F4F1EA}
.rg-done:focus-visible{outline:2px solid var(--clay);outline-offset:8px}

@media(prefers-reduced-motion:reduce){
  .rg-step,.rg-done{transition:none !important;animation:none !important}
}

/* Build 026: cookie-bar styling removed with the bar. */

@media(prefers-reduced-motion:reduce){
  .page-head .ph-media img,.hero.sub .media img{filter:none;transform:none}
  .reveal,.slide,.slide img,.rg-step,body > nav{transition:none !important}
  .rail:not(.live) .slide{opacity:1 !important}
  .g img{filter:none !important}
  .deck .rise{opacity:1 !important;transform:none !important}
  .nb-plate > img{transform:none !important}
}

/* ============================================================
   SECOND PASS - the ground goes dark, the pictures come forward

   The cream returned as soon as the pages left the deck, and it was
   the cream that made every seam show. So: no light panels anywhere.
   One out-of-focus field behind the whole site, glass on top of it,
   and the photographs are the only thing left in sharp focus - with
   corners, because a rounded picture reads as an object on a surface
   rather than a hole cut in it.
   ============================================================ */

/* ---------- the field behind everything ---------- */
body{background:#100F0D;color:rgba(240,236,228,.72)}
.vh-ground{position:fixed;inset:0;z-index:-1;pointer-events:none;background:#100F0D}

.vh-ground::after{content:"";position:absolute;inset:0;
  background:radial-gradient(80% 60% at 50% 20%,rgba(16,15,13,.2),rgba(16,15,13,.9))}
.page,section{background:transparent}
/* the tail is the one opaque thing: it has to cover the plate it rides over */
.tail{position:relative;z-index:20;background:#100F0D;
  box-shadow:0 -40px 90px rgba(10,9,8,.7)}
/* Build 024: .tail carried a hard-coded near-black and no light twin, so on a
   light page every gap between its sections read as a black bar. */
body.t-light .tail{background:var(--ground);box-shadow:0 -40px 90px rgba(120,110,95,.14)}
.page-head + section{padding-top:clamp(56px,7vw,104px)}

/* type on the dark */
h1,h2,h3,h4,.display{color:#F4F1EA}
h2.title{color:rgba(244,241,234,.8)}
h2.title em{color:#F7F4ED}
p,.lead,li,dd{color:rgba(240,236,228,.66)}
.lead{color:rgba(240,236,228,.66)}
.kicker{color:var(--clay)}
.kicker::before{background:var(--clay)}
a{color:inherit}
.btn{border-color:rgba(240,236,228,.34);color:#F2EFE8}
.btn:hover{background:#F2EFE8;color:#14130F;border-color:#F2EFE8}
.btn-solid{background:#F2EFE8;color:#14130F;border-color:#F2EFE8}
.btn-solid:hover{background:var(--moss);border-color:var(--moss);color:#fff}

/* ---------- glass instead of white, everywhere ---------- */
.frame,.g,.d-pic,.mapframe,.spec div,.board,.fp-panel,.cmp-col,.saved-list,.card,.tile{
  border-radius:18px;overflow:hidden}
.frame,.g{background:rgba(255,255,255,.05)}
/* Build 028: unscoped, and carrying !important, so on a light page these
   panels were 4.5% white on cream - no plate at all, and a hairline border in
   a colour meant for the dark. Every light rule written since lost to it.
   Scoped to the dark, with a light twin below. */
body.t-dark .spec div,body.t-dark .board,body.t-dark .fp-panel,
body.t-dark .cmp-col,body.t-dark .saved-list{
  background:rgba(255,255,255,.045) !important;
  border:1px solid rgba(240,236,228,.13) !important}
body.t-light .spec div,body.t-light .board,body.t-light .fp-panel,
body.t-light .cmp-col,body.t-light .saved-list{
  background:#FBF9F5 !important;
  border:1px solid rgba(43,38,32,.16) !important}
body.t-dark .board-head,body.t-dark .fp-panel .panel-head,body.t-dark .ov-head{
  background:transparent !important;border-color:rgba(240,236,228,.13) !important}
body.t-light .board-head,body.t-light .fp-panel .panel-head,body.t-light .ov-head{
  background:transparent !important;border-color:rgba(43,38,32,.16) !important}

/* ---------- the pictures are the sharp thing ---------- */
.frame img,.g img,.d-pic img,.card img,.tile img{border-radius:inherit}
.g img,.frame img{filter:none !important}
.reveal .frame img,.reveal.frame img{filter:none}
@media(hover:hover){
  .g img{filter:none;transform:scale(1.01)}
  .g:hover img,.g:focus-visible img{filter:none;transform:scale(1.045)}
}
.page-head,.hero.sub{border-radius:0 0 clamp(18px,2.4vw,32px) clamp(18px,2.4vw,32px)}


/* ---------- the menu ----------
   A panel of smoked glass floating clear of the edges, and the page
   behind it goes soft rather than dark.
   ============================================================ */
/* Build 039: the close button is back. It was hidden on the grounds that the
   burger turns into an X and two circles in one corner was the bug in the
   picture. That reasoning was sound and the result was not, because the burger
   lives in the header at z-index 95 and the panel that covers it sits at 97:
   the X was painted underneath the menu on every width, so the panel had no
   visible way out at all. Only one of the two is ever on top, so there is
   still only one circle in that corner, and it is this one.

   Styled off the open burger rather than off .d-close in site.css, which is a
   paper-white circle meant for a light panel and reads as a hole punched in
   this dark one. Sitting inside the panel, it moves with the panel's own
   padding rather than the page gutter, which runs to 72px on a wide screen and
   would have parked it oddly far from the corner. */
.d-close{z-index:98;right:clamp(18px,3vw,26px);
  top:calc(env(safe-area-inset-top) + clamp(18px,3vw,26px));
  width:48px;height:48px;font-size:17px;
  background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.24);
  color:#F2EFE8}
.d-close:hover,.d-close:focus-visible{background:#F2EFE8;border-color:#F2EFE8;color:#14130F}
.veil{background:rgba(10,9,8,.72)}
body.menu-open > nav{color:#F2EFE8}
body.menu-open .burger{background:rgba(255,255,255,.16);
  border:1px solid rgba(255,255,255,.24)}

/* Build 007: full height, flush right - it read as a card, not a panel. */
.drawer{top:0;right:0;bottom:0;width:min(430px,78vw);
  border-radius:0;overflow:hidden;color:#F2EFE8;
  padding-top:env(safe-area-inset-top);
  background:linear-gradient(rgba(34,30,26,.97),rgba(20,18,16,.98));
  border:1px solid rgba(255,255,255,.14);
  box-shadow:0 40px 90px rgba(0,0,0,.55);
  transform:translateX(calc(100% + 30px)) scale(.97);
  transition:transform .6s var(--ease),opacity .5s ease;opacity:0}
body.menu-open .drawer{transform:none;opacity:1}
.d-pic{height:32%;min-height:170px;margin:0;border-radius:0;
  background:rgba(255,255,255,.05)}
@media(max-width:520px){.d-pic{height:24%;min-height:130px}}
.d-pic span{font-size:17px}
/* Build 036: the drawer picture follows the pointer down the menu. Two frames
   stacked in the same box so the change is a cross-fade rather than a blink.
   Both keep the existing settle-in scale, so opening the menu still behaves as
   it did. */
.d-pic .d-fr{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .55s ease,transform 1.6s var(--ease)}
.d-pic .d-fr.on{opacity:1}
.d-cap{transition:opacity .3s ease}
.d-cap.d-swap{opacity:0}
@media(prefers-reduced-motion:reduce){
  .d-pic .d-fr,.d-cap{transition:none}}


.d-body{padding:26px 22px 24px;gap:2px}
.drawer a{border-bottom:0;border-radius:14px;padding:13px 14px;
  font-size:clamp(20px,2.4vw,25px);color:rgba(242,239,232,.86);
  transition:background .3s,color .3s,opacity .45s ease,transform .45s var(--ease)}
.drawer a:hover{background:rgba(255,255,255,.1);color:#FBF9F4}
.d-num{color:rgba(242,239,232,.4);font-size:9.5px}
.drawer a.d-go{margin:14px 14px 0;border-radius:999px;background:rgba(255,255,255,.92);
  color:#14130F;padding:14px 26px;font-weight:600}
.drawer a.d-go:hover{background:var(--clay);color:#fff}
.drawer .d-meta{margin:22px 14px 0;color:rgba(242,239,232,.5);font-size:12.5px}
.drawer a.d-mail{color:rgba(242,239,232,.62);padding:0;border-radius:0}
.drawer a.d-mail:hover{background:none;color:#FBF9F4}

/* ---------- chips and controls on the dark ---------- */
.gfilter{border-color:rgba(240,236,228,.22);color:rgba(240,236,228,.62)}
.gfilter:hover{border-color:rgba(240,236,228,.6);color:#F2EFE8}
.gfilter.on{background:#F2EFE8;border-color:#F2EFE8;color:#14130F}
/* Build 024: these were unscoped and carried !important, so they beat every
   later .pg .chip rule no matter its specificity - on a light page the
   filters became near-white on cream. Scoped to the dark, with a light
   twin below in the theme block. */
body.t-dark .chip{background:rgba(255,255,255,.05) !important;border-color:rgba(240,236,228,.2) !important;
  color:rgba(240,236,228,.76) !important;border-radius:999px}
body.t-dark .chip.on{background:#F2EFE8 !important;border-color:#F2EFE8 !important;color:#14130F !important}
/* Build 034: the floor-plan panel's controls, written cream for the dark and
   never scoped. The panel is a pale plate on the light page, so the level
   tabs, the status pill, the price and the save button were cream on cream:
   present, clickable, invisible. Scoped, with light twins below. */
body.t-dark .icon-btn{border-color:rgba(240,236,228,.28);color:#F2EFE8;border-radius:999px}
body.t-dark .icon-btn:hover{background:#F2EFE8;color:#14130F}
body.t-dark .levels button{color:rgba(240,236,228,.6)}
body.t-dark .levels button.on{color:#F7F4ED}

body.t-light .icon-btn{border-color:rgba(43,38,32,.3);color:#2A2620;border-radius:999px}
body.t-light .icon-btn:hover{background:#1B1A17;border-color:#1B1A17;color:#F7F5F0}
body.t-light .levels button{color:#6B655B}
body.t-light .levels button:hover{color:#1B1A17}
body.t-light .levels button.on{color:#14130F}
body.t-light .levels button small{color:#8B8478}
body.t-light .levels button.on small{color:#5A6650}

/* ---------- floor plans: the drawing keeps its paper ----------
   A plan is a printed sheet; it stays white, but it is now a sheet
   lying on the glass rather than the panel itself. */
.planbox,.cmp-plan{background:#F7F5F0 !important;border-radius:14px;margin:12px}
.planbox{padding:clamp(12px,1.6vw,20px)}
.site-holder{border-radius:14px;overflow:hidden;margin:12px}
body.t-dark .prow > div,body.t-dark .cmp-spec div{
  border-color:rgba(240,236,228,.12) !important;color:rgba(240,236,228,.7)}
body.t-light .prow > div,body.t-light .cmp-spec div{
  border-color:rgba(43,38,32,.14) !important;color:#3F3A33}
.cmp-spec div.diff{background:rgba(180,113,78,.16) !important}
body.t-dark .price{color:#F4F1EA}
body.t-dark .status{border-color:rgba(240,236,228,.35);color:rgba(240,236,228,.8)}
body.t-light .price{color:#14130F}
body.t-light .status{border-color:rgba(90,102,80,.5);color:#4A5643;
  background:rgba(90,102,80,.09)}
body.t-light .status.sold{border-color:rgba(43,38,32,.28);color:#7A7367;
  background:rgba(43,38,32,.05)}
body.t-light .price.sold{color:#8B8478}
/* Build 038: the same ink at 97% rather than flat. The overlay covers the
   screen, so three percent of show-through is not visible, but the alpha is
   what stops it disagreeing with every other iPhone toolbar candidate while
   the plan viewer is open. .tray and .lb on this page were already written
   this way. */
.ov{background:rgba(18,17,15,.97) !important}
.ov-x{border-color:rgba(240,236,228,.3);color:#F2EFE8;border-radius:999px}
.ov-x:hover{background:#F2EFE8;color:#14130F}
/* Build 028: the mail-the-plans form only appears on floorplans.html, which is
   a light page - so this dark styling was the whole of it: a 5% white field on
   cream, invisible, with cream text inside. Scoped, with a light twin. Caught
   by sweeping for unscoped !important colour rules rather than by finding it
   on screen. */
body.t-dark .mailform input{background:rgba(255,255,255,.05) !important;
  border-color:rgba(240,236,228,.2) !important;color:#F4F1EA;border-radius:12px}
body.t-dark .mailform button{background:#F2EFE8 !important;color:#14130F !important;border-radius:999px}
body.t-light .mailform input{background:#FFFDF9 !important;
  border-color:rgba(43,38,32,.24) !important;color:#1B1A17;border-radius:0}
body.t-light .mailform input::placeholder{color:#8B8478}
body.t-light .mailform button{background:#1B1A17 !important;color:#F7F5F0 !important;border-radius:0}
body.t-light .mailform button:hover{background:#2F2A24 !important}
.demo-note{background:rgba(255,255,255,.05) !important;border-radius:18px;
  border:1px solid rgba(240,236,228,.13)}

/* the shared caption pill, restyled for glass */
.cap{background:rgba(16,15,13,.62);border-radius:999px;padding:7px 14px}

/* ============================================================
   THE DECK, portable - same rules the homepage uses, moved here so
   any page marked data-deck can be one.
   ============================================================ */
.deck{position:relative}
.deck .bleed{position:fixed;inset:0;z-index:0;pointer-events:none;background:#0C0B0A}

/* Build 002 - plates no longer stack. They were sticky, so each one parked
   at the top and the next climbed over it. Ordinary blocks in ordinary flow
   now: --in still fades the content in on arrival, --out drifts the picture
   inside its frame on the way out, and nothing covers anything. */
.deck .panel{--in:1;--out:0;
  position:relative;height:100svh;overflow:hidden;isolation:isolate;z-index:1;
  background:#211E1A}
.deck .panel > .lift{display:none}
.deck .rise{--s:0;--k:clamp(0,calc((var(--in) - var(--s)) / (.78 - var(--s))),1);
  opacity:var(--k);transform:translate3d(0,calc((1 - var(--k)) * 26px),0)}

/* ---------- neighbourhood, as a deck ---------- */
.deck .hero.sub.panel{height:100svh;min-height:0;max-height:none}
.nb-times{display:grid;place-items:center;background:#211E1A}
.nbt-in{position:relative;z-index:2;width:100%}
.nb-times h2{font-family:'Jost',sans-serif;font-weight:200;letter-spacing:-.02em;
  font-size:clamp(28px,4.2vw,58px);line-height:1.08;margin-top:18px;max-width:18ch;
  color:rgba(244,241,234,.82);text-wrap:balance}
.nb-times h2 em{color:#F7F4ED}
.deck .times{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--gap);
  margin-top:clamp(40px,6vw,84px)}
@media(max-width:860px){.deck .times{grid-template-columns:repeat(2,1fr)}}
.deck .time{border-top:1px solid rgba(240,236,228,.16);padding-top:22px}
.deck .time b{color:#F4F1EA;font-variant-numeric:tabular-nums}
.deck .time b i{color:rgba(240,236,228,.45)}
.deck .time small{color:rgba(240,236,228,.6)}

.nb-plate{background:#211E1A}
.nb-plate > img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* Build 002 - cut oversize so the drift against the frame never opens an edge */
.nb-plate > img{top:-6%;height:112%;transform:translate3d(0,calc(var(--out) * -4.5%),0)}
.nb-plate .grad{position:absolute;inset:0;
  background:linear-gradient(100deg,rgba(14,13,11,.68) 0%,rgba(14,13,11,.28) 42%,rgba(14,13,11,0) 72%),
             linear-gradient(to top,rgba(14,13,11,.5),rgba(14,13,11,0) 36%)}
.nb-plate .words{position:absolute;z-index:2;left:var(--gutter);right:var(--gutter);
  top:50%;transform:translateY(-50%);display:grid;gap:16px;justify-items:start;
  align-content:center;max-width:min(46ch,calc(100% - 2 * var(--gutter)))}
.nb-plate .words .n{font-family:'Inter',sans-serif;font-size:10px;letter-spacing:.28em;
  text-transform:uppercase;color:var(--clay)}
.nb-plate .words h2{font-family:'Jost',sans-serif;font-weight:200;letter-spacing:-.02em;
  font-size:clamp(32px,4.6vw,64px);line-height:1.06;color:rgba(247,245,240,.82);
  text-wrap:balance}
.nb-plate .words h2 em{color:#FBF8F2}
.nb-plate .words p{font-size:clamp(14.5px,1.15vw,17px);line-height:1.75;
  color:rgba(240,236,228,.66);max-width:40ch}

/* the map, framed like everything else */
.mapframe{border-radius:18px;overflow:hidden;border:1px solid rgba(240,236,228,.13);
  background:rgba(255,255,255,.04)}
.map-wait{color:rgba(240,236,228,.6)}
/* Build 025: same fault as the chips - written for the dark, never scoped to
   it, so on a light page the column heads and the times were near-white on
   cream. The page's own rules had set them correctly; these overwrote them. */
body.t-dark .list h4{color:#F4F1EA}
body.t-dark .list li{border-color:rgba(240,236,228,.12) !important;color:rgba(240,236,228,.7)}
body.t-dark .list li span{color:rgba(240,236,228,.45)}
.note{color:rgba(240,236,228,.45)}

/* ---------- gallery: the wall goes on a board ----------
   The filters were floating on the bare ground with a hairline under
   them and the pictures loose below, which read as an unfinished page
   next to the floor plans, where everything sits on one card. Same
   card here: a head that names the set you are looking at, and the
   wall inside it.  */
.gal-tools{border-bottom:0 !important;gap:8px;margin-bottom:clamp(18px,2vw,26px)}
.gfilter .n{opacity:.55;margin-left:5px;font-variant-numeric:tabular-nums}
.gfilter.on .n{opacity:.65}

.gal-board{padding:0 clamp(10px,1.2vw,16px) clamp(10px,1.2vw,16px);
  border-radius:20px}
.gal-board .board-head{display:flex;justify-content:space-between;align-items:center;
  gap:16px;flex-wrap:wrap;padding:18px clamp(10px,1.2vw,14px);
  border-bottom:1px solid rgba(240,236,228,.12);margin-bottom:clamp(12px,1.4vw,18px)}
.gal-board .board-head h3{font-family:'Inter',sans-serif;font-size:11px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:#F2EFE8}
.gal-board .board-head .hint{font-size:12.5px;color:rgba(240,236,228,.45)}
.gal-board .gal{padding-inline:clamp(4px,.6vw,8px)}
.gal-board .g{border-radius:14px}


/* ---------- coming into focus, cheaply ----------
   A blur that animates is repainted every frame at the full size of the
   picture, which is what the scroll was stuttering on. A blur that never
   changes is rasterised once. So each plate carries two copies of its
   picture - one permanently soft underneath, one sharp on top - and what
   moves between them is opacity, which the compositor owns outright. */

.sf img.sf-sharp{opacity:0;transform:scale(1.02) translateZ(0);z-index:1;
  transition:opacity 1.5s var(--ease)}
.sf.act img.sf-sharp,.sf.lit img.sf-sharp{opacity:1}

.page-head.sf img.sf-sharp{filter:brightness(.82)}


/* ---------- what sits behind everything ----------
   This started as a blurred copy of each page's own picture. Two ways of
   making that cheap both failed: a full-size filter:blur() repaints on
   every frame of a scroll, and blurring a small copy and scaling it up
   does not work either - Chrome rasterises the layer at the scale it
   ends up at, so the blur comes back sharp and the surface becomes
   enormous. It is paint now, and nothing in the scroll path filters
   anything. */
/* Build 039: the background-color line is why the iPhone toolbar went glass on
   the homepage and stayed solid on all five pages that have this layer. The
   gradient shorthand sets background-color to transparent, and a fixed
   full-viewport element with a transparent colour is the one shape that makes
   Safari give up and read the opaque body instead. This is the same trap that
   cost the reference project five builds through its page grain layer. The
   colour is never seen, because the gradient paints over it. It is here purely
   to carry an alpha, and it has to stay after the shorthand or the shorthand
   wipes it out again. */
.vh-ground{position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:radial-gradient(120% 80% at 50% 0%,#1C1A16 0%,#100F0D 62%,#0B0A09 100%);
  background-color:var(--tint-glass,rgba(16,15,13,.96))}
/* Build 042. This layer is built by vh.js on the four pages without a .deck,
   and being fixed and full screen it reached the bottom edge, where only #chin
   is allowed to be. It is the same element and the same mistake as the grain
   layer in CHIN-iOS-SAFARI.md, and the remedy there is the first one that
   document lists: stop it being fixed. Absolute against a relative body still
   covers the whole document, so it looks the same going down the page; the
   gradient stretches over the document rather than the screen, which on a
   radial this diffuse is not something you can see. iPhone only, so the
   desktop keeps the fixed backdrop it was designed with. */
@supports (-webkit-text-size-adjust:none) and (font:-apple-system-body) and (-webkit-touch-callout:none){
  @media(max-width:760px){.vh-ground{position:absolute}}
}
.vh-ground img{display:none}

.vh-fan .fan-bg{background:radial-gradient(78% 66% at 50% 42%,#241F19 0%,#14130F 62%,#0C0B0A 100%)}
.vh-fan .fan-bg img{display:none}

.deck{background:radial-gradient(120% 80% at 50% 0%,#1A1815 0%,#0C0B0A 70%)}
.deck .bleed{display:none}

/* Each plate keeps its own compositor layer. Without it Chrome repaints
   the whole plate on every frame of the drift. */
.deck .panel{will-change:transform}

/* No soft twin either: the picture is shown as it is, and the scrim over
   it is what makes the words read. */
.sf img.sf-soft{display:none}
.sf img.sf-sharp{opacity:1 !important;transform:none !important}

/* ============================================================
   BUILD 004 - the reveal system and the rebuilt footer, shared.
   index.html keeps its own copy of both: it does not load this file.
   ============================================================ */

/* ---------- the reveal ----------
   Build 004. Two complaints answered here. Things were animating before you
   reached them, because half the page was still on the deck's --in, which
   starts the moment a plate's edge enters the viewport - by the time you had
   scrolled to a line it had already finished moving. Everything is now on one
   observer with a real threshold, so a thing moves when you are looking at it.

   And it is no longer one move. Three, picked per element:

     data-rv          rise and fade        - copy, captions, cards, rows
     data-rv="mask"   wipes up out of a    - headlines. The line is clipped at
                      clipped edge           its own baseline and released, so
                                             it reads as type being set rather
                                             than a block sliding.
     data-rv="zoom"   the picture settles  - images inside a card, easing off a
                      out of an oversize     small overscale so the card feels
                                             like it is coming to rest

   Hidden state is applied by the script (body.rv-on), so no JS means a plain
   readable page rather than a blank one.                                   */
body.rv-on [data-rv]{opacity:0;transform:translate3d(0,26px,0)}
body.rv-on [data-rv="mask"]{opacity:1;transform:none;
  clip-path:inset(0 0 102% 0)}
body.rv-on [data-rv="zoom"]{opacity:1;transform:none}
body.rv-on [data-rv="zoom"] img{transform:scale(1.10);opacity:.82}

body.rv-on [data-rv].rv-in{opacity:1;transform:none;
  transition:opacity .85s var(--ease) var(--d,0ms),transform .95s var(--ease) var(--d,0ms)}
body.rv-on [data-rv="mask"].rv-in{clip-path:inset(0 0 -6% 0);
  transition:clip-path 1.15s var(--ease) var(--d,0ms)}
body.rv-on [data-rv="zoom"].rv-in img{transform:none;opacity:1;
  transition:transform 1.5s var(--ease) var(--d,0ms),opacity 1s ease var(--d,0ms)}

/* the counters get a touch more than the row they sit in */
body.rv-on .wk.rv-in .wk-n{animation:wkPop .9s var(--ease) var(--d,0ms) both}
@keyframes wkPop{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

@media(prefers-reduced-motion:reduce){
  body.rv-on [data-rv],
  body.rv-on [data-rv="mask"],
  body.rv-on [data-rv="zoom"],
  body.rv-on [data-rv="zoom"] img{opacity:1 !important;transform:none !important;
    clip-path:none !important;transition:none !important;animation:none !important}
}

/* ---------- the footer ----------
   Build 004. It had no material: a flat charcoal panel of link columns landing
   straight after the form. Now it is built in layers - picture, wash, grain -
   with the wordmark oversized and bleeding off the left edge, so the page ends
   on something made rather than something left over.

   The grain is an inline SVG turbulence, not an image request: it stops the
   big gradient banding on a wide screen, and it is what stops the surface
   reading as flat CSS. */
footer{position:relative;isolation:isolate;background:#1A1714;color:#ADA79D;
  overflow:hidden}
/* the straight hairline is replaced by the traced edge below */

.fx-bg{position:absolute;inset:0;z-index:0;overflow:hidden}
.fx-bg img{position:absolute;inset:0;width:100%;height:118%;top:-9%;
  object-fit:cover;object-position:50% 34%;
  transform:translate3d(0,calc(var(--fp,0) * 5%),0)}
/* the wash: dark enough to read type on, warm enough to keep the dusk in the
   picture rather than turning it into grey */
.fx-wash{position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(18,16,13,.72) 0%,rgba(24,20,17,.80) 44%,rgba(16,14,12,.90) 100%),
             radial-gradient(78% 60% at 14% 8%,rgba(196,124,84,.20),transparent 60%),
             radial-gradient(60% 50% at 92% 96%,rgba(120,138,116,.14),transparent 62%)}
.fx-grain{position:absolute;inset:-50%;opacity:.42;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E")}

.fx-body{position:relative;z-index:2;
  padding:clamp(64px,8vw,110px) 0 clamp(34px,4vw,52px)}

/* the lead */
.f-lead{display:grid;grid-template-columns:1fr auto;gap:clamp(26px,4vw,64px);
  align-items:end;padding-bottom:clamp(40px,5vw,68px)}
@media(max-width:860px){.f-lead{grid-template-columns:1fr;align-items:start;gap:28px}}
.f-kick{font-family:'Inter',sans-serif;font-size:10px;letter-spacing:.3em;
  text-transform:uppercase;color:var(--clay);margin-bottom:16px}
.f-lead-say h2{font-family:'Jost',sans-serif;font-weight:200;letter-spacing:-.025em;
  font-size:clamp(34px,5.4vw,74px);line-height:1.02;color:#F7F4EE}
.f-lead-say h2 em{font-family:'Newsreader',Georgia,serif;font-style:italic;
  font-weight:200;color:#FBF8F2}
.f-lead-say p{margin-top:20px;font-size:14px;line-height:1.8;color:rgba(240,236,228,.58)}
.f-lead-act{display:grid;gap:18px;justify-items:start}
@media(min-width:861px){.f-lead-act{justify-items:end}}
.f-mail{font-family:'Inter',sans-serif;font-size:13px;letter-spacing:.02em;
  color:rgba(240,236,228,.7) !important;text-decoration:none;
  border-bottom:1px solid rgba(240,236,228,.28);transition:border-color .35s}
.f-mail:hover{border-color:var(--clay)}

/* Build 005: an oversized wordmark used to sit here, bleeding off the left
   edge between two rules. Read as the name printed twice with lines through
   it. Gone - the footer carries one proper lockup, in the brand column. */

/* the utility rows */
.f-top{padding-top:clamp(40px,5vw,66px)}
.f-brand p{color:rgba(240,236,228,.5)}
.f-mark{color:#F4F1EA}
.f-cols h4{color:var(--clay);opacity:.9}
.f-cols a{color:rgba(240,236,228,.8)}
.f-cols span{color:rgba(240,236,228,.5)}
.f-cols a:not(.f-cta){position:relative;width:fit-content}
.f-cols a:not(.f-cta)::after{content:"";position:absolute;left:0;bottom:3px;height:1px;
  width:0;background:currentColor;transition:width .45s var(--ease)}
.f-cols a:not(.f-cta):hover::after{width:100%}

/* the credit line Robert asked for, as a single link */
.credit-dl{display:flex;align-items:center;gap:14px;text-decoration:none}
/* Build 033: was .credit-dl only, so the TwinLines credit had no hover even
   once it became a link. Any credit that leads somewhere now responds. */
a.credit small{transition:color .3s}
a.credit:hover small{color:var(--clay)}
a.credit .mk{transition:opacity .35s ease}
a.credit:hover .mk{opacity:1}
.f-credits{border-top:1px solid rgba(240,236,228,.1);
  padding-top:clamp(26px,3vw,40px);margin-top:clamp(30px,3.6vw,50px)}
.f-legal{color:rgba(240,236,228,.32);border-top-color:rgba(240,236,228,.09)}

@media(prefers-reduced-motion:reduce){
  .fx-bg img{transform:none !important}
}

/* ============================================================
   THE SEAM - where one section meets the next
   ============================================================
   Build 010, and the fifth attempt. Sawtooth, wide radius, square step,
   then a straight edge with nothing. Every one of those was the same
   category of answer - cut a silhouette into the boundary - and the last
   was just giving up. Researched properly this time, against how studios
   who publish full-bleed photography actually handle it.

   Nobody good cuts a shape. What they do instead:

     Herzog & de Meuron  a gradient backdrop at the FOOT of every plate,
                         so the picture ends by fading rather than stopping
     111 West 57th       full-bleed plates alternating with inset ones, so
                         a band of ground appears between them; one hairline
                         token at 20% opacity is the entire divider language
     Snøhetta            a fixed full-width overlay that never stops, so
                         there is no seam - only a change of ground behind
                         a constant frame

   All three are the same idea: articulate the boundary with STROKE and
   GROUND, never with silhouette. So there are three devices here, and
   they compose:

   1. THE REVEAL BAND - the architectural shadow gap, literally. The plates
      no longer butt together and no longer overlap; a band of page ground
      opens between them. The hairline sits FLUSH TO THE TOP of that band
      rather than centred in it, because a symmetric empty band reads as
      nothing - the asymmetry plus one piece of type is what makes it a
      detail instead of a gap. The band carries a plate index, the way an
      architecture monograph numbers its plates.

   2. THE DATUM - two hairlines at the gutters, fixed, running the whole
      height of the page. They never stop, so nothing ever fully divides:
      the ground changes behind a constant frame. Over photography a 1px
      white line at 13% either vanishes or reads as a screen artifact, so
      each carries a half-pixel dark shadow underneath it - a stroke
      sandwich - which holds it on a bright sky and a dark brick alike.

   3. THE BLEED - the picture above the band fades into it over its last
      few percent, via a mask rather than an overlay, so the fade is in the
      image's own alpha and nothing is being painted on top of it. Short:
      past about 15% it stops reading as a detail and starts reading as a
      smudge.

   Content never overlaps. Nothing is clipped. Nothing can collide with a
   floating control, because every device sits in its own band or runs the
   full height of the page.                                               */

/* ---------- 1. the reveal band ----------
   Build 011. The band was right; one rule straight across it was not - a
   full-width border is the most ordinary mark there is, and four of them
   down a page is a table, not a detail.

   Three strokes per band instead, and none of them spans the width:

     the long stroke   left gutter to a stopping point that changes band to
                       band - 58%, 71%, 44%, 66%. It stops in open ground,
                       which is what stops it reading as a border-top.
     the short stroke  a second, much shorter rule out at the right, dropped
                       a few pixels below the first, so the two overlap in
                       the horizontal but never meet. Two lines at different
                       heights is the oldest trick in a technical drawing
                       for saying "these are the same line, continued".
     the vector        a fine hairline running on a slight angle between the
                       two heights. Not a diagonal division - an 8px rise
                       over 40px, the angle of a drawn leader line.

   The plate index hangs off the long stroke on a short tick.               */
.seam{position:relative;z-index:2;
  height:clamp(64px,9vh,116px);
  /* Build 019: the colour lives in the theme block at the foot of this file.
     It was hard-coded here, which is exactly how a page ended up striped. */
  display:flex;align-items:flex-start;
  --run:58%;   /* where the long stroke stops */
  --drop:7px}  /* how far the short stroke sits below it */
.seam:nth-of-type(2n){--run:71%;--drop:5px}
.seam:nth-of-type(3n){--run:44%;--drop:9px}
.seam:nth-of-type(4n){--run:66%;--drop:6px}

.seam-in{position:relative;width:100%;max-width:var(--shell);
  margin-inline:auto;padding-inline:var(--gutter)}

/* the long stroke - stops in open ground rather than reaching the edge */
.seam-in::before{content:"";position:absolute;left:var(--gutter);
  width:calc(var(--run) - var(--gutter));top:0;height:1px;
  background:linear-gradient(90deg,
    rgba(196,124,84,.5) 0%,rgba(196,124,84,.5) 82%,rgba(196,124,84,0) 100%)}

/* the short stroke, dropped and out to the right */
.seam-in::after{content:"";position:absolute;right:var(--gutter);
  width:clamp(70px,11vw,190px);top:var(--drop);height:1px;
  background:linear-gradient(90deg,
    rgba(240,236,228,0) 0%,rgba(240,236,228,.26) 34%,rgba(240,236,228,.26) 100%)}

/* the vector between the two heights: a leader line, not a division */
.seam-v{position:absolute;top:0;height:var(--drop);
  left:calc(var(--run) + 2%);width:clamp(26px,3.6vw,56px);
  overflow:visible;pointer-events:none}
.seam-v::before{content:"";position:absolute;inset:0;
  background:linear-gradient(to bottom right,
    transparent calc(50% - .5px),rgba(196,124,84,.34) calc(50% - .5px),
    rgba(196,124,84,.34) calc(50% + .5px),transparent calc(50% + .5px))}

.seam-lab{position:relative;display:inline-flex;align-items:baseline;gap:14px;
  padding-top:17px;
  font-family:'Inter',sans-serif;font-size:9.5px;letter-spacing:.28em;
  text-transform:uppercase;color:rgba(240,236,228,.46)}
.seam-lab b{font-weight:600;color:var(--clay);font-variant-numeric:tabular-nums}
/* the tick that hangs the label off the long stroke */
.seam-lab::before{content:"";position:absolute;left:0;top:calc(-1 * 17px);
  width:1px;height:17px;background:rgba(196,124,84,.42)}

@media(max-width:640px){
  .seam{height:clamp(52px,7vh,72px);--run:74%}
  .seam-in::after,.seam-v{display:none}
}

/* ---------- 2. the datum ---------- */
/* above the sections (the tail sits at 20), below the header at 95 */
/* Build 028: the datum is off. Two fixed hairlines running the full height of
   the window on every page is a vertical rhythm the design does not otherwise
   have - the language here is horizontal: seams, rules, the plate edges. A
   vertical stroke should be a local decision inside a section that earns it,
   like the column rules in the neighbourhood index, not a permanent frame
   around everything. The markup stays on the pages so this is one line to
   undo if it is ever wanted back. */
.datum{display:none}
.datum i{position:absolute;top:0;bottom:0;width:1px;
  background:rgba(255,255,255,.13);
  /* the stroke sandwich: without it the line disappears into a bright sky
     and reads as a rendering artifact over a dark one */
  box-shadow:0 0 0 .5px rgba(8,7,6,.32)}
.datum i:nth-child(1){left:var(--gutter)}
.datum i:nth-child(2){right:var(--gutter)}
@media(max-width:820px){.datum{display:none}}

/* ---------- 3. the bleed ---------- */
/* the last of the picture goes to nothing, in the image's own alpha */
.bleed-end{-webkit-mask-image:linear-gradient(to bottom,#000 87%,transparent 100%);
  mask-image:linear-gradient(to bottom,#000 87%,transparent 100%)}

/* the ground layers stay; they are just grounds now. The joint is the band
   above them, not an edge on them. */
.lap-g{position:absolute;inset:0;z-index:0}

/* Build 011: nothing on this site should fall back to the slate-blue tint */
body{--tint:#191614}
.cb{--cb-accent:#F4F1EA;--cb-on-accent:#1B1A17}
.cb-launch{box-shadow:0 16px 40px rgba(0,0,0,.45);border:1px solid rgba(255,255,255,.2)}
/* Build 043. The button sits 14px off the bottom on a phone and this shadow
   reaches 56px down, 16 of offset plus 40 of blur, so 42px of it lands below
   the screen. That was invisible while the toolbar was solid and covering it.
   Against a glass one it shows through as a line across the bottom corner.
   A shadow's reach is offset plus blur, so it has to come to 14 or less; this
   is 12, with the alpha raised so the button still reads as lifted at that
   size. The hover is included because Safari applies it on tap. Nothing else
   in the widget is touched, and nothing here can affect the toolbar sampling:
   a shadow changes neither a layout box nor a background colour. */
@media(max-width:520px){
  .cb-launch,.cb-launch:hover,.cb-launch:focus-visible{box-shadow:0 2px 10px rgba(0,0,0,.5)}
}
.cb-head{background:#1B1A17 !important;color:#F7F5F0 !important}
.rg-step legend{float:left;width:100%;margin-bottom:clamp(30px,3.6vw,48px)}
.rg-two,.chips{clear:both}
.rg-form input{clear:both}

/* ============================================================
   TEXTURE - for the grounds with no photograph on them
   ============================================================
   From the building again: the homes are vertical cedar over grey brick, so
   the two textures are a fine vertical batten rhythm and a horizontal brick
   course, plus the grain the footer already uses. All laid at an opacity you
   would not name if asked - they exist to stop a large flat fill reading as
   flat fill, and to give the gradients something to sit on so they stop
   banding on a wide screen. */
.tex-batten{background-image:
  repeating-linear-gradient(90deg,
    rgba(255,255,255,.021) 0 1px, transparent 1px 15px)}
.tex-brick{background-image:
  repeating-linear-gradient(0deg,
    rgba(255,255,255,.016) 0 1px, transparent 1px 10px),
  repeating-linear-gradient(90deg,
    rgba(255,255,255,.010) 0 1px, transparent 1px 34px)}
/* the grain rides the ground layer, so it takes the same rounded corners
   rather than printing a hard rectangle over them */
.tex-grain{isolation:isolate}
.tex-grain::after{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  opacity:.30;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E")}

/* ---------- buttons ----------
   Build 007. site.css draws these as hard rectangles, which put square
   corners next to a pill Menu, pill Continue and pill Register - three
   different button shapes on one page. They are all pills now, and the
   hover fills from the left rather than swapping colour on a switch, so
   the fill reads as a movement instead of a state change. */
.btn{position:relative;overflow:hidden;border-radius:999px;
  padding:16px 30px;isolation:isolate;
  transition:color .45s var(--ease),border-color .45s var(--ease)}
.btn::before{content:"";position:absolute;inset:0;z-index:-1;
  background:var(--paper);transform:scaleX(0);transform-origin:left center;
  transition:transform .55s var(--ease)}
.btn:hover::before,.btn:focus-visible::before{transform:scaleX(1)}
.btn-light{border-color:rgba(247,245,240,.5);color:#F7F5F0}
.btn-light:hover,.btn-light:focus-visible{background:transparent;color:var(--ink);
  border-color:var(--paper)}
.btn .arr{transition:transform .45s var(--ease)}
.btn:hover .arr{transform:translateX(6px)}

/* ---------- the lap, wired up on the pages that share this sheet ---------- */
footer{background:transparent}
.fx-bg{overflow:hidden;background-color:#1A1714}
.fx-body{padding-top:clamp(64px,8vw,110px)}

.vh-reg{background:transparent;padding-top:clamp(64px,7.5vw,104px)}
.vh-reg .lap-g{background-color:#2A2621;
  background-image:
    repeating-linear-gradient(0deg,rgba(255,255,255,.016) 0 1px,transparent 1px 10px),
    repeating-linear-gradient(90deg,rgba(255,255,255,.010) 0 1px,transparent 1px 34px),
    linear-gradient(168deg,#332E28 0%,#2A2621 54%,#242019 100%)}
.rg-glow{z-index:1}
.rg-in{z-index:2}

/* ============================================================
   BUILD 012 - the inner pages brought onto the homepage standard
   ============================================================
   The homepage settled a house style over eleven rounds. Everything below
   is that style applied to the five pages that were still running the old
   one: the same grounds, the same texture recipe, the same bands, the same
   reveal, the same light.

   The palette, so it is in one place and stops drifting:
     #1D1A17  the page ground and the reveal bands
     #262220  a lifted plate (the entry walk, an inner-page section)
     #2C2825  a card at rest        #38332C  a card on hover
     #302B25  the registration ground
   ============================================================ */


/* ---------- the grounds ----------
   Bare <section>s on these pages were transparent over the page ground, which
   on a dark site is a very long stretch of one flat colour. Each carries the
   plate ground and the cladding texture now, exactly as the homepage does:
   a vertical batten with a shadow line beside each board, a raking light
   across the fill, and the grain over the top. */
.pg{position:relative;isolation:isolate;background-color:#262220;
  background-image:
    repeating-linear-gradient(90deg,rgba(255,255,255,.040) 0 1px,transparent 1px 15px),
    repeating-linear-gradient(90deg,rgba(0,0,0,.055) 0 1px,transparent 1px 15px),
    linear-gradient(100deg,rgba(255,255,255,.035) 0%,transparent 34%,rgba(0,0,0,.05) 74%)}
/* the grain, on the same terms as the homepage */
.pg::after{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  opacity:.42;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E")}
.pg > *{position:relative;z-index:1}
/* every second one steps a shade darker, so a run of them has a rhythm */
.pg:nth-of-type(even){background-color:#221F1C}

/* the neighbourhood deck takes the same grounds as the homepage plates */
.deck .panel,.nb-times,.nb-plate{background-color:#1D1A17}
.nb-times{background-image:
  repeating-linear-gradient(90deg,rgba(255,255,255,.038) 0 1px,transparent 1px 15px),
  repeating-linear-gradient(90deg,rgba(0,0,0,.05) 0 1px,transparent 1px 15px),
  radial-gradient(92% 74% at 50% 0%,#332E29 0%,#221F1C 68%)}

/* the type on a lifted ground */
.pg .lead,.lead{color:rgba(240,236,228,.68)}
.pg h2.title,h2.title{color:rgba(247,245,240,.88)}
.pg .kicker,.kicker{color:var(--clay)}
.pg p{color:rgba(240,236,228,.7)}

/* ---------- the reveal, on the inner pages ----------
   .reveal/.in is retired: those elements now carry data-rv and are driven by
   the same observer as the homepage, so the trigger point, the easing and the
   stagger are identical everywhere. The rules below only exist to catch the
   handful of places that still add .in from a filter script. */
.reveal,.reveal.in{opacity:1;transform:none;transition:none}
[data-rv].rv-in.hide{display:none}

/* ---------- the opening picture bleeds into the first band ---------- */
.page-head .ph-media.bleed-end,.hero.sub .media.bleed-end{
  -webkit-mask-image:linear-gradient(to bottom,#000 88%,rgba(0,0,0,0) 100%);
  mask-image:linear-gradient(to bottom,#000 88%,rgba(0,0,0,0) 100%)}
.page-head,.hero.sub{background:#1D1A17}

/* ============================================================
   BUILD 013 - the lightbox, the loops, and the registration ground
   ============================================================ */

/* ---------- the lightbox caption ----------
   It was a plain charcoal rectangle sitting in the corner with the title and
   the sentence at nearly the same weight, and the counter floating off on its
   own in a second box. Two boxes for one piece of information.

   One bar now, across the foot, on the same gradient the pictures use rather
   than on a hard panel - so the caption sits ON the photograph instead of in a
   tile parked over it. The title is set in Jost against the sentence in Inter,
   with a clay rule between them and the counter on the same baseline as the
   title, right-aligned. Same vocabulary as the plate bands. */
.lb-bar{padding:0;display:block;
  background:linear-gradient(to top,rgba(12,11,10,.94) 0%,rgba(12,11,10,.72) 46%,rgba(12,11,10,0) 100%);
  padding:clamp(52px,9vh,120px) clamp(18px,3.4vw,44px) clamp(18px,2.8vh,32px)}
.lb-bar::before{content:"";position:absolute;left:clamp(18px,3.4vw,44px);
  right:clamp(18px,3.4vw,44px);bottom:calc(clamp(18px,2.8vh,32px) + 62px);
  height:1px;background:linear-gradient(90deg,
    rgba(196,124,84,.55) 0%,rgba(196,124,84,.55) 24%,rgba(196,124,84,.12) 62%,transparent 100%)}

.lb-cap{background:none;-webkit-backdrop-filter:none;backdrop-filter:none;
  padding:0;max-width:min(62ch,72%);
  font-family:'Inter',sans-serif;font-size:13px;line-height:1.62;
  color:rgba(240,236,228,.72)}
.lb-cap b{display:block;margin:0 0 7px;
  font-family:'Jost',sans-serif;font-weight:200;letter-spacing:-.01em;
  font-size:clamp(20px,2.2vw,30px);line-height:1.14;color:#F7F5F0}

.lb-count{position:absolute;right:clamp(18px,3.4vw,44px);
  bottom:calc(clamp(18px,2.8vh,32px) + 62px + 14px);
  background:none;-webkit-backdrop-filter:none;backdrop-filter:none;padding:0;
  font-family:'Inter',sans-serif;font-size:10px;letter-spacing:.28em;
  text-transform:uppercase;color:rgba(240,236,228,.5);
  font-variant-numeric:tabular-nums}

.lb-zoomhint{background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.16);
  border-radius:999px;padding:9px 18px;font-size:9.5px;letter-spacing:.24em;
  color:rgba(240,236,228,.78)}
.lb-close,.lb-prev,.lb-next{background:rgba(18,17,15,.55);
  border:1px solid rgba(255,255,255,.16);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}

/* a looping clip is not a player: no chrome, and nothing to scrub */
.lb-stage video::-webkit-media-controls{display:none !important}
.lb-stage video::-webkit-media-controls-enclosure{display:none !important}
.lb-stage video{pointer-events:none}

@media(max-width:640px){
  .lb-cap{max-width:100%}
  .lb-count{position:static;display:block;margin-bottom:10px}
  .lb-bar::before{display:none}
}

/* ---------- the registration ground ----------
   It was a brown-black barely separable from the section above it, on a page
   where it is the one thing being asked for. It gets the only real colour on
   the site: the moss the buttons already use, deepened to a ground and warmed
   at one corner by the clay. Still dark enough to carry white type at AA, but
   unmistakably a different room from the plates either side of it. */
.vh-reg .lap-g{background-color:#20302B;
  background-image:
    repeating-linear-gradient(0deg,rgba(255,255,255,.030) 0 1px,transparent 1px 10px),
    repeating-linear-gradient(0deg,rgba(0,0,0,.05) 0 1px,transparent 1px 10px),
    repeating-linear-gradient(90deg,rgba(255,255,255,.022) 0 1px,transparent 1px 34px),
    linear-gradient(to bottom,rgba(29,26,23,0) 90%,#1D1A17 100%),
    linear-gradient(158deg,#2A3D36 0%,#20302B 52%,#1B2724 100%)}
.rg-glow{background:
  radial-gradient(72% 58% at 84% 10%,rgba(206,132,88,.34),transparent 62%),
  radial-gradient(58% 48% at 4% 94%,rgba(150,176,142,.16),transparent 64%)}
.rg-form{background:rgba(255,255,255,.07);border-color:rgba(237,234,227,.2)}
.vh-reg .rg-eyebrow{color:#E8A97E}
.rg-why li::before{background:#E8A97E}
.rg-rail i.on{background:#E8A97E}
.rg-form input:focus{border-bottom-color:#E8A97E}
.chips button[aria-pressed="true"]{background:#F4F1EA;border-color:#F4F1EA;color:#1B2724}

/* ============================================================
   BUILD 015 - the mosaic, the team, and the animation pass
   ============================================================ */

/* ---------- the gallery, as a mosaic ----------
   The coverflow is gone. A uniform grid would have been the safe replacement
   and would also have been a contact sheet - twelve identical rectangles say
   nothing about which picture matters. A mosaic on a twelve-column grid: most
   tiles take four columns, one in seven takes eight and one in five runs two
   rows tall. The rhythm is fixed rather than random, so a filter never leaves
   a hole in the wall. */
.gal{display:grid;grid-template-columns:repeat(12,1fr);
  gap:clamp(8px,1vw,16px);grid-auto-rows:clamp(150px,17vw,240px)}
.gal .g{grid-column:span 4;grid-row:span 1;
  position:relative;display:block;overflow:hidden;border-radius:3px;
  background:#262220}
.gal .g-wide{grid-column:span 8}
.gal .g-tall{grid-row:span 2}
.gal .g img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform 1.6s var(--ease)}
.gal .g:hover img{transform:scale(1.06)}
.gal .g::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to top,rgba(14,13,11,.72),rgba(14,13,11,0) 52%);
  opacity:.9;transition:opacity .6s var(--ease)}
.gal .g:hover::after{opacity:.5}
.gal .g .meta{position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding:clamp(12px,1.4vw,20px);display:grid;gap:5px;
  transform:translateY(6px);opacity:.82;
  transition:transform .6s var(--ease),opacity .5s ease}
.gal .g:hover .meta{transform:none;opacity:1}
.gal .g .meta small{font-family:'Inter',sans-serif;font-size:9px;letter-spacing:.26em;
  text-transform:uppercase;color:var(--clay)}
.gal .g .meta b{font-family:'Jost',sans-serif;font-weight:300;
  font-size:clamp(15px,1.5vw,20px);color:#F7F5F0;line-height:1.15}
.gal .g .zi{position:absolute;top:12px;right:12px;z-index:2;
  width:34px;height:34px;display:grid;place-items:center;border-radius:999px;
  background:rgba(18,17,15,.55);border:1px solid rgba(255,255,255,.18);
  color:#F7F5F0;font-size:13px;opacity:0;transform:scale(.9);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  transition:opacity .45s ease,transform .45s var(--ease)}
.gal .g:hover .zi,.gal .g:focus-visible .zi{opacity:1;transform:none}
.gal .g:focus-visible{outline:2px solid var(--clay);outline-offset:4px}
.gal .g.hide{display:none}
@media(max-width:900px){
  .gal{grid-template-columns:repeat(6,1fr);grid-auto-rows:clamp(130px,22vw,190px)}
  .gal .g{grid-column:span 3}
  .gal .g-wide{grid-column:span 6}
}
@media(max-width:560px){
  .gal{grid-template-columns:repeat(2,1fr);grid-auto-rows:clamp(140px,38vw,190px)}
  .gal .g,.gal .g-wide{grid-column:span 2}
  .gal .g-tall{grid-row:span 1}
}
.gal-tools{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:clamp(20px,2.6vw,34px)}
.gfilter{color:rgba(240,236,228,.55)}
.gfilter:hover{color:#F7F5F0}
.gfilter.on{color:#F7F5F0;border-bottom-color:var(--clay)}
.board-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:18px;margin-bottom:clamp(16px,2vw,26px)}
.board-head h3{font-family:'Jost',sans-serif;font-weight:200;
  font-size:clamp(22px,2.6vw,34px);color:rgba(247,245,240,.9)}
.board-head .hint{font-family:'Inter',sans-serif;font-size:10px;letter-spacing:.24em;
  text-transform:uppercase;color:rgba(240,236,228,.42)}

/* ============================================================
   BUILD 016 - the neighbourhood map
   ============================================================
   Drawn from the same frozen OpenStreetMap snapshot the old iframe used, so
   these are the real streets: Victoria Drive down the middle, Kingsway on the
   diagonal, Trout Lake where Trout Lake is. What makes it a drawing rather
   than a map screenshot is what is left out - no labels on the roads, no
   buildings, no colour except where something is worth walking to.

   Five weights of line carry the whole hierarchy, from a residential hairline
   at 12% white up to Kingsway at 46%. The parks are the only large fill, the
   lake the only saturated one, and the walk rings the only thing drawn in the
   accent - because the rings are the argument the section is making.
   ============================================================ */
.nmap{position:relative;width:100%;aspect-ratio:1/1;max-height:min(78vh,860px);
  margin-top:clamp(20px,2.6vw,34px);overflow:hidden;border-radius:3px;
  background:#1A1815;border:1px solid rgba(240,236,228,.13);isolation:isolate}
@media(max-width:700px){.nmap{aspect-ratio:3/4}}
.nmap-svg{position:absolute;inset:0;width:100%;height:100%;display:block}

/* the ground and its greens */
.m-grass{fill:rgba(126,146,120,.055);stroke:none}
.m-park{fill:rgba(126,146,120,.13);stroke:rgba(126,146,120,.22);stroke-width:1}
.m-garden{fill:rgba(126,146,120,.10);stroke:none}
.m-school{fill:rgba(196,124,84,.07);stroke:rgba(196,124,84,.20);stroke-width:1}
.m-pitch{fill:none;stroke:rgba(240,236,228,.10);stroke-width:1}
.m-water{fill:rgba(92,118,144,.5);stroke:rgba(146,178,204,.45);stroke-width:1.2}

/* the streets: five weights, and nothing else says hierarchy */
.m-resi{fill:none;stroke:rgba(240,236,228,.12);stroke-width:1.1}
.m-tert{fill:none;stroke:rgba(240,236,228,.22);stroke-width:1.8}
.m-sec{fill:none;stroke:rgba(240,236,228,.34);stroke-width:2.6}
.m-prim{fill:none;stroke:rgba(240,236,228,.46);stroke-width:3.6}
.m-resi,.m-tert,.m-sec,.m-prim{stroke-linecap:round;stroke-linejoin:round}
.m-rail{fill:none;stroke:rgba(240,236,228,.3);stroke-width:1.6;stroke-dasharray:1 7;
  stroke-linecap:round}

/* the walk rings - the only thing in the accent, because they are the point */
.m-ring{fill:none;stroke:rgba(196,124,84,.34);stroke-width:1;stroke-dasharray:3 6}
.m-ringlab{fill:rgba(196,124,84,.62);font-family:'Inter',sans-serif;font-size:11px;
  letter-spacing:.22em;text-transform:uppercase;text-anchor:middle}

/* ---------- the pins ----------
   HTML buttons over the drawing, not shapes inside it: focusable, named, and
   able to carry a card without any SVG accessibility gymnastics. */
.npin{position:absolute;left:var(--x);top:var(--y);transform:translate(-50%,-50%);
  z-index:3;display:block;padding:0;border:0;background:none;cursor:pointer;
  color:inherit;font:inherit;
  transition:opacity .45s var(--ease),filter .45s var(--ease)}
.npin.is-off{opacity:.16;filter:grayscale(1);pointer-events:none}
.npin-dot{display:block;width:11px;height:11px;border-radius:50%;
  background:#F4F1EA;box-shadow:0 0 0 4px rgba(26,24,21,.9),0 2px 12px rgba(0,0,0,.5);
  transition:transform .5s var(--ease),background .4s ease}
.npin-park .npin-dot{background:#A8C29B}
.npin-transit .npin-dot{background:#E8A97E}
.npin-shops .npin-dot{background:#EBD9A6}
.npin-school .npin-dot{background:#9FB6C9}
.npin:hover .npin-dot,.npin:focus-visible .npin-dot,.npin.is-open .npin-dot{
  transform:scale(1.45)}
.npin:focus-visible{outline:2px solid var(--clay);outline-offset:8px;border-radius:50%}

/* a ripple, so a pin reads as a place rather than a bullet */
.npin::after{content:"";position:absolute;left:50%;top:50%;width:11px;height:11px;
  margin:-5.5px 0 0 -5.5px;border-radius:50%;pointer-events:none;
  border:1px solid currentColor;color:rgba(240,236,228,.4);
  opacity:0;transform:scale(1)}
.npin:hover::after,.npin:focus-visible::after,.npin.is-open::after{
  animation:npulse 1.9s var(--ease) infinite}
@keyframes npulse{
  0%{opacity:.55;transform:scale(1)}
  70%{opacity:0;transform:scale(3.6)}
  100%{opacity:0;transform:scale(3.6)}}

/* the card */
.npin-card{position:absolute;left:50%;bottom:calc(100% + 14px);
  transform:translate(-50%,6px);width:max-content;max-width:min(240px,44vw);
  display:grid;gap:5px;text-align:left;padding:13px 16px 14px;border-radius:3px;
  background:rgba(20,18,16,.93);border:1px solid rgba(240,236,228,.18);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  box-shadow:0 24px 50px rgba(0,0,0,.5);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .4s ease,transform .5s var(--ease),visibility .4s}
.npin:hover .npin-card,.npin:focus-visible .npin-card,.npin.is-open .npin-card{
  opacity:1;visibility:visible;transform:translate(-50%,0)}
.npin-card::after{content:"";position:absolute;left:50%;top:100%;
  width:1px;height:11px;background:rgba(240,236,228,.3);transform:translateX(-50%)}
.npin-walk{font-family:'Inter',sans-serif;font-size:9px;letter-spacing:.26em;
  text-transform:uppercase;color:var(--clay)}
.npin-name{font-family:'Jost',sans-serif;font-weight:300;font-size:17px;
  line-height:1.14;color:#F7F5F0}
.npin-meta{font-family:'Inter',sans-serif;font-size:11.5px;line-height:1.5;
  color:rgba(240,236,228,.62)}
/* the pins at the top of the frame flip their card underneath */
.npin[style*="--y:1"] .npin-card,.npin[style*="--y:2"] .npin-card{
  bottom:auto;top:calc(100% + 14px)}
.npin[style*="--y:1"] .npin-card::after,.npin[style*="--y:2"] .npin-card::after{
  top:auto;bottom:100%}

/* the site: always on, never filtered, and the only square marker */
.npin-site{z-index:4;pointer-events:none}
.npin-site .npin-dot{width:15px;height:15px;border-radius:2px;background:var(--clay);
  box-shadow:0 0 0 5px rgba(26,24,21,.92),0 0 0 6px rgba(196,124,84,.5),
             0 4px 18px rgba(0,0,0,.55)}
.npin-here{position:absolute;left:50%;top:calc(100% + 12px);transform:translateX(-50%);
  white-space:nowrap;font-family:'Inter',sans-serif;font-size:9.5px;font-weight:600;
  letter-spacing:.26em;text-transform:uppercase;color:#F7F5F0;
  text-shadow:0 2px 10px rgba(0,0,0,.8)}

.nmap-rose{position:absolute;right:clamp(12px,2vw,22px);top:clamp(12px,2vw,22px);
  z-index:3;width:34px;height:34px;color:rgba(240,236,228,.42)}
.nmap-rose svg{width:100%;height:100%;display:block}

/* the filter */
.nmap-tools{display:flex;flex-wrap:wrap;gap:8px;margin-top:clamp(18px,2.4vw,30px)}
.nfilter{font-family:'Inter',sans-serif;font-size:11px;font-weight:600;
  letter-spacing:.16em;text-transform:uppercase;cursor:pointer;
  padding:11px 20px;border-radius:999px;background:none;
  border:1px solid rgba(240,236,228,.22);color:rgba(240,236,228,.66);
  transition:background .4s var(--ease),color .4s ease,border-color .4s ease}
.nfilter:hover{border-color:rgba(240,236,228,.5);color:#F7F5F0}
.nfilter.on{background:#F4F1EA;border-color:#F4F1EA;color:#1B1A17}
.nfilter:focus-visible{outline:2px solid var(--clay);outline-offset:3px}
.nmap-note{margin-top:14px;font-family:'Inter',sans-serif;font-size:11.5px;
  color:rgba(240,236,228,.42)}

@media(max-width:560px){
  .npin-card{max-width:min(200px,58vw);padding:11px 13px 12px}
  .npin-name{font-size:15px}
  .nfilter{padding:10px 15px;font-size:10px;letter-spacing:.12em}
}
@media(prefers-reduced-motion:reduce){
  .npin::after{animation:none !important}
  .npin,.npin-dot,.npin-card{transition:none !important}
}

/* ---------- corners, on the shared sheet ----------
   Same argument as the joint: Victoria Haus is an orthogonal building, and
   the softness on these pages was coming from 12–20px radii on every panel -
   slides, plan boxes, the map frame, the gallery tiles. All down to a
   hairline chamfer. Placed last in the file so it beats the earlier
   declarations rather than having to hunt each one down.

   The pill controls are deliberately excluded. A button is not a panel, and
   Menu, Continue and Register have to stay one family. */
.hcard,.vh-card,.slide,.d-pic,.drawer a,
.planbox,.cmp-plan,.site-holder,.mapframe,.gal-board .g,.demo-note,
.vh-walk .fr,.vh-walk .words{border-radius:3px}
.rg-form{border-radius:4px}

/* ============================================================
   BUILD 014 - mobile
   ============================================================
   Everything below 720px had been laid out by the desktop rules collapsing
   rather than by anything deciding what a phone should get. Three places
   showed it: the lightbox threw away its rule, registration hung off the
   left edge, and the footer stacked into one long undifferentiated column.
   ============================================================ */

/* ---------- the lightbox rule stays ----------
   It was dropped below 640px on the theory that there was no room. There is:
   the rule is what separates the caption from the picture, and without it the
   type just floats on the gradient. It runs shorter and sits directly above
   the counter instead of beside it. */
@media(max-width:640px){
  .lb-bar{padding:clamp(64px,14vh,140px) var(--gutter) calc(env(safe-area-inset-bottom) + 20px)}
  .lb-bar::before{display:block;left:var(--gutter);right:auto;
    width:clamp(90px,42vw,190px);
    bottom:auto;top:calc(clamp(64px,14vh,140px) - 26px);
    background:linear-gradient(90deg,rgba(196,124,84,.6),rgba(196,124,84,.1))}
  .lb-count{position:static;display:block;margin:0 0 12px;
    font-size:9.5px;letter-spacing:.26em}
  .lb-cap b{font-size:clamp(19px,5.4vw,26px)}
  .lb-cap{font-size:12.5px;line-height:1.6}
  .lb-prev,.lb-next{width:44px;height:44px;font-size:18px}
  .lb-close{width:42px;height:42px}
}

/* ---------- registration ----------
   The section is full-bleed and .rg-in is a .wrap, so the gutter was there -
   what was missing was the list resetting its own indent, which put the
   bullets and their text outside everyone else's margin. Beyond that the
   whole block needed to be told what it is on a phone: one column, the form
   as the thing that matters, and the reasons above it rather than beside. */
@media(max-width:720px){
  .vh-reg{padding:clamp(48px,11vw,72px) 0 clamp(44px,10vw,68px)}
  .rg-in{grid-template-columns:1fr;gap:clamp(28px,7vw,40px);align-items:start}
  .rg-say h2{font-size:clamp(29px,8.6vw,42px);line-height:1.04}
  .rg-say > p{max-width:none}
  .rg-why{margin-top:clamp(20px,5.5vw,28px);gap:0}
  .rg-why li{padding:10px 0 10px 28px;font-size:clamp(15px,4.4vw,17px)}
  .rg-why li::before{width:16px;top:1em}
  .rg-contact{margin-top:clamp(24px,6vw,32px)}
  /* the email button goes full width, like Continue - two ways in, one shape */
  .rg-contact a{width:100%;justify-content:center;font-size:11px;
    padding:15px 22px;letter-spacing:.14em}
  .rg-form{padding:clamp(20px,5.5vw,30px);gap:18px}
  .rg-step{gap:clamp(22px,6vw,32px)}
  .rg-step legend{margin-bottom:clamp(22px,6vw,32px);font-size:clamp(20px,5.6vw,26px)}
  .rg-two{grid-template-columns:1fr;gap:20px}
  /* a full-width Continue reads as the next step rather than as a corner button */
  .rg-acts{flex-wrap:wrap;gap:10px}
  .rg-go{margin-left:0;width:100%;justify-content:center;padding:17px 26px}
  .rg-back{order:2;width:100%;text-align:center;padding-top:4px}
  .rg-consent{font-size:11px;line-height:1.6}
  .rg-sum > div{grid-template-columns:9ch 1fr;gap:12px}
}

/* ---------- the footer ----------
   It stacked into one column with every row the same weight, so the last
   screen of the site was a wall of links. It gets a hierarchy: the lead
   stays large, the three utility columns become two, the credits sit on
   their own line at a size that reads, and the legal type gets out of the
   way at the bottom. */
@media(max-width:860px){
  .fx-body{padding:clamp(48px,12vw,80px) 0 clamp(26px,6vw,40px)}
  .f-lead{gap:clamp(22px,6vw,32px);padding-bottom:clamp(30px,8vw,44px)}
  .f-lead-say h2{font-size:clamp(32px,9.4vw,52px);line-height:1.02}
  .f-lead-say p{margin-top:14px;font-size:13.5px}
  .f-lead-act{width:100%;gap:14px}
  .f-lead-act .btn{width:100%;justify-content:center}
  .f-top{padding-top:clamp(30px,8vw,46px);
    grid-template-columns:1fr;gap:clamp(26px,7vw,38px)}
  .f-brand p{font-size:13.5px;max-width:none}
  /* two columns, not three squeezed or one long list */
  .f-cols{grid-template-columns:1fr 1fr;gap:clamp(22px,6vw,34px) clamp(18px,5vw,28px)}
  .f-cols > div:last-child{grid-column:1 / -1}
  .f-cols h4{font-size:9.5px;letter-spacing:.2em;margin-bottom:10px}
  .f-cols a,.f-cols span{font-size:13.5px;padding:6px 0}
}
@media(max-width:520px){
  .f-cols{grid-template-columns:1fr}
  .f-cols > div:last-child{grid-column:auto}
}
@media(max-width:860px){
  .f-credits{--mark:19px;flex-wrap:wrap;gap:clamp(18px,5vw,26px);
    margin-top:clamp(26px,7vw,38px);padding-top:clamp(22px,6vw,32px)}
  .credit{gap:11px}
  .credit small{font-size:9.5px;letter-spacing:.16em}
  .f-legal{flex-direction:column;align-items:flex-start;gap:12px;
    margin-top:clamp(22px,6vw,32px);padding-top:18px}
  .f-legal p{font-size:11px;line-height:1.65}
  .f-copy{white-space:normal}
  .f-mail{font-size:12.5px}
}

/* ---------- the bands, on a phone ----------
   The plate index is the one piece of type on the band, so it stays; the
   band itself comes down so it does not eat a quarter of a small screen. */
@media(max-width:640px){
  .seam{height:clamp(46px,12vw,64px)}
  .seam-lab{padding-top:13px;font-size:9px;letter-spacing:.22em;gap:11px}
  .seam-lab::before{height:13px;top:-13px}
}

/* ============================================================
   BUILD 017 - daylight on the inner pages
   ============================================================
   Every page had gone to the same near-black. On the homepage that is the
   point: it is a reel of photographs and the dark holds them. On the pages
   you actually read - the plans, the team, the neighbourhood - it meant long
   stretches of pale grey type on a black field, and the site stopped having
   any range.

   So the reading sections turn over to paper. The rhythm down an inner page
   becomes: dark opening plate, paper, dark reveal band, paper, moss
   registration, dark footer. The photographs stay dark-mounted; the words sit
   on something you would print on.

   The batten texture inverts with it - dark boards on a light ground rather
   than light boards on a dark one - and the grain comes down, because
   overlay noise reads twice as strong over paper.
   ============================================================ */
.pg{background-color:#EDE9E1;color:#2A2620;
  background-image:
    repeating-linear-gradient(90deg,rgba(43,38,32,.045) 0 1px,transparent 1px 15px),
    repeating-linear-gradient(90deg,rgba(255,255,255,.5) 0 1px,transparent 1px 15px),
    linear-gradient(100deg,rgba(255,255,255,.5) 0%,transparent 38%,rgba(43,38,32,.045) 78%)}
.pg:nth-of-type(even){background-color:#E6E1D8}
.pg::after{opacity:.16}

/* the type */
.pg .kicker{color:#9A6B45}
.pg .kicker::before{background:#9A6B45}
.pg h2,.pg h3,.pg h2.title,.pg .display{color:#1B1A17}
.pg h2 em,.pg h3 em{color:#12110F}
.pg .lead{color:#4E483F}
.pg p,.pg li,.pg dd,.pg .txt{color:#4E483F}
.pg .cap,.pg .note,.pg .hint,.pg .hs-sub{color:#6B6459}
.pg .num,.pg .n,.pg .sq,.pg .lvl,.pg .role{color:#9A6B45}
.pg small{color:#6B6459}
.pg a{color:inherit}

/* rules, panels and cards, restated for paper */
/* Build 026: .list is out of this list too - it was in both plate rules, and
   removing it from only one left the box exactly where it was. */
.pg .frame,.pg .fig,.pg .figA,.pg .figB,.pg .board,.pg .unit,.pg .spec div,
.pg .hs,.pg .member{
  background:rgba(255,255,255,.62);border:1px solid rgba(43,38,32,.14)}
.pg .board-head{border-bottom:1px solid rgba(43,38,32,.14)}
.pg .board-head h3{color:#1B1A17}
.pg .spec dt,.pg .list dt{color:#7A7367}
.pg .spec dd,.pg .list dd{color:#1B1A17}
.pg .list > *,.pg .spec > *{border-color:rgba(43,38,32,.14)}
.pg hr,.pg .rule{background:rgba(43,38,32,.16)}

/* controls on paper */
.pg .gfilter{color:#6B6459}
.pg .gfilter:hover{color:#1B1A17}
.pg .gfilter.on{color:#1B1A17;border-bottom-color:#9A6B45}
.pg .chip{background:rgba(255,255,255,.7);border:1px solid rgba(43,38,32,.16);color:#3A352E}
.pg .chip.on{background:#1B1A17;border-color:#1B1A17;color:#F7F5F0}
.pg .btn{border-color:rgba(27,26,23,.42);color:#1B1A17}
.pg .btn::before{background:#1B1A17}
.pg .btn:hover,.pg .btn:focus-visible{color:#F7F5F0;border-color:#1B1A17}
.pg .btn-light{border-color:rgba(27,26,23,.42);color:#1B1A17}
.pg .btn-light:hover,.pg .btn-light:focus-visible{color:#F7F5F0}

/* the gallery mosaic keeps its dark mounts - a photograph wants a dark edge */
.pg .gal .g{background:#211E1A;border:0}
.pg .gal .g .meta b{color:#F7F5F0}
.pg .gal .g .meta small{color:#E8A97E}

/* the team cards */
.pg .member{background:rgba(255,255,255,.62)}
.pg a.member:hover{background:#fff;border-color:rgba(43,38,32,.3)}
.pg .member .mk{color:#1B1A17}
/* the two real marks are white artwork, so they need their dark plate back */
.pg .member .mk-pair{background:#1B1A17;padding:16px 20px;border-radius:2px}
.pg .member .mk-pair i{background:rgba(247,245,240,.34)}
.pg .member .role{border-top-color:rgba(43,38,32,.18)}
.pg .member h3{color:#1B1A17}
.pg .member p{color:#4E483F}

/* the about block stays moss - it is the one dark thing on a light page,
   which is what makes it read as the closing argument */
.pg .demo-note h3,.pg .demo-note p,.pg .demo-note b{color:inherit}
.pg .demo-note h3{color:#F7F4EE}
.pg .demo-note p{color:rgba(240,236,228,.74)}
.pg .demo-note .btn{border-color:rgba(240,236,228,.42);color:#F7F5F0}
.pg .demo-note .btn::before{background:#F4F1EA}
.pg .demo-note .btn:hover{color:#1B2724}

/* ---------- the marks, everywhere ----------
   They were sized to fit rather than to be seen, and the TwinLines artwork was
   an inverted plate - a white box with the type knocked out of it, which is why
   it read as a black label. The plate is stripped out of the SVG so it is white
   letterforms on nothing, like Dreamlife, and both come up in size. */
.credit{--mark:30px}
.credit .mk.dl{height:calc(var(--mark) * 1.35)}
.credit .mk.tl{height:calc(var(--mark) * 1.619)}
.member .mk img{height:52px}
.member .mk-dl{height:32px}
.member .mk-tl{height:40px}
.dn-mark img{width:clamp(150px,16vw,220px)}
@media(max-width:700px){
  .credit{--mark:24px}
  .member .mk img{height:42px}
  .member .mk-dl{height:26px}
  .member .mk-tl{height:33px}
}

/* ---------- the map, and the room around it ----------
   The frame was sized by the child page reporting its own height, which came
   back taller than the drawing and left a bank of empty ground under it. It is
   given an aspect instead, and the section below no longer opens with a full
   band of padding on top of the band that already separates them. */
/* the frame is sized by the child again; it only needs a floor while that
   measurement is still coming back, and a light ground so the map does not
   flash dark before it draws */
/* Build 023: nothing measures the child any more, so the frame carries its own
   height. A blob-backed iframe has an opaque origin - the parent could never
   read it from disk, and every attempt to threw. */
/* Build 024: overflow was clipping the map to a height that had nothing to do
   with how tall it actually drew. The frame no longer clips, and the height
   below is only a starting value - map.html measures itself and reports up. */
.mapframe{border:1px solid var(--panel-line);background:#faf9f5;overflow:visible;border-radius:0}
.mapframe iframe{width:100%;height:clamp(680px,88vh,1080px);display:block;border:0}
@media(max-width:760px){.mapframe iframe{height:clamp(520px,86vh,820px)}}
#map{padding-bottom:clamp(30px,4vw,54px)}
#map + .seam + .pg{padding-top:clamp(30px,4vw,54px)}

/* ---------- the neighbourhood plates ----------
   Build 019. 018 put picture and words side by side in two columns, which
   read as a slide deck: a big empty half beside a big picture, three times
   in a row, and still most of a screen each.

   The words overlap the picture now - a panel hung off its lower corner,
   crossing the edge - so the plate is only as tall as the photograph and the
   two elements read as one object. Alternating corner down the page. */
.deck .nb-plate{position:relative;height:auto;min-height:0;overflow:visible;
  background-color:var(--ground);
  padding:clamp(26px,3.6vw,52px) var(--gutter)}
.nb-plate .nbp{position:relative;max-width:var(--shell);margin-inline:auto}
.nbp-pic{position:relative;overflow:hidden;border-radius:3px;
  aspect-ratio:16/9;background:#211E1A;width:min(100%,none);
  margin-left:0;margin-right:clamp(0px,10vw,150px)}
.deck .nb-plate:nth-of-type(even) .nbp-pic{
  margin-left:clamp(0px,10vw,150px);margin-right:0}
.deck .nb-plate > img,.nbp-pic > img{position:absolute;inset:0;
  width:100%;height:100%;object-fit:cover;transform:none;border-radius:0}
.nb-plate .grad{display:none}

/* the panel that crosses the edge */
.nb-plate .words{position:absolute;z-index:3;
  right:0;bottom:clamp(-26px,-2.6vw,-14px);
  width:min(430px,72%);display:grid;gap:11px;justify-items:start;
  padding:clamp(22px,2.4vw,32px);
  background:var(--ground);border:1px solid var(--panel-line);
  border-radius:3px;box-shadow:0 26px 60px rgba(10,9,8,.28)}
.deck .nb-plate:nth-of-type(even) .words{right:auto;left:0}
@media(max-width:820px){
  .nbp-pic,.deck .nb-plate:nth-of-type(even) .nbp-pic{
    margin:0;aspect-ratio:4/3}
  .nb-plate .words,.deck .nb-plate:nth-of-type(even) .words{
    position:relative;right:auto;left:auto;bottom:auto;width:100%;
    margin-top:-34px;box-shadow:none}
}
.nb-plate .words .n{font-family:'Inter',sans-serif;font-size:9.5px;letter-spacing:.28em;
  text-transform:uppercase;color:var(--kick)}
.nb-plate .words h2{font-family:'Jost',sans-serif;font-weight:200;letter-spacing:-.02em;
  font-size:clamp(24px,2.6vw,38px);line-height:1.08;color:var(--tx);text-wrap:balance}
.nb-plate .words h2 em{color:var(--tx)}
.nb-plate .words p{font-size:14px;line-height:1.65;color:var(--tx-2);max-width:38ch}
.nb-plate .words .vh-facts{margin-top:2px;color:var(--tx-3)}
.nb-plate .words .vh-facts span+span::before{background:var(--panel-line)}

.deck .nb-times{height:auto;min-height:0;padding-block:clamp(56px,9vh,110px)}

/* ============================================================
   BUILD 018 - the rest of the daylight, and the marks on paper
   ============================================================ */

/* the neighbourhood deck sits on the light ground with everything else; only
   the opening plate and the walk board stay dark, so the page opens and turns
   over once rather than flickering between the two */
.deck .nb-plate{background-color:#EDE9E1;color:#2A2620}
.deck .nb-plate:nth-of-type(even){background-color:#E6E1D8}
.deck .nb-times{background-color:#1D1A17}

/* ---------- the marks on a light ground ----------
   Build 017 put the two real marks on a black plate so the white artwork would
   read. That is the wrong way round on paper: a logo sitting in a black box on
   a cream card looks like a placeholder. The dark artwork already exists -
   dreamlife-black.svg and twinlines-dark.svg - so the light pages use those and
   the plate goes away. Dark pages keep the white pair. */
.pg .member .mk-pair{background:none;padding:0;border-radius:0}
.pg .member .mk-pair i{background:rgba(43,38,32,.26)}

/* ---------- the closing note ----------
   017 turned this into a full-width moss slab with four paragraphs of agency
   copy - a Dreamlife advert stapled to the end of the client's page. It is the
   project's own voice now, and small: a rule, three lines, one credit. */
.demo-note{display:block;background:none;color:inherit;padding:0;
  border-radius:0;margin-top:clamp(40px,5vw,72px);
  border-top:1px solid rgba(43,38,32,.18);padding-top:clamp(22px,3vw,34px)}
.demo-note::after{display:none}
.pg .demo-note h3{color:#1B1A17;font-family:'Jost',sans-serif;font-weight:200;
  letter-spacing:-.01em;font-size:clamp(19px,2vw,25px);line-height:1.14}
.pg .demo-note p{color:#4E483F;font-size:14.5px;line-height:1.72;max-width:62ch;
  margin-top:12px}
.demo-note .dn-mark{display:none}
.dn-body{display:block}
.dn-credit{display:flex;align-items:center;gap:14px;margin-top:clamp(18px,2.4vw,26px);
  text-decoration:none}
.dn-credit small{font-family:'Inter',sans-serif;font-size:9.5px;letter-spacing:.22em;
  text-transform:uppercase;color:#7A7367;transition:color .3s}
.dn-credit img{height:22px;width:auto;display:block}
.dn-credit:hover small{color:#9A6B45}
.pg .demo-note .btn{display:none}

/* ---------- the header must not swallow the page ----------
   Build 018. `body > nav` is `position:fixed; inset:0 0 auto 0` - a strip
   across the full width of every page, containing a wordmark on the left and a
   pill on the right and nothing in between. It has no background, so it looks
   like nothing; it still takes every click that lands in it. Anything in the
   top ~90px of any page - a link, a card, the first row of a drawer - was
   unreachable, and it looked like the link was broken rather than covered.

   The strip is transparent to the pointer now and only the two things actually
   in it take clicks. The drawer also moves above the header, so a full-height
   panel can never have its top rows covered by the strip it opens from. */
body > nav{pointer-events:none}
body > nav .logo,body > nav .burger,body > nav ul,body > nav a{pointer-events:auto}
.drawer{z-index:97}
/* Build 037: the panel is plainly not the full screen now, so the edge that
   faces the page is rounded. Only the two left corners: the right edge is the
   screen edge and a radius there would show the page through the gap. */
/* no overflow change here: .drawer is already overflow:auto, which clips
   children to the radius on its own. overflow:hidden would have taken the
   panel's scrolling away on a short screen. */
.drawer{border-radius:clamp(16px,3.6vw,24px) 0 0 clamp(16px,3.6vw,24px)}
@media(min-width:961px){.drawer{border-radius:clamp(18px,1.6vw,26px) 0 0 clamp(18px,1.6vw,26px)}}

.veil{z-index:96}

/* ============================================================
   BUILD 019 - one theme per page
   ============================================================
   018 lit the reading sections and left the reveal bands hard-coded at
   #1D1A17. So every page came out striped: cream, black bar, cream, black
   bar. That is not a design, it is two designs fighting, and it was my
   mistake - I changed the sections and forgot the thing between them.

   A page now picks ONE base and everything on it follows:

     body.t-dark    the photographic pages - index, homes, gallery
     body.t-light   the reading pages - floor plans, neighbourhood, team

   Every ground, every band and every rule reads from the same four
   variables, so there is no way for one of them to be left behind again.
   The registration block keeps its moss on both, because it is the one
   place that is meant to interrupt.
   ============================================================ */
body.t-dark{
  --ground:#1D1A17; --ground-2:#211E1A; --band:#171512;
  --edge:rgba(196,124,84,.42); --hair:rgba(240,236,228,.14);
  --tx:#F4F1EA; --tx-2:rgba(240,236,228,.68); --tx-3:rgba(240,236,228,.44);
  --kick:#C4805A; --panel:rgba(255,255,255,.05); --panel-line:rgba(240,236,228,.14);
  --batten-a:rgba(255,255,255,.040); --batten-b:rgba(0,0,0,.055);
  --rake:rgba(255,255,255,.035); --grain:.42;
}
body.t-light{
  --ground:#EDE9E1; --ground-2:#E5E0D6; --band:#DDD7CB;
  --edge:rgba(154,107,69,.5); --hair:rgba(43,38,32,.16);
  --tx:#1B1A17; --tx-2:#4E483F; --tx-3:#7A7367;
  --kick:#9A6B45; --panel:rgba(255,255,255,.62); --panel-line:rgba(43,38,32,.14);
  --batten-a:rgba(43,38,32,.045); --batten-b:rgba(255,255,255,.55);
  --rake:rgba(255,255,255,.5); --grain:.16;
}

body{background:var(--ground)}
.page{background:var(--ground)}

/* ---------- the bands take the page's base ---------- */
.seam{background-color:var(--band);
  background-image:
    repeating-linear-gradient(90deg,var(--batten-a) 0 1px,transparent 1px 15px),
    repeating-linear-gradient(90deg,var(--batten-b) 0 1px,transparent 1px 15px)}
.seam-in::before{background:linear-gradient(90deg,
  var(--edge) 0%,var(--edge) 82%,transparent 100%)}
.seam-in::after{background:linear-gradient(90deg,
  transparent 0%,var(--hair) 34%,var(--hair) 100%)}
.seam-v::before{background:linear-gradient(to bottom right,
  transparent calc(50% - .5px),var(--edge) calc(50% - .5px),
  var(--edge) calc(50% + .5px),transparent calc(50% + .5px))}
.seam-lab{color:var(--tx-3)}
.seam-lab b{color:var(--kick)}
.seam-lab::before{background:var(--edge)}

/* ---------- the reading sections ---------- */
.pg{background-color:var(--ground);color:var(--tx);
  background-image:
    repeating-linear-gradient(90deg,var(--batten-a) 0 1px,transparent 1px 15px),
    repeating-linear-gradient(90deg,var(--batten-b) 0 1px,transparent 1px 15px),
    linear-gradient(100deg,var(--rake) 0%,transparent 38%,var(--batten-a) 78%)}
.pg:nth-of-type(even){background-color:var(--ground-2)}
.pg::after{opacity:var(--grain)}

.pg .kicker,.pg .num,.pg .n,.pg .sq,.pg .lvl,.pg .role{color:var(--kick)}
.pg .kicker::before{background:var(--kick)}
.pg h2,.pg h3,.pg h2.title,.pg .display,.pg h2 em,.pg h3 em{color:var(--tx)}
.pg .lead,.pg p,.pg li,.pg dd,.pg .txt{color:var(--tx-2)}
.pg .cap,.pg .note,.pg .hint,.pg .hs-sub,.pg small{color:var(--tx-3)}
.pg .frame,.pg .fig,.pg .figA,.pg .figB,.pg .board,.pg .unit,.pg .spec div,
/* Build 026: .list was in here. A grid with no padding of its own was being
   given a white plate and a border, so the rules ran straight into the edges
   and the whole thing read as a box someone forgot to finish. The index sits
   on the page ground; its own rules are the structure. */
.pg .hs,.pg .member{background:var(--panel);border:1px solid var(--panel-line)}
.pg .board-head{border-bottom:1px solid var(--panel-line)}
.pg .board-head h3{color:var(--tx)}
.pg .spec dt,.pg .list dt{color:var(--tx-3)}
.pg .spec dd,.pg .list dd{color:var(--tx)}
.pg .list > *,.pg .spec > *{border-color:var(--panel-line)}
.pg .gfilter{color:var(--tx-3)}
.pg .gfilter:hover,.pg .gfilter.on{color:var(--tx)}
.pg .gfilter.on{border-bottom-color:var(--kick)}
/* Build 024: a control has to read as a control. The plate is opaque, the
   stroke is the same clay hairline used everywhere, and the label sits at
   full text colour rather than the muted second tier. */
.pg .chip{background:#FCFAF6;border:1px solid rgba(43,38,32,.22);color:var(--tx);
  box-shadow:0 1px 0 rgba(43,38,32,.05)}
.pg .chip:hover{border-color:rgba(43,38,32,.45);background:#fff}
.pg .chip.on{background:var(--tx);border-color:var(--tx);color:var(--ground);box-shadow:none}
.pg .chip.on .dot{background:var(--ground)}
.pg .chip.on .dot.sold{background:rgba(240,236,228,.55)}
.pg .btn,.pg .btn-light{border-color:var(--tx);color:var(--tx);opacity:.92}
.pg .btn::before{background:var(--tx)}
.pg .btn:hover,.pg .btn:focus-visible{color:var(--ground);opacity:1}

/* photographs keep a dark mount on either base - a picture wants a dark edge */
.pg .gal .g{background:#211E1A;border:0}
.pg .gal .g .meta b{color:#F7F5F0}
.pg .gal .g .meta small{color:#E8A97E}

/* ---------- the team cards ---------- */
.pg .member .mk{color:var(--tx)}
.pg .member .mk-pair{background:none;padding:0;border-radius:0}
.pg .member .mk-pair i{background:var(--panel-line)}
.pg .member .role{border-top-color:var(--panel-line)}

/* Build 028: the team cards read heavy on a light page. The plate was a 62%
   white wash, so it sat only a shade off the ground and the card never lifted
   off it - with four dark marks on top, the section read darker than the page
   around it. A solid plate, a firmer edge, the role label on the theme's clay
   rather than the darker base clay, and the body copy up a step. */
body.t-light .pg .member{background:#FBF9F5;border-color:rgba(43,38,32,.17)}
body.t-light a.member:hover{background:#fff;border-color:rgba(43,38,32,.34);
  box-shadow:0 18px 40px rgba(60,52,40,.10)}
body.t-light .pg .member h3{color:#1B1A17}
body.t-light .pg .member p{color:#4A443B}
body.t-light .pg .member .role{color:var(--kick)}
body.t-light .pg .member .mk{opacity:.88}
body.t-light a.member:hover .mk{opacity:1}
.pg a.member:hover{border-color:var(--tx-3)}

/* ---------- the closing note ---------- */
.demo-note{border-top:1px solid var(--panel-line)}
.pg .demo-note h3{color:var(--tx)}
.pg .demo-note p{color:var(--tx-2)}
.dn-credit small{color:var(--tx-3)}
.dn-credit:hover small{color:var(--kick)}

/* ---------- the deck, on a light page ---------- */
body.t-light .deck .nb-plate{background-color:var(--ground);color:var(--tx)}
body.t-light .deck .nb-plate:nth-of-type(even){background-color:var(--ground-2)}
body.t-light .deck .nb-times{background-color:var(--ground-2);color:var(--tx)}
body.t-light .nb-times h2,body.t-light .nb-times .kicker{color:var(--tx)}
body.t-light .nb-times .kicker{color:var(--kick)}
body.t-light .deck .time b,body.t-light .wk-n{color:var(--tx)}
body.t-light .deck .time small,body.t-light .deck .time b i{color:var(--tx-3)}
body.t-light .deck .time{border-top-color:var(--panel-line)}
body.t-light .hero.sub,body.t-light .page-head{background:var(--band)}

/* the map frame belongs to the page, not to itself */
.mapframe{border:1px solid var(--panel-line);background:#faf9f5}

/* ---------- the footer follows the page too ----------
   On a light page a full-dark footer is another black bar, which is the thing
   this build exists to remove. The picture stays; the wash over it goes pale,
   and the type inverts with it. On a dark page nothing changes. */
body.t-light footer{color:#4E483F}
body.t-light .fx-bg{background-color:#E5E0D6}
/* Build 024: picture backings. Invisible while an image covers them, a dark
   plate the moment one is letterboxed or slow. */
body.t-light .nbp-pic,body.t-light .nmap,body.t-light .d-pic{background-color:var(--ground-2)}
/* Build 025: the italic in a headline is the one word that carries the line.
   These were all cream, so on a light page the emphasis vanished. */
body.t-light .nb-times h2 em,body.t-light h2.title em,body.t-light .fan-head h2 em,
body.t-light .nb-plate .words h2 em,body.t-light .page-head h1 em{color:var(--kick)}
body.t-light .fx-wash{
  background:linear-gradient(180deg,rgba(237,233,225,.90) 0%,rgba(232,227,217,.94) 44%,rgba(226,220,209,.97) 100%),
             radial-gradient(72% 58% at 82% 10%,rgba(196,124,84,.16),transparent 62%)}
body.t-light .fx-grain{opacity:.2}
body.t-light .f-lead{border-bottom-color:var(--panel-line)}
body.t-light .f-kick{color:var(--kick)}
body.t-light .f-lead-say h2,body.t-light .f-lead-say h2 em,
body.t-light .f-mark,body.t-light .f-cols a{color:var(--tx)}
body.t-light .f-lead-say p,body.t-light .f-brand p,
body.t-light .f-cols span{color:var(--tx-2)}
body.t-light .f-cols h4{color:var(--kick)}
body.t-light .f-legal{color:var(--tx-3);border-top-color:var(--panel-line)}
body.t-light .f-mail{color:var(--tx-2) !important;border-bottom-color:var(--panel-line)}
body.t-light .f-credits{border-top-color:var(--panel-line)}
body.t-light .credit small{color:var(--tx-3)}
/* the two credit marks are white artwork, so a light footer takes the dark pair */
body.t-light .credit .mk.dl,body.t-light .credit .mk.tl{filter:invert(1)}
body.t-light .f-mark .lmk{color:var(--tx)}
body.t-light .btn-light{border-color:var(--tx);color:var(--tx)}
body.t-light .btn-light::before{background:var(--tx)}
body.t-light .btn-light:hover{color:var(--ground)}

/* the deck's own plates, so nothing in it can be left on the old literal */
body.t-light .deck .panel{background-color:var(--ground)}
body.t-dark .deck .panel{background-color:#211E1A}

/* ---------- Build 020: the bands stop being bands ----------
   A band in its own colour is a strip, and on a page whose whole point is one
   continuous ground that is exactly what it looked like - the section stopped,
   a darker rectangle ran across, the section started again.

   The band takes the page ground now. Nothing changes colour at a seam: the
   grey runs from under the header straight through to the texture below it,
   and what marks the joint is the three strokes and the plate index, which is
   all it ever needed to be.

   The band before the footer is gone from the markup entirely - registration
   butts straight onto it, which is where a page should end. */
.seam{background-color:var(--ground)}
.seam + .pg,.seam + section{background-color:var(--ground)}
/* a seam that follows an even section keeps that section's tone, so the run
   reads as one surface rather than alternating across the joint */
.pg:nth-of-type(even) + .seam{background-color:var(--ground-2)}
.vh-reg{margin-bottom:0}
.vh-reg + footer{margin-top:0}


/* Build 023: the map loading plate is gone - the map is a static drawing
   and should simply be there. */

/* Build 025: a solid square plate, not a hairline pill. It sits on a
   photograph, so it carries its own ground rather than borrowing contrast
   from whatever happens to be behind it. */
/* and the block it now sits in comes up off the bottom edge to make room */
.hero.sub .hero-inner{padding-bottom:clamp(38px,5.2vh,64px)}
/* Build 026: dark at rest, white on hover - the reverse of before. The chat
   button below it is white, so a white plate at rest put two identical
   plates in the same corner. Dark first also lets the hover be a real
   change of state rather than a fill draining away to nothing. */
.hero-jump{display:inline-flex;align-items:center;gap:14px;
  margin-top:clamp(20px,2.4vw,30px);padding:15px 24px;border-radius:0;
  background:rgba(14,13,11,.88);color:#F4F1EA;border:1px solid rgba(244,241,234,.22);
  font-family:'Jost',sans-serif;font-size:12px;font-weight:500;
  letter-spacing:.16em;text-transform:uppercase;text-decoration:none;
  box-shadow:0 12px 34px rgba(10,9,8,.30);
  animation:heroJumpIn .8s var(--ease) .62s both;
  transition:background .4s var(--ease),color .4s var(--ease),
             border-color .4s var(--ease),box-shadow .4s var(--ease)}
.hero-jump:hover,.hero-jump:focus-visible{background:#F7F5F0;color:#14130F;
  border-color:#F7F5F0;box-shadow:0 14px 38px rgba(10,9,8,.34)}
.hero-jump .arr{transition:transform .45s var(--ease);font-size:14px}
.hero-jump:hover .arr{transform:translateY(4px)}
@keyframes heroJumpIn{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.hero-jump{animation:none}}
