/* Castro Oasis / OUT FRONT v1: identity tokens from IDENTITY.md */

@font-face{
  font-family:"Archivo";
  src:url("../assets/font/archivo-var.woff2") format("woff2");
  font-weight:100 900; font-stretch:62% 125%; font-display:swap;
}
@font-face{
  font-family:"Inter Tight";
  src:url("../assets/font/intertight.woff2") format("woff2");
  font-weight:400 500; font-display:swap;
}
@font-face{
  font-family:"JetBrains Mono";
  src:url("../assets/font/jbmono.woff2") format("woff2");
  font-weight:400 500; font-display:swap;
}

/* =====================================================================
   TOKENS.

   Three things separate a dark page that reads as photographed from one
   that reads as filled, and all three are here rather than in any
   component:

   1. THE PAGE IS LIT. `body::before` lays a very low contrast luminance
      field over the whole document, warm from above and cold from the
      upper left, the same direction the hero photograph is lit from.
      Nothing else in the build casts light, so without it every surface
      below the fold is the same flat value and the eye reads "fill".
   2. SURFACES ARE LIFTS, NOT FILLS. `--lift-1/2/3` are alpha whites, so a
      panel sits ON the lit ground rather than punching a hole in it. The
      old `--bay` was an opaque #131316 against an opaque #0B0B0C: a 2%
      step you could not see, doing the work of a section boundary.
   3. THE PAGE HAS GRAIN. `body::after`, 4%, one inlined SVG turbulence.
      It is the cheapest thing on this list and the one that does the most,
      because a perfectly smooth gradient is not a thing a camera makes.

   TYPE runs three tiers, not two. `--d0` is DISPLAY and is spent on
   exactly two things, the closing ask and the quote head, because the
   site opens on that sentence and closes on it. `--d2` is the section
   HEADLINE and `--d3` the sub head. `--d1` is the hero alone: it is set
   at wdth 68, so it needs its own scale and does not belong on the same
   ladder as the rest. Every head being one size was the reason nothing on
   the page looked more important than anything else. Tracking tightens as
   size grows, which is what a display face wants and what the old flat
   -.02em was not doing.
   ===================================================================== */
:root{
  --ink:#09090A; --rule:#2A2A31; --hair:#1A1A1F;
  --cream:#F2EFE7; --ash:#9E9A91;
  --gold:#E6BE3C; --gold-hot:#FFD86B; --gold-dim:#6E5C22; --green:#0A7846;

  --lift-1:rgba(242,239,231,.028);   /* a band, a card */
  --lift-2:rgba(242,239,231,.055);   /* a card on a band, an input well */
  --lift-3:rgba(242,239,231,.085);   /* hover */

  --d0:clamp(2.6rem, 5.9vw, 5.15rem);
  --d1:clamp(2.35rem, 5.15vw, 5.05rem);
  --d2:clamp(1.95rem, 3.8vw, 3.4rem);
  --d3:clamp(1.06rem, 1.6vw, 1.5rem);
  --b1:clamp(.92rem, 1.05vw, 1.02rem);
  --b2:clamp(.98rem, 1.2vw, 1.18rem);
  --m1:.8125rem; --m2:.6875rem;

  --pad:clamp(1.25rem, 5vw, 4.5rem);     /* page margin: 20 / 40 / 72 */
  --sec:clamp(5.5rem, 11vw, 11rem);      /* section padding */
  --sec-sm:clamp(3.4rem, 7vw, 6.5rem);   /* when a section follows its own kind */
  --r:2px;                               /* ONE radius. The page is drawn with rules */

  /* THE SLANT. ONE angle for the whole page. The two tokens below are NOT
     independent: tan(2.4deg) = .0419, so a full-bleed edge that rises by
     4.19vw across the viewport IS 2.4deg, which is why the band's leaning
     edge and the car flying along it agree at every width without either
     one being measured. Change one and you must change the other.
     2.4deg was the first setting and it was too polite to read as a
     decision: 60px of rise across 1440px looked like a rendering
     accident. tan(3.6deg) = .0629. */
  --slant:3.6deg;
  --slant-rise:6.29vw;

  --ease-launch:cubic-bezier(.55,.06,.85,.06);
  --ease-arrive:cubic-bezier(.16,1,.30,1);
  --ease-ui:cubic-bezier(.20,.60,.20,1);
  --t-fast:180ms; --t-base:320ms; --t-exit:900ms; --t-enter:1100ms;

  --mono:"JetBrains Mono",ui-monospace,monospace;
  --disp:"Archivo",system-ui,sans-serif;
  --text:"Inter Tight",system-ui,sans-serif;
}

*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  background:var(--ink); color:var(--cream);
  font-family:var(--text); font-size:var(--b1); line-height:1.6;
  -webkit-font-smoothing:antialiased; overflow-x:hidden;
}
/* the light. Fixed, so it does not scroll with the content and cannot be
   mistaken for a gradient painted on any one section */
body::before{
  content:""; position:fixed; inset:0; z-index:-2; pointer-events:none;
  background:
    radial-gradient(115% 70% at 62% -8%,  rgba(230,190,60,.070), transparent 62%),
    radial-gradient(80%  55% at 6%  14%,  rgba(126,158,214,.045), transparent 70%),
    radial-gradient(120% 90% at 50% 108%, rgba(230,190,60,.028), transparent 66%);
}
/* the grain. One 90px tile of fractal noise, repeated. Nothing loads. */
body::after{
  content:""; position:fixed; inset:0; z-index:-1; pointer-events:none; opacity:.042;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='90' height='90'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/></filter><rect width='90' height='90' filter='url(%23n)'/></svg>");
  background-size:90px 90px;
}
::selection{background:var(--gold); color:var(--ink)}
:focus-visible{outline:2px solid var(--gold); outline-offset:3px; border-radius:var(--r)}
img{display:block; max-width:100%}
button{font:inherit; color:inherit; background:none; border:0; cursor:pointer}
a{color:inherit; text-decoration:none}

/* ---------- nav ---------- */
/* The bar is transparent over the hero and only earns its surface once the
   page has moved. A chrome bar that is always there is a chrome bar you
   stop seeing; one that arrives is a chrome bar that means the reader has
   left the photograph. `page.js` sets `.is-stuck` past 24px. */
/* THREE COLUMNS, not a flex row with `margin-left:auto`. The links belong on
   the CENTRE LINE of the bar and nowhere else: hung off the right they read as
   an afterthought pushed there by the call to action, and the whole bar leans.
   `1fr auto 1fr` centres the middle column on the viewport no matter how wide
   the mark or the button get, which a flex row cannot do. */
.nav{
  position:fixed; inset:0 0 auto 0; z-index:40;
  display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:1.5rem;
  padding:1.35rem clamp(1rem,3.5vw,2.9rem);
  background:linear-gradient(rgba(9,9,10,.55), rgba(9,9,10,.16) 76%, transparent);
  border-bottom:1px solid rgba(242,239,231,.10);
  transition:background var(--t-base) var(--ease-ui), border-color var(--t-base) var(--ease-ui),
             padding var(--t-base) var(--ease-ui);
}
.nav.is-stuck{
  background:rgba(9,9,10,.86); border-bottom-color:var(--hair);
  padding-block:.62rem;
  -webkit-backdrop-filter:blur(14px) saturate(1.2); backdrop-filter:blur(14px) saturate(1.2);
}
.nav__brand{justify-self:start}
.nav__brand img{height:62px; width:auto; transition:height var(--t-base) var(--ease-ui)}
.nav.is-stuck .nav__brand img{height:32px}
.nav__links{
  justify-self:center;
  display:flex; gap:clamp(1.6rem,3.2vw,3rem);
  font-family:var(--mono); font-size:var(--m1); letter-spacing:.18em; text-transform:uppercase;
}
/* over the hero the links are on a PHOTOGRAPH, and ash on a lit shopfront is
   not a legible colour. They only drop to ash once the bar has a ground. */
.nav:not(.is-stuck) .nav__links a{color:rgba(242,239,231,.86)}
/* the underline is drawn, not toggled: a border that appears on hover shifts
   the text by a pixel and the whole bar twitches */
.nav__links a{
  color:var(--ash); padding:.42rem 0; position:relative;
  transition:color var(--t-fast) var(--ease-ui);
}
.nav__links a::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:1px; background:var(--gold);
  transform:scaleX(0); transform-origin:left center;
  transition:transform var(--t-base) var(--ease-arrive);
}
.nav__links a:hover{color:var(--cream)}
.nav__links a:hover::after{transform:scaleX(1)}
.nav__links a[aria-current]{color:var(--cream)}
.nav__links a[aria-current]::after{transform:scaleX(1)}
.nav__cta{justify-self:end}
.nav__cta.btn{padding:1.25rem 2.6rem}
.nav.is-stuck .nav__cta.btn{padding:.82rem 1.35rem}

/* ---------- buttons ---------- */
/* SQUARE. Every other edge on this page is a 1px rule or a 2px corner: the
   inputs, the chips, the figure borders, the bars in section 03. A pill in
   the middle of that reads as a different product, and it was the loudest
   consumer note in the build. */
.btn{
  display:inline-flex; align-items:center; gap:.6rem;
  font-family:var(--mono); font-size:var(--m1); font-weight:500;
  letter-spacing:.14em; text-transform:uppercase;
  padding:.82rem 1.35rem; border-radius:var(--r); white-space:nowrap;
  transition:background var(--t-fast) var(--ease-ui), border-color var(--t-fast) var(--ease-ui),
             color var(--t-fast) var(--ease-ui), transform var(--t-fast) var(--ease-ui);
}
.btn svg{transition:transform var(--t-fast) var(--ease-ui)}
.btn--gold{background:var(--gold); color:var(--ink)}
.btn--gold:hover{background:var(--gold-hot)}
.btn--gold:hover svg{transform:translateX(4px)}
.btn--ghost{
  border:1px solid rgba(242,239,231,.24); color:var(--cream);
  background:var(--lift-1);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
}
.btn--ghost:hover{border-color:rgba(242,239,231,.55); background:var(--lift-3)}
.btn--ghost:hover svg{transform:translateX(4px)}

/* ---------- hero stage ---------- */
.hero{position:relative; height:100svh; min-height:560px; overflow:hidden}
/* pan-y hands vertical scrolling to the page and horizontal intent to the
   drag handler. Without it the browser claims the gesture and the drag dies
   on a pointercancel one move in. */
.stage{position:absolute; inset:0; overflow:hidden; touch-action:pan-y}
/* an <img> is natively draggable, and that native drag was stealing every
   swipe before the listeners saw it */
.stage img, .stage video{
  -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
}
.frame{
  position:absolute; top:50%; left:50%;
  width:max(100vw, calc(100svh * 1.7917));
  aspect-ratio:5504/3072;
  transform:translate(-50%,-50%);
}
.layer{position:absolute; inset:0; width:100%; height:100%; object-fit:fill}
.layer--plate{visibility:hidden}
.layer--plain{
  opacity:0; pointer-events:none;
  -webkit-mask-image:url("../assets/hero/blob.png");
          mask-image:url("../assets/hero/blob.png");
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-size:0px 0px; mask-size:0px 0px;
}
.layer--plain img{position:absolute; inset:0; width:100%; height:100%; object-fit:fill}
.sprite{position:absolute; will-change:transform; pointer-events:none}
/* the drive clips sit exactly where the stills sit, so the handover is invisible */
.clip{
  inset:0; width:100%; height:100%; object-fit:fill;
  transition:opacity 60ms linear;
}
/* the arrival fades off the still it landed on, rather than cutting: the two
   differ only by h264 quantisation and a hard cut showed that as a faint pop */
.clip--settle{transition:opacity 190ms linear}

.scrim{position:absolute; pointer-events:none}
.scrim--left{
  inset:0 auto 0 0; width:56%;
  background:linear-gradient(90deg, rgba(9,9,10,.78), rgba(9,9,10,.38) 46%, transparent);
}
.scrim--bottom{
  inset:auto 0 0 0; height:34%;
  background:linear-gradient(transparent, rgba(9,9,10,.72));
}
/* clear of the credential strip, which lifted off the floor and grew a rule */
.figmark{
  position:absolute; right:clamp(.9rem,2vw,1.6rem); bottom:clamp(7.8rem,14.5vh,10rem);
  font-family:var(--mono); font-size:.5625rem; letter-spacing:.18em; color:rgba(155,151,142,.6);
}

/* ---------- hero copy ---------- */
/* NO centred max-width here, unlike every other block on the site. The copy
   hangs off the LEFT EDGE of the photograph, so its margin has to be a
   fraction of the viewport; a 1440 wrapper would walk it inward on a wide
   screen and the headline would drift away from the frame it is set against.
   `--edge` is that margin and the service card and the credential strip share
   it, so all three left edges line up. */
.hero{--edge:clamp(1.25rem,5.3vw,5.6rem)}
.hero__inner{
  position:relative; z-index:5; height:100%;
  padding:0 clamp(1.1rem,3.5vw,2.6rem) 0 var(--edge);
  display:flex; align-items:flex-start;
  pointer-events:none;               /* the stage underneath owns hover and drag */
}
.hero__inner a, .hero__inner button{pointer-events:auto}
/* The stack is THREE things: the sentence, one line naming what is on screen,
   and the two actions. It used to be six, and six items at four sizes is what
   made the hero read as a column of notes rather than a composition. The
   micron figures that used to sit here are section 02's whole subject, drawn
   to scale, one screen down. */
/* Set from the TOP, not centred. Centring a three item stack in a full height
   hero drops it to the optical middle, which puts the first word of the page
   below the car's roofline; the sentence has to open in the upper third or it
   stops being the thing you read first. The measure is a fraction of the
   viewport so it holds the same proportion on any screen. */
.hero__copy{max-width:33rem; padding-top:clamp(8.5rem,22.7vh,17rem)}
.hero__title{
  font-family:var(--disp); font-size:var(--d1); line-height:.90;
  font-weight:900; font-variation-settings:"wdth" 64; letter-spacing:-.022em;
  word-spacing:.09em;
  text-transform:uppercase; display:grid; gap:.05em;
  text-shadow:0 2px 30px rgba(9,9,10,.5);
}
.hero__title em{font-style:normal; color:var(--gold)}

.svcdeck{position:relative; margin-top:3.1rem; min-height:1.9rem}
.svc{position:absolute; inset:0; visibility:hidden}
.svc.is-active{visibility:visible}
/* Nothing rotates the deck without JS, so stacking the three is the only way
   the other two services are readable at all. The ten live on their own page
   now, which makes this a shorter fallback than it used to be, not a missing
   one. */
.no-js .svcdeck{min-height:0}
.no-js .svc{position:static; visibility:visible}
.no-js .svc + .svc{margin-top:1.4rem; padding-top:1.4rem; border-top:1px solid var(--rule)}
/* ONE line: the service's own mark, its name, its entry price. It replaces a
   counter, a sub head, a sentence and a price sitting on four separate lines. */
.svc__line{
  display:flex; align-items:center; gap:.75rem; flex-wrap:wrap;
  font-family:var(--mono); font-size:var(--m1); font-weight:500;
  letter-spacing:.16em; text-transform:uppercase; color:var(--cream);
}
.svc__ico{flex:none; color:var(--gold)}
.svc__price{
  display:flex; align-items:center; gap:.75rem;
  color:var(--gold); letter-spacing:.12em;
}
/* the divider is drawn by the price, so a service without one needs no markup */
.svc__price::before{content:""; width:1px; height:.95em; background:rgba(242,239,231,.28)}

/* Line-wipe animation for the swap. DIRECT CHILDREN ONLY. The line now nests
   its mark, its name and its price, and a descendant selector would translate
   the parent and then translate each child again inside it, so the icon would
   travel twice as far as the line carrying it. */
.js .svc.is-leaving > [class^="svc__"],
.js .svc.is-entering > [class^="svc__"]{
  animation-duration:var(--t-fast); animation-fill-mode:both; animation-timing-function:var(--ease-ui);
}
.js .svc.is-leaving > [class^="svc__"]{animation-name:lineOut}
.js .svc.is-entering > [class^="svc__"]{animation-name:lineIn; animation-duration:420ms; animation-timing-function:var(--ease-arrive)}
@keyframes lineOut{to{opacity:0; transform:translateY(-10px)}}
@keyframes lineIn{from{opacity:0; transform:translateY(12px)}to{opacity:1; transform:none}}

.hero__cta{display:flex; gap:1rem; margin-top:2.25rem; flex-wrap:wrap}
.hero__cta .btn{padding:1.05rem 1.75rem}
/* The hover hint line is gone. It was a fourth item in a stack the reference
   composition holds to three, and `SEE THE WORK` already performs the reveal
   on click, so the affordance is a control the reader can press rather than a
   caption telling them to try something. */

/* ---------- edges, rail, trust ---------- */
/* ROUND, and below the midline. These are the only circles on the page and
   that is the point: everything else is a rule or a 2px corner, so a disc
   reads unmistakably as "this rotates" rather than as another panel. They sit
   at 58% rather than 50% so they clear the headline's optical centre and land
   against the car instead of the sky. */
.edge{
  position:absolute; top:58%; transform:translateY(-50%); z-index:6;
  width:60px; height:60px; border-radius:50%;
  border:1px solid rgba(242,239,231,.26); color:var(--cream);
  background:var(--lift-1);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
  display:grid; place-items:center;
  transition:border-color var(--t-fast) var(--ease-ui), color var(--t-fast) var(--ease-ui),
             background var(--t-fast) var(--ease-ui);
}
.edge:hover{border-color:var(--gold); color:var(--gold); background:var(--lift-3)}
.edge--left{left:clamp(.7rem,1.8vw,1.6rem)}
.edge--right{right:clamp(.7rem,1.8vw,1.6rem)}

/* The switcher is a CARD, not a strip of text tabs. Each service gets its own
   mark above its name, because three words in a row at 11px is a segmented
   control and reads as a filter on a list rather than as the thing choosing
   what the whole photograph shows. The trailing disc repeats the edge arrows
   inside the card, which is where the hand already is. */
.rail{
  position:absolute; z-index:6; left:var(--edge); bottom:clamp(7.5rem,15.5vh,11rem);
  display:flex; align-items:stretch; padding:.5rem;
  border-radius:var(--r); border:1px solid rgba(242,239,231,.16);
  background:var(--lift-1);
  -webkit-backdrop-filter:blur(14px) saturate(1.25); backdrop-filter:blur(14px) saturate(1.25);
}
.rail__tabs{display:flex; align-items:stretch}
.rail__tab{
  display:grid; justify-items:center; align-content:center; gap:.6rem;
  font-family:var(--mono); font-size:var(--m2); letter-spacing:.16em; text-transform:uppercase;
  color:var(--ash); padding:1.3rem 2.4rem; border-radius:0;
  transition:color var(--t-fast) var(--ease-ui);
}
.rail__tab + .rail__tab{box-shadow:inset 1px 0 0 rgba(242,239,231,.11)}
.rail__tab:hover{color:var(--cream)}
.rail__tab[aria-selected="true"]{color:var(--gold)}
.rail__ico{flex:none}
.rail__next{
  align-self:center; flex:none; margin-inline:.75rem .15rem;
  width:52px; height:52px; border-radius:50%;
  border:1px solid rgba(242,239,231,.26); color:var(--cream);
  display:grid; place-items:center;
  transition:border-color var(--t-fast) var(--ease-ui), color var(--t-fast) var(--ease-ui),
             background var(--t-fast) var(--ease-ui);
}
.rail__next:hover{border-color:var(--gold); color:var(--gold); background:var(--lift-3)}

/* The credential strip. It was a row of green circles on a glass bar and it
   was the one element that read like a plugin. It is now a hairline ledger:
   mono caps, hairline dividers, and the tick shrunk to a mark rather than a
   badge. Green still means "verified" and still means nothing else. */
/* It lifts off the bottom edge and becomes a bordered strip rather than a
   full bleed band welded to the viewport floor. Welded, it read as browser
   chrome; lifted, with its own rule around it, it reads as the last element of
   the photograph. Three EQUAL columns, so the dividers land on a rhythm
   instead of wherever the sentences happen to end. */
.trust{
  position:absolute; z-index:6; inset:auto 0 clamp(1rem,2.6vh,1.7rem) 0;
  display:flex; justify-content:center;
  padding-inline:var(--edge);
}
.trust__inner{
  width:100%; max-width:78vw;
  display:grid; grid-template-columns:repeat(3,1fr);
  border:1px solid rgba(242,239,231,.14); border-radius:var(--r);
  background:rgba(9,9,10,.42);
  -webkit-backdrop-filter:blur(14px) saturate(1.2); backdrop-filter:blur(14px) saturate(1.2);
  font-family:var(--mono); font-size:var(--m1); letter-spacing:.14em; text-transform:uppercase;
  color:var(--cream);
}
.trust p{
  display:flex; align-items:center; gap:.7rem;
  padding:1.4rem clamp(.9rem,2.2vw,1.9rem);
  line-height:1.45;
}
.trust p + p{box-shadow:inset 1px 0 0 rgba(242,239,231,.11)}
.tick{flex:none}

/* ---------- mobile call bar ---------- */
.callbar{display:none}

/* ---------- responsive ---------- */
@media (max-width:900px){
  /* The links used to be hidden here, which was fine when the whole site was
     one scroll and the nav was decoration. It is four pages now, and hiding
     them left a phone with no way to reach three of them. The number goes to
     the screen reader and the call bar instead, and the glyph keeps the
     action in the chrome. */
  .nav{gap:.75rem; padding:.72rem 1rem}
  .nav__brand img{height:30px}
  .nav.is-stuck .nav__brand img{height:28px}
  .nav__links{gap:clamp(.65rem,3vw,1.4rem); font-size:.625rem; letter-spacing:.11em}
  .nav__brand img, .nav.is-stuck .nav__brand img{height:30px}
  .nav__num{
    position:absolute; width:1px; height:1px; margin:-1px;
    overflow:hidden; clip-path:inset(50%); white-space:nowrap;
  }
  .nav__cta.btn, .nav.is-stuck .nav__cta.btn{padding:.62rem; gap:0}
  .hero__inner{padding-left:clamp(1.1rem,3.5vw,2.6rem)}
  .hero__copy{max-width:100%; align-self:flex-end; padding-top:0; padding-bottom:10.5rem}
  .hero__inner{align-items:flex-end}
  .hero__cta .btn{padding:.82rem 1.35rem}
  /* the label line wraps here, and a divider drawn before the price then lands
     at the start of the second line as a stray mark */
  .svc__price::before{display:none}
  .svc__line{gap:.3rem .75rem}
  .scrim--left{width:100%; background:linear-gradient(rgba(9,9,10,.30), transparent 40%)}
  .scrim--bottom{height:62%; background:linear-gradient(transparent, rgba(9,9,10,.88) 72%)}
  .edge{display:none}
  /* the card goes back to a strip on a phone: three marks stacked over three
     words is 150px of a 640px screen spent on a control */
  .rail{
    left:0; right:0; bottom:5.6rem; margin-inline:1rem; padding:0;
    overflow-x:auto; scrollbar-width:none; border-radius:var(--r);
  }
  .rail__tabs{flex:1}
  .rail__tab{
    flex:1; grid-auto-flow:column; justify-items:center; align-items:center;
    gap:.5rem; padding:.72rem .9rem;
  }
  .rail__ico{width:17px; height:17px}
  .rail__next{display:none}
  .rail::-webkit-scrollbar{display:none}
  .trust{display:none}
  .figmark{bottom:auto; top:4.9rem}
  .callbar{
    position:fixed; z-index:50; inset:auto 0 0 0;
    display:flex; gap:.6rem; justify-content:center;
    padding:.7rem 1rem calc(.7rem + env(safe-area-inset-bottom));
    background:rgba(9,9,10,.55);
    -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
    border-top:1px solid rgba(242,239,231,.10);
    transition:transform var(--t-base) var(--ease-ui);
  }
  .callbar[aria-hidden="true"]{transform:translateY(110%)}
  .callbar .btn{flex:1; justify-content:center}
}

/* =====================================================================
   THE DOCUMENT: sections 02 to 11.
   One grid, one eyebrow, one caption rule. Gold is light, green is a mark
   and never a word. No shadows: depth is surface lightness only.
   ===================================================================== */

/* Sections are top heavy on purpose: a heading belongs to what comes after
   it, not to what came before, so the space above a section is larger than
   the space below it. Even padding is what made every block on this page
   read as interchangeable. */
.sec{padding:var(--sec) 0 calc(var(--sec) * .74); position:relative; scroll-margin-top:4.5rem}
/* A band is a LIFT, not a fill. The old `--bay` was an opaque #131316 on an
   opaque #0B0B0C, a 2% step that you could not actually see doing the job of
   a section boundary. An alpha lift sits on the lit ground and keeps the
   grain, so the band reads as a change of surface rather than a change of
   colour, and the hairline above it does the dividing. */
.sec--bay{background:var(--lift-1); border-block:1px solid var(--hair)}
.wrap{max-width:1440px; margin-inline:auto; padding-inline:var(--pad)}

/* =====================================================================
   THE SLANT.

   A band whose top and bottom edges lean by `--slant`, and a car that
   flies along that same lean while the heading is uncovered behind it.
   The angle is shared, so the band edge, the gold path the car runs on
   and the wipe that reveals the words are all one gesture rather than
   three decorations.

   The lean is drawn with a clip-path polygon that stays INSIDE the
   section's own box, not with `transform: skewY()`. Skew was the obvious
   way and it does not work here: it overhangs the box vertically, and
   `.sec--pass` carries `overflow:hidden` to clip the car's travel, so the
   overhang is exactly what gets cut off. An inset polygon needs no
   overhang and therefore does not care about the clip.

   The diagonal edges carry NO hairline, deliberately. The rectangular
   bands are divided by a rule; these are divided by the lean itself, and
   an undecorated diagonal is the more confident of the two. It also
   avoids a second pseudo-element per band to draw two 1px lines that a
   clip-path would immediately eat.
   ===================================================================== */
/* the rise is added to the padding, not taken out of it: the top LEFT
   corner of the band sits `--slant-rise` down from the section's own top
   edge, so without this the first line of an eyebrow can end up outside
   its own band */
.sec--slant{
  background:none; border-block:0;
  padding-block:calc(var(--sec) + var(--slant-rise))
                calc(var(--sec) * .74 + var(--slant-rise));
}
.sec--slant::before{
  content:""; position:absolute; inset:0; z-index:-1; background:var(--lift-1);
  clip-path:polygon(0 var(--slant-rise), 100% 0,
                    100% calc(100% - var(--slant-rise)), 0 100%);
}
/* a page head is a surface too once it leans: the straight rule under it
   goes, and the head becomes the thing the rest of the page sits below */
.phead--slant{
  border-bottom:0;
  padding-bottom:calc(clamp(3.2rem,6vw,5.5rem) + var(--slant-rise));
}
.phead--slant::before{
  content:""; position:absolute; inset:0; z-index:-1; background:var(--lift-1);
  clip-path:polygon(0 0, 100% 0, 100% calc(100% - var(--slant-rise)), 0 100%);
}
/* ONE hairline per band, on the leaning edge the reader meets first: the
   top edge of a band you scroll down into, the bottom edge of a page head
   you scroll down out of. Both edges lined looked like a ribbon; neither
   lined left a 2.8% surface change doing all the work at 3.6deg, which is
   legible but not decisive. The strip is drawn as a polygon rather than a
   border because a clip-path eats borders. */
.sec--slant::after,
.phead--slant::after{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:var(--rule);
}
.sec--slant::after{
  clip-path:polygon(0 var(--slant-rise), 100% 0, 100% 1px, 0 calc(var(--slant-rise) + 1px));
}
.phead--slant::after{
  clip-path:polygon(0 100%, 100% calc(100% - var(--slant-rise)),
                    100% calc(100% - var(--slant-rise) + 1px), 0 calc(100% + 1px));
}

/* Below 700px the rise is under 30px and the lean reads as a mistake
   rather than a decision, so the bands go straight and keep their rule. */
@media (max-width:700px){
  .sec--slant::before{clip-path:none; border-block:1px solid var(--hair)}
  .phead--slant::before{clip-path:none; border-bottom:1px solid var(--hair)}
  .sec--slant::after, .phead--slant::after{display:none}
  .sec--slant{padding-block:var(--sec) calc(var(--sec) * .74)}
  .phead--slant{padding-bottom:clamp(3.2rem,6vw,5.5rem)}
}

/* The eyebrow now rides a rule that runs the FULL width of the measure and
   carries the section's index. Two things come free: the empty right half of
   every head stops reading as an unfinished column, because the rule
   occupies it deliberately; and the page reads as a numbered document, which
   is what it has always been in the copy. */
.eyebrow{
  font-family:var(--mono); font-size:var(--m2); letter-spacing:.18em;
  text-transform:uppercase; color:var(--ash);
  display:flex; align-items:center; gap:.85rem; margin-bottom:1.9rem;
  padding-top:.95rem; border-top:1px solid var(--rule);
}
.eyebrow::after{content:""; height:1px; background:var(--hair); flex:1; margin-left:.2rem}
.eyebrow__n{color:var(--gold); font-variant-numeric:tabular-nums}
.eyebrow__n::after{content:""; display:inline-block; width:18px; height:1px;
  background:var(--gold-dim); vertical-align:.32em; margin-left:.85rem}

.sec__head{
  font-family:var(--disp); font-size:var(--d2); line-height:.94;
  font-weight:800; font-variation-settings:"wdth" 100; letter-spacing:-.03em;
  text-transform:uppercase; text-wrap:balance;
}
/* The head is a two column band on wide screens: headline left, lede right,
   baselines aligned. Before this, nine section heads in a row each put a
   short display line in the left half and left the right half empty, which
   is the single thing that made a careful page look like a template. Only
   heads that HAVE a lede split, which is why `:has()` gates it; a browser
   without `:has()` gets exactly the old single column, so nothing is lost.
   No measure cap on the headline itself: it is a display block with authored
   line breaks, and the 58ch measure belongs to the prose. */
.head{margin-bottom:clamp(2.8rem,5.5vw,5rem)}
/* A head with no lede is not a head with a missing column: it is a
   STATEMENT, and it gets the display tier for it. That gives the page two
   kinds of section rather than nine of the same kind, which is the
   display/headline distinction the reference systems all draw and the one
   this build did not. Six heads qualify, and every one of them is a full
   sentence that earns the size. */
.head:not(:has(> .lede)) .sec__head{
  font-size:var(--d0); line-height:.90; letter-spacing:-.035em;
  font-variation-settings:"wdth" 92; max-width:19ch;
}
@media (min-width:1000px){
  .head:has(> .lede){
    display:grid; grid-template-columns:minmax(0,1.06fr) minmax(0,.94fr);
    column-gap:clamp(2.5rem,6vw,6.5rem); align-items:end;
  }
  .head:has(> .lede) > .eyebrow{grid-column:1 / -1}
  .head:has(> .lede) > .lede{margin-top:0; max-width:46ch; padding-bottom:.35em}
}
.lede{font-size:var(--b2); line-height:1.55; color:var(--cream); max-width:56ch; margin-top:1.5rem}
.body{font-size:var(--b1); line-height:1.65; color:var(--ash); max-width:56ch; margin-top:1rem}

.cap{
  font-family:var(--mono); font-size:var(--m2); letter-spacing:.18em;
  text-transform:uppercase; color:var(--ash); margin-bottom:.7rem;
}
.mark{
  font-family:var(--mono); font-size:var(--m2); letter-spacing:.18em;
  text-transform:uppercase; color:var(--ash); margin-top:1.6rem;
  padding-top:1rem; border-top:1px solid var(--rule); display:inline-block;
}

/* ---------- 02 the promise ---------- */
.promise{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:clamp(2rem,5vw,4.5rem) clamp(2rem,5vw,5rem); align-items:start}
.promise__fig img{width:100%; height:auto; border:1px solid var(--rule)}
.facts{grid-column:1 / -1; display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:1.6rem; padding-top:2.4rem; border-top:1px solid var(--rule)}
.facts dt{font-family:var(--mono); font-size:var(--m2); letter-spacing:.16em; text-transform:uppercase; color:var(--ash); margin-bottom:.5rem}
.facts dd{font-size:var(--b1); line-height:1.4; color:var(--cream)}

/* ---------- 03 the stack ---------- */
.stack{border-top:1px solid var(--rule); padding-top:1.6rem}
.lyr{padding:clamp(1.4rem,2.6vw,2.2rem) 0; border-bottom:1px solid var(--rule)}
.lyr__name{
  font-family:var(--disp); font-size:var(--d3); font-weight:800;
  font-variation-settings:"wdth" 100; text-transform:uppercase; letter-spacing:-.01em;
}
.lyr__bar{position:relative; height:10px; margin:1rem 0 .8rem; background:rgba(242,239,231,.05)}
.lyr__fill{
  position:absolute; inset:0 auto 0 0; width:var(--w); min-width:2px;
  transform-origin:left center;
}
.lyr__fill--gold{background:var(--gold)}
.lyr__fill--ash{background:var(--ash)}
.rev .lyr__fill{transform:scaleX(0); transition:transform 900ms var(--ease-arrive) 120ms}
.rev [data-reveal].in .lyr__fill{transform:scaleX(1)}
.lyr__num{
  font-family:var(--mono); font-size:var(--m1); font-weight:500; letter-spacing:.12em;
  color:var(--gold);
}
.lyr__num i{font-style:normal; color:var(--ash)}
.lyr__note{font-size:var(--b1); line-height:1.55; color:var(--ash); max-width:58ch; margin-top:.7rem}

/* The closing line of section 03 is the argument in one sentence, so it is
   set at the display tier rather than at sub-head size with a rule beside
   it. A pull quote that is the same size as the list it follows is not a
   pull quote. */
.pull{
  font-family:var(--disp); font-size:clamp(1.35rem,2.6vw,2.3rem); font-weight:800;
  font-variation-settings:"wdth" 96; text-transform:uppercase; line-height:1.06;
  letter-spacing:-.025em; margin-top:clamp(3rem,6vw,5rem); max-width:30ch;
  padding-left:clamp(1.2rem,2vw,1.8rem); border-left:2px solid var(--gold);
}
.pull em{font-style:normal; color:var(--gold)}

/* ---------- 04 elite ---------- */
.moats{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:clamp(2rem,4vw,3.6rem)}
.moat__fig{border:1px solid var(--hair); padding:1rem; margin-bottom:1.6rem; background:var(--lift-1)}
.moat__fig img{width:100%; height:clamp(140px,16vw,210px); object-fit:contain; object-position:center}
.moat:nth-child(2) .moat__fig img{object-fit:cover}
.moat__h{
  font-family:var(--disp); font-size:var(--d3); font-weight:800;
  font-variation-settings:"wdth" 100; text-transform:uppercase; line-height:1.15;
  letter-spacing:-.01em; display:flex; gap:.7rem; align-items:flex-start;
}
.moat__h .tick{flex:none; margin-top:.18em}
/* the rule spans the section; only the sentence is capped to a measure. A
   border that stops where the text stops reads as an accident. */
.quote-line{
  margin-top:clamp(2.8rem,5.5vw,4.5rem); padding-top:2.4rem; border-top:1px solid var(--rule);
  font-size:var(--b2); line-height:1.5; color:var(--cream);
}
.quote-line span{display:block; max-width:64ch}

/* ---------- 05 the ten ---------- */
.ten{list-style:none; border-top:1px solid var(--rule)}
.ten__row{
  display:grid; grid-template-columns:minmax(0,17.5rem) minmax(0,1fr) auto;
  gap:.4rem clamp(1.2rem,3vw,2.6rem); align-items:baseline;
  padding:clamp(1.1rem,2vw,1.5rem) 0; border-bottom:1px solid var(--rule);
  transition:background var(--t-fast) var(--ease-ui);
}
.ten__row:hover{background:var(--lift-1)}
.ten__name{
  font-family:var(--disp); font-size:var(--d3); font-weight:800;
  font-variation-settings:"wdth" 100; text-transform:uppercase; letter-spacing:-.01em;
}
.ten__desc{font-size:var(--b1); color:var(--ash); line-height:1.5}
.ten__price{
  font-family:var(--mono); font-size:var(--m1); font-weight:500; letter-spacing:.12em;
  color:var(--gold); white-space:nowrap; text-align:right;
}
.ten__price span{color:var(--ash); font-size:var(--m2)}
.ten__foot{
  margin-top:1.8rem; font-family:var(--mono); font-size:var(--m2);
  letter-spacing:.16em; text-transform:uppercase; color:var(--ash);
}

/* ---------- 06 the work ---------- */
.sec--work{padding-bottom:calc(var(--sec) * .8)}
.strip{overflow-x:auto; overscroll-behavior-x:contain; scrollbar-width:none; -webkit-overflow-scrolling:touch}
.strip::-webkit-scrollbar{display:none}
.strip__rail{
  list-style:none; display:flex; gap:clamp(1rem,2vw,1.8rem);
  padding-inline:var(--pad); width:max-content;
}
.shot{flex:none; width:min(64vw, 22rem); display:flex; flex-direction:column}
.shot--wide{width:min(84vw, 38rem)}
.shot .cap{min-height:2.6em}                     /* two-line captions keep the strip level */
.shot img{
  width:100%; height:clamp(230px, 29vw, 400px); object-fit:cover;
  border:1px solid var(--rule); margin-top:auto;
}
.strip__hint{
  margin-top:1.2rem; font-family:var(--mono); font-size:var(--m2);
  letter-spacing:.16em; text-transform:uppercase; color:var(--ash);
}

/* ---------- 07 the room ---------- */
.room{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:clamp(1.4rem,3vw,2.6rem)}
.room__fig--wide{grid-column:1 / -1}
.room__fig img{width:100%; height:auto; border:1px solid var(--rule)}

/* ---------- 08 how it goes ---------- */
.steps{list-style:none; display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:clamp(1.8rem,4vw,3.4rem)}
.step{padding-top:1.4rem; border-top:1px solid var(--rule); position:relative}
.step::before{content:""; position:absolute; top:-1px; left:0; width:40px; height:1px; background:var(--gold)}
.step__n{font-family:var(--mono); font-size:var(--m1); font-weight:500; letter-spacing:.12em; color:var(--gold)}
.step__h{
  font-family:var(--disp); font-size:var(--d3); font-weight:800; margin-top:.5rem;
  font-variation-settings:"wdth" 100; text-transform:uppercase; letter-spacing:-.015em; line-height:1.1;
  /* step 3 wraps to two lines and step 1 and 2 do not, so without this the
     three paragraphs start on three different baselines */
  min-height:2.2em;
}
.area{margin-top:clamp(2.6rem,5vw,4rem); padding-top:2.2rem; border-top:1px solid var(--rule)}
.area__list{display:flex; flex-wrap:wrap; gap:.6rem}
.area__list span{
  font-family:var(--mono); font-size:var(--m1); letter-spacing:.12em; text-transform:uppercase;
  border:1px solid var(--rule); border-radius:var(--r); padding:.55rem .95rem; color:var(--cream);
  background:var(--lift-1);
}
.area__more{
  margin-top:.9rem; font-family:var(--mono); font-size:var(--m2);
  letter-spacing:.16em; text-transform:uppercase; color:var(--ash);
}

/* ---------- 09 the record ---------- */
/* Was a centred stack: numeral, five gold dashes standing in for stars, a
   caption, a paragraph. The dashes were the problem. They were an
   abstraction of a star rating that read as five leftover rules, and a
   rating drawn as marks invites the reader to count them. The figure states
   itself instead: 4.9 against a quiet /5.0, with the count and the span on
   a ledger line underneath. Nothing is claimed that was not claimed before. */
.sec--score{text-align:center}
.score .eyebrow{justify-content:center}
.score .eyebrow::after{display:none}
.score__fig{
  display:flex; align-items:baseline; justify-content:center; gap:.14em;
  color:var(--gold); line-height:.80;
}
/* mono was giving the decimal point a full monospace cell, so at this size
   4.9 read as "4 . 9". The figure is display type; the qualifier is data. */
.score__n{
  font-family:var(--disp); font-weight:800; font-variation-settings:"wdth" 96;
  font-size:clamp(4.4rem,14vw,10.5rem); letter-spacing:-.045em;
}
.score__of{
  font-family:var(--mono); font-weight:500; color:var(--ash);
  font-size:clamp(1rem,2.2vw,1.8rem); letter-spacing:.02em; margin-left:.18em;
}
.score__cap{
  display:flex; align-items:center; justify-content:center; flex-wrap:wrap;
  gap:.7rem clamp(1rem,3vw,2.4rem); margin-top:clamp(1.6rem,3vw,2.4rem);
  padding-top:1.2rem; border-top:1px solid var(--rule);
  max-width:38rem; margin-inline:auto;
  font-family:var(--mono); font-size:var(--m1); font-weight:500;
  letter-spacing:.18em; text-transform:uppercase; color:var(--cream);
}
.score__cap b{font-weight:500; color:var(--gold)}
.score .lede{margin-inline:auto; text-align:center; margin-top:1.8rem}

/* ---------- 10 quote ---------- */
.quote{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,27rem); gap:clamp(2.4rem,5vw,5.5rem); align-items:start}
.quote .sec__head{font-size:var(--d0); line-height:.90; letter-spacing:-.035em;
  font-variation-settings:"wdth" 92; max-width:14ch}
.quote__direct{display:flex; flex-wrap:wrap; gap:.7rem; margin-top:1.8rem}
.quote__badge{
  display:flex; align-items:center; gap:.6rem; margin-top:1.6rem;
  font-family:var(--mono); font-size:var(--m2); letter-spacing:.14em;
  text-transform:uppercase; color:var(--cream);
}
.qf{border:1px solid var(--rule); background:var(--lift-1); padding:clamp(1.5rem,3vw,2.4rem); border-radius:var(--r)}
.qf__field{margin-bottom:1.1rem}
.qf label{
  display:block; font-family:var(--mono); font-size:var(--m2); letter-spacing:.16em;
  text-transform:uppercase; color:var(--ash); margin-bottom:.5rem;
}
.qf input,.qf select{
  width:100%; font:inherit; font-size:var(--b1); color:var(--cream);
  background:rgba(9,9,10,.55); border:1px solid var(--rule); border-radius:var(--r);
  padding:.78rem .85rem; transition:border-color var(--t-fast) var(--ease-ui),
             background var(--t-fast) var(--ease-ui);
}
.qf input::placeholder{color:rgba(155,151,142,.55)}
.qf input:focus,.qf select:focus{border-color:var(--gold); background:rgba(9,9,10,.85)}
.qf select{appearance:none; background-image:linear-gradient(45deg,transparent 50%,var(--ash) 50%),linear-gradient(135deg,var(--ash) 50%,transparent 50%); background-position:calc(100% - 18px) 55%, calc(100% - 13px) 55%; background-size:5px 5px; background-repeat:no-repeat; padding-right:2.2rem}
.qf__send{width:100%; justify-content:center; margin-top:.4rem}
.qf__note{margin-top:1rem; font-size:var(--m1); line-height:1.5; color:var(--ash)}

/* ---------- 11 footer ---------- */
/* The footer was four thin grey columns and a small mark, which is where a
   careful page usually gives up. It closes on the sentence the shop closes
   on instead: the tagline set at sub-head size beside the mark, the three
   columns as a ledger with their own hairlines, and the address links given
   cream rather than ash so the one thing anyone comes to a footer for is
   the most legible thing in it. */
.foot{border-top:1px solid var(--rule); padding:clamp(3.6rem,6.5vw,6rem) 0 clamp(2rem,4vw,3rem); background:var(--lift-1)}
.foot__grid{display:grid; grid-template-columns:1.5fr repeat(3,minmax(0,1fr)); gap:clamp(2rem,4vw,3.2rem)}
.foot__brand img{height:40px; width:auto; margin-bottom:1.3rem}
.foot__tag{
  font-family:var(--disp); font-size:var(--d3); font-weight:800;
  font-variation-settings:"wdth" 96; letter-spacing:-.02em; line-height:1.1;
  text-transform:uppercase; color:var(--cream); max-width:14ch;
}
.foot__col{padding-top:1.1rem; border-top:1px solid var(--rule)}
.foot__col p{font-size:var(--b1); line-height:1.75; color:var(--ash)}
.foot__col .cap{color:var(--gold); margin-bottom:.9rem}
.foot__col a{color:var(--cream); transition:color var(--t-fast) var(--ease-ui)}
.foot__col a:hover{color:var(--gold)}
.foot__legal{
  max-width:1440px; margin:clamp(2.4rem,5vw,3.6rem) auto 0; padding:1.4rem var(--pad) 0;
  border-top:1px solid var(--rule);
  font-family:var(--mono); font-size:var(--m2); letter-spacing:.14em;
  text-transform:uppercase; color:var(--ash);
}

/* =====================================================================
   THE PASS. A car crosses the heading at speed and the title is left
   behind in its wake.

   Used on THREE headings out of nine, deliberately. It is a punctuation
   mark, and punctuation stops working when every sentence has it.

   Rules it obeys, all of them the same rules the rest of the site obeys:
   the title is real text in the DOM and is readable with JS off, with
   `rev` gating the hidden state; the only colour the car adds is gold,
   because gold is light; it runs once and never repeats; and reduced
   motion gets the title with no car at all.
   ===================================================================== */
/* The car gets its own lane under the heading, so it drives past the words
   instead of through them, and it crosses the whole screen rather than just
   the text block. The section clips it, which is why .sec--pass exists. */
.sec--pass{overflow:hidden}
/* the lane is new vertical space, so claw most of it back off the head's
   own margin, or these three sections breathe differently to the other six */
.wipehead{position:relative; padding-bottom:var(--lane); margin-bottom:calc(var(--lane) * -.62)}
:root{--lane:clamp(52px, 7.5vw, 88px)}

.wipe{
  position:absolute; left:0; bottom:0; width:100%; height:var(--lane);
  z-index:2; pointer-events:none;
}
.wipe__car{
  position:absolute; bottom:0; left:0;
  height:calc(var(--lane) * .92); width:auto;
  opacity:0; will-change:transform;
  transform:translate3d(-70vw, 0, 0);
}
/* a gold hairline is the ground the car runs on, drawn and then let go */
.wipe__line{
  position:absolute; left:0; right:0; bottom:0; height:1px;
  background:linear-gradient(90deg, transparent, var(--gold) 16%, var(--gold) 84%, transparent);
  transform:scaleX(0); transform-origin:left center; opacity:0;
}

/* The title is NEVER hidden by a resting rule. It carries an animation that
   supplies its own covered state for the first 275ms and then uncovers, so a
   heading that is never triggered is simply a normal, readable heading. An
   earlier build hid it with a persistent clip-path and revealed on a class:
   that lost the #quote title outright whenever the trigger did not fire, and
   a heading you can lose is not a heading.

   The reveal window is timed to the car: the nose reaches the heading's left
   edge at ~39% of the travel and clears its right edge at ~64%, so the words
   are uncovered in exactly that gap and the car is genuinely doing the work.

   TIMING. The travel was 760ms and read as a flick: something crossed the
   screen and the title was simply there afterwards. It is now 1250ms, and
   every other number here is the same FRACTION of the travel it always was,
   so the car still does the uncovering and nothing had to be re-measured.
   The geometry is deliberately untouched for the same reason.
   360ms of the travel passes before the car is on screen at all, and that is
   not dead time: the gold line is drawing through it, which is the thing that
   says a car is coming. */
.wipehead.ran .sec__head{animation:titleWake 345ms linear 452ms both}
@keyframes titleWake{
  from{clip-path:inset(0 100% 0 0)}
  to  {clip-path:inset(0 0 0 0)}
}

/* THE DIAGONAL VARIANT.

   The lane rotates by `--slant` and nothing else about the pass changes,
   which is the whole reason it is done this way: the car's own animation
   is still a plain translate, so it now runs ALONG the rotation, and
   every fraction the timing was measured against (nose at the heading's
   left edge at 39% of travel, clear of the right edge at 64%) survives
   untouched. cos(2.4deg) is .999, so the horizontal positions the reveal
   window was tuned to do not move.

   The wipe that uncovers the words leans HARDER than the car flies, and
   that is deliberate rather than sloppy. They are two different gestures:
   the path is a road, and it is nearly flat because a car crossing a
   whole screen cannot climb much without reading as a jump. The wipe is a
   swipe, and a swipe at 2.4deg from vertical is indistinguishable from a
   straight one. The lean is set in `em` so it scales with the type rather
   than with the column, which keeps the angle constant from 390px up. */
.wipe--diag{left:-4%; width:108%; transform:rotate(calc(-1 * var(--slant)))}
/* Once the head splits into two columns the lane is only as wide as the
   headline column, and a road that stops halfway across the page is a
   rule, not a road. 190% of that column is about the full wrap. The ends
   ride out of the lane by ~45px at this angle, which is correct: the
   section clips them, so the path arrives from off the page and leaves
   the same way. */
@media (min-width:1000px){
  .wipe--diag{left:-6%; width:190%}
}
.wipehead--diag.ran .sec__head{animation-name:titleWakeDiag}
@keyframes titleWakeDiag{
  from{clip-path:polygon(-9em 0%, -9em 0%, -11.8em 100%, -11.8em 100%)}
  to  {clip-path:polygon(-9em 0%, calc(100% + 3.2em) 0%,
                         calc(100% + .4em) 100%, -11.8em 100%)}
}
@media (max-width:700px){
  .wipe--diag{left:0; width:100%; transform:none}
}
.wipehead.ran .wipe__car{animation:carPass 1250ms linear both}
.wipehead.ran .wipe__car--blur{animation-name:carPassBlur}
.wipehead.ran .wipe__line{animation:carLine 1640ms cubic-bezier(.22,.7,.30,1) both}

/* Sharp at both ends, smeared through the middle. The smeared frame used to
   hold for 48% of the travel; at this speed that is too much of a pass you
   are now meant to be able to watch, so it holds for 32% and the sharp car
   gets longer at each end, which is where the shape actually reads. */
@keyframes carPass{
  0%  {transform:translate3d(-70vw,0,0); opacity:1}
  22% {opacity:1}
  34% {opacity:0}
  66% {opacity:0}
  78% {opacity:1}
  100%{transform:translate3d(112vw,0,0); opacity:1}
}
@keyframes carPassBlur{
  0%  {transform:translate3d(-70vw,0,0); opacity:0}
  22% {opacity:0}
  34% {opacity:1}
  66% {opacity:1}
  78% {opacity:0}
  100%{transform:translate3d(112vw,0,0); opacity:0}
}
@keyframes carLine{
  0%  {transform:scaleX(0); opacity:0}
  28% {opacity:.5}
  66% {transform:scaleX(1); opacity:.3}
  100%{transform:scaleX(1); opacity:0}
}

/* =====================================================================
   THE OTHER THREE PAGES.

   The site is four pages, not one scroll. Home carries the hero, the
   argument and the ask; SERVICES carries the ten and what they are; WORK
   carries the photography; SHOP carries the room, the process and the
   address. Nothing below invents a new visual language: every page is the
   same grid, the same eyebrow, the same gold hairline, the same rule
   colour, and each one gets exactly ONE car pass, on its own title.
   ===================================================================== */

/* ---------- page header, the three pages that have no hero ---------- */
/* A page with no hero has to earn its top some other way, and the way it
   earns it is air. The title sits well down the page with the lede beside
   it on the same baseline, exactly the split the section heads use, so the
   three inner pages open in the same voice the home page speaks in. */
.phead{
  padding:clamp(8rem,14vw,11.5rem) 0 clamp(3.2rem,6vw,5.5rem);
  border-bottom:1px solid var(--rule); position:relative;
}
.phead__lede{font-size:var(--b2); line-height:1.55; color:var(--ash); max-width:46ch; margin-top:1.6rem}
@media (min-width:1000px){
  .phead__grid{
    display:grid; grid-template-columns:minmax(0,1.06fr) minmax(0,.94fr);
    column-gap:clamp(2.5rem,6vw,6.5rem); align-items:end;
  }
  .phead__grid > .eyebrow{grid-column:1 / -1}
  .phead__grid > .phead__lede{margin-top:0; padding-bottom:.35em}
}
/* the establishing photograph, when a page opens on one */
.phead__fig{margin-top:clamp(2.8rem,5.5vw,4.5rem)}
.phead__fig img{width:100%; height:clamp(220px,34vw,520px); object-fit:cover; border:1px solid var(--hair)}
/* the section that follows a page head does not need a full section's air
   above it: the head already supplied it */
.sec--tight{padding-top:var(--sec-sm)}

/* ---------- home: the way in to the other three ---------- */
.gate{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:clamp(1.2rem,2.6vw,2.2rem)}
.gate__card{
  display:flex; flex-direction:column; border:1px solid var(--hair); background:var(--lift-1);
  transition:border-color var(--t-base) var(--ease-ui), background var(--t-base) var(--ease-ui);
}
.gate__card:hover{border-color:var(--rule); background:var(--lift-2)}
.gate__card img{width:100%; height:clamp(150px,17vw,230px); object-fit:cover}
.gate__body{padding:clamp(1.1rem,2vw,1.6rem); display:flex; flex-direction:column; flex:1}
.gate__h{
  font-family:var(--disp); font-size:var(--d3); font-weight:800;
  font-variation-settings:"wdth" 100; text-transform:uppercase; letter-spacing:-.01em;
  line-height:1.1; margin-bottom:.7rem;
}
.gate__p{font-size:var(--b1); color:var(--ash); line-height:1.5; flex:1}
.gate__go{
  margin-top:1.4rem; font-family:var(--mono); font-size:var(--m2); letter-spacing:.16em;
  text-transform:uppercase; color:var(--gold); display:flex; align-items:center; gap:.5rem;
}
.gate__card:hover .gate__go svg{transform:translateX(4px)}
.gate__go svg{transition:transform var(--t-fast) var(--ease-ui)}

/* ---------- services: four with an argument, six with a price ---------- */
.grp{margin-top:clamp(3rem,6vw,5rem)}
.grp:first-of-type{margin-top:0}
.grp__h{
  font-family:var(--mono); font-size:var(--m2); letter-spacing:.16em; text-transform:uppercase;
  color:var(--cream); padding-top:1.1rem; border-top:1px solid var(--gold); margin-bottom:2.2rem;
}
/* A service earns a figure and a paragraph when there is a real technical
   fact and a real photograph to put behind it. The other six get a clean
   priced line rather than prose written to fill the space. */
.feat{display:grid; grid-template-columns:minmax(0,24rem) minmax(0,1fr); gap:clamp(1.6rem,4vw,3.4rem);
      padding:clamp(2.2rem,4.5vw,3.6rem) 0; border-bottom:1px solid var(--hair); align-items:start}
.feat:first-child{padding-top:0}
.feat:last-child{border-bottom:0}
.feat__fig img{width:100%; height:clamp(190px,21vw,280px); object-fit:cover; border:1px solid var(--rule)}
/* The PROSE is capped, not the row. Capping the whole body at 44rem left
   the price floating a hundred-odd pixels short of the rule it sits above,
   which reads as a broken row rather than an airy one. Cap only the
   sentences and the measure stays honest AND the price lands on the edge. */
.feat__body > p{max-width:52ch}
.feat__top{
  display:grid; grid-template-columns:minmax(0,1fr) auto;
  align-items:baseline; gap:.4rem 1.4rem;
  padding-bottom:1rem; border-bottom:1px solid var(--hair); margin-bottom:1.15rem;
}
.feat__h{
  font-family:var(--disp); font-size:var(--d3); font-weight:800;
  font-variation-settings:"wdth" 100; text-transform:uppercase; letter-spacing:-.01em; line-height:1.1;
}
.feat__price{
  font-family:var(--mono); font-size:var(--m1); font-weight:500; letter-spacing:.12em;
  color:var(--gold); white-space:nowrap;
}
.feat__price span{color:var(--ash); font-size:var(--m2)}
.feat__note{
  margin-top:1.2rem; padding-left:1.1rem; border-left:2px solid var(--gold);
  font-size:var(--b1); line-height:1.55; color:var(--cream); max-width:52ch;
}
.svcfoot{margin-top:clamp(2.4rem,5vw,3.6rem); padding-top:2rem; border-top:1px solid var(--rule)}

/* ---------- work: the photography, given room ---------- */
/* No dense packing. The rows are authored so that each one holds a single
   aspect ratio, and dense flow undoes exactly that: it lifts a short item up
   into an earlier gap, which breaks both the reading order and the alignment
   the rows were built to keep. */
.gal{list-style:none; display:grid; grid-template-columns:repeat(6,minmax(0,1fr));
     gap:clamp(1rem,2.2vw,1.8rem)}
.gal__it{grid-column:span 2; display:flex; flex-direction:column}
.gal__it--w{grid-column:span 3}
.gal__it--f{grid-column:span 6}
.gal__it .cap{min-height:2.6em; order:1; margin:.9rem 0 0}
/* aspect-ratio owns the box and object-fit does the cropping, so height must
   stay auto: a height of 100% inside the flex column fights the ratio */
.gal__it img{width:100%; height:auto; object-fit:cover; border:1px solid var(--rule); aspect-ratio:4/3}
.gal__it--t img{aspect-ratio:3/4}
/* 2/1 rather than 21/9: the opener is a car under their own sign, and the
   wider crop takes the tagline off the top of the sign */
.gal__it--f img{aspect-ratio:2/1}

/* ---------- the closing ask, on the pages with no form ---------- */
.ask{text-align:center}
.ask .eyebrow{justify-content:center}
.ask .eyebrow::after{display:none}
/* the closing ask is the second and last thing on the site set at the
   DISPLAY tier. The hero opens on the sentence, the ask closes on it */
.ask__h{
  font-family:var(--disp); font-size:var(--d0); line-height:.90; font-weight:800;
  font-variation-settings:"wdth" 92; letter-spacing:-.035em; text-transform:uppercase;
  max-width:16ch; margin-inline:auto; text-wrap:balance;
}
.ask__row{display:flex; gap:.8rem; justify-content:center; flex-wrap:wrap; margin-top:2.6rem}
.ask__badge{
  margin-top:1.8rem; display:inline-flex; align-items:center; gap:.6rem;
  font-family:var(--mono); font-size:var(--m2); letter-spacing:.16em; text-transform:uppercase;
  color:var(--ash);
}

/* ---------- shop: where it is ---------- */
.place{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:clamp(1.6rem,4vw,3rem);
       padding-top:2.4rem; border-top:1px solid var(--rule)}
.place__k{font-size:var(--b2); line-height:1.5; color:var(--cream)}
.place__k a:hover{color:var(--gold)}

/* ---------- scroll reveal, gated on html.rev so no-JS reads fully ---------- */
.rev [data-reveal]{opacity:0; transform:translateY(14px); transition:opacity 620ms var(--ease-arrive), transform 620ms var(--ease-arrive)}
.rev [data-reveal].in{opacity:1; transform:none}

/* ---------- responsive ---------- */
@media (max-width:1024px){
  .facts{grid-template-columns:repeat(2,minmax(0,1fr))}
  .steps{grid-template-columns:1fr}
  .foot__grid{grid-template-columns:1fr 1fr}
  .gate{grid-template-columns:1fr}
  .gate__card img{height:clamp(160px,26vw,240px)}
  .place{grid-template-columns:1fr 1fr}
}
@media (max-width:900px){
  .promise{grid-template-columns:1fr}
  .moats{grid-template-columns:1fr}
  .room{grid-template-columns:1fr}
  .room__fig--wide{grid-column:auto}
  .quote{grid-template-columns:1fr}
  .ten__row{grid-template-columns:minmax(0,1fr) auto; row-gap:.35rem}
  .ten__desc{grid-column:1 / -1}
  .feat{grid-template-columns:1fr; gap:1.4rem}
  /* three across is two portraits and a stamp at this width; go to two */
  .gal{grid-template-columns:repeat(4,minmax(0,1fr))}
  .gal__it, .gal__it--w{grid-column:span 2}
  .gal__it--f{grid-column:span 4}
}
@media (max-width:560px){
  .facts{grid-template-columns:1fr}
  .foot__grid{grid-template-columns:1fr}
  .place{grid-template-columns:1fr}
  /* one photograph at a time: two 47vw thumbnails read as neither */
  .gal{grid-template-columns:1fr; gap:2rem}
  .gal__it, .gal__it--w, .gal__it--f{grid-column:span 1}
  .gal__it--f img{aspect-ratio:16/9}
  .gal__it .cap{min-height:0}
  .feat__top{grid-template-columns:1fr; gap:.35rem}
}

/* ---------- reduced motion / no-js ---------- */
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms !important; transition-duration:.01ms !important}
  html{scroll-behavior:auto}
  .rev [data-reveal]{opacity:1; transform:none}
  .rev .lyr__fill{transform:scaleX(1)}
  /* no car, and the title is simply there. The diagonal variant needs
     naming here too: `.wipehead--diag.ran .sec__head` outranks
     `.wipehead.ran .sec__head`, so `animation:none` alone would not hold. */
  .wipehead.ran .sec__head,
  .wipehead--diag.ran .sec__head{animation:none}
  .wipe{display:none}
}
.no-js .edge,.no-js .rail,.no-js .hint{display:none}
