/* L'aur Interiors — English review build */

:root{
  --ground:#fff;
  --ink:#1a1a1a;
  --ink-soft:#4a4744;
  --muted:#8f8a84;
  --line:#e5e1dc;
  --surface:#f6f4f1;
  --accent:#bfa893;
  --accent-dark:#a89179;

  --serif:"Libre Baskerville",Baskerville,"Times New Roman",serif;
  --display:"Bodoni Moda","Libre Baskerville",Baskerville,serif;
  --ui:"Montserrat",-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;

  --pad:clamp(1.25rem,4.5vw,7rem);
  --max:1880px;
  --gap:clamp(1rem,2.2vw,2rem);

  --t-fast:200ms;
  --t-img:400ms;
  --ease:cubic-bezier(.22,.61,.36,1);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--ground);color:var(--ink);
  font-family:var(--serif);font-size:15px;line-height:1.8;
  font-weight:400;-webkit-font-smoothing:antialiased;
}
img{max-width:100%;display:block;height:auto}
a{color:inherit}

/* ---------- loading screen ----------
   Her full logo lockup settling in, then lifting. Driven entirely by CSS keyframes, NOT JS:
   if a script fails the overlay still removes itself, so the site can never get stuck
   behind it. The dash lengths are the measured getTotalLength() of the two pen strokes
   (A 2051.4, B 1088.5) — re-measure if MARK_A / MARK_B ever change.
   The inline script in <head> adds .seen to <html> after the first page of a visit,
   so the loader plays once per session and not on every click. */
.loader{
  position:fixed;inset:0;z-index:200;background:var(--ground);
  display:grid;place-items:center;color:var(--ink);
  animation:ld-out .45s var(--ease) 1.45s forwards;
}
.loader-brand{
  text-align:center;
  animation:ld-lift .45s var(--ease) 1.45s forwards;
}
/* Same lockup as the header: Bodoni wordmark over the tracked-caps role line.
   The script L is NOT used here — it belongs to section 2 and should stay a surprise. */
.ld-name{
  display:block;font-family:var(--display);
  font-size:clamp(1.3rem,3vw,2.35rem);letter-spacing:.16em;text-transform:uppercase;
  line-height:1;color:var(--ink);
  opacity:0;transform:translateY(.5rem);
  /* .25s head start so the webfont has landed before the wordmark appears —
     otherwise a slow connection shows a fallback serif that visibly swaps */
  animation:ld-in .7s var(--ease) .25s forwards;
}
.ld-role{
  display:block;margin-top:1rem;font-family:var(--ui);font-weight:400;
  font-size:clamp(.56rem,.8vw,.66rem);letter-spacing:.34em;text-transform:uppercase;
  color:var(--muted);
  opacity:0;transform:translateY(.4rem);
  animation:ld-in .7s var(--ease) .5s forwards;
}
@keyframes ld-in{to{opacity:1;transform:none}}
@keyframes ld-out{to{opacity:0;visibility:hidden}}
@keyframes ld-lift{to{transform:translateY(-.75rem)}}
/* second page onward, and anyone who asked for less motion: no loader at all */
.seen .loader{display:none}
@media (prefers-reduced-motion:reduce){.loader{display:none}}

/* ---------- shell ---------- */
.wrap{max-width:var(--max);margin-inline:auto;padding-inline:var(--pad)}

/* ---------- header ---------- */
.site-head{
  position:sticky;top:0;z-index:50;background:var(--ground);
  border-bottom:1px solid transparent;
}
.site-head.is-stuck{border-bottom-color:var(--line)}
.head-in{
  display:flex;align-items:center;justify-content:space-between;
  gap:2rem;padding-block:1.75rem;
}
.brand{text-decoration:none;display:inline-block;line-height:1}
.brand .name{
  font-family:var(--display);font-size:clamp(1.05rem,1.6vw,1.45rem);
  letter-spacing:.14em;text-transform:uppercase;display:block;
}
.brand .role{
  font-family:var(--ui);font-size:.56rem;font-weight:400;
  letter-spacing:.34em;text-transform:uppercase;color:var(--muted);
  display:block;margin-top:.5rem;
}
.head-right{display:flex;align-items:center;gap:clamp(1.25rem,3vw,2.75rem)}
.nav{display:flex;gap:clamp(1.25rem,2.5vw,2.25rem)}
.nav a{
  font-family:var(--ui);font-size:.72rem;letter-spacing:.13em;
  text-transform:lowercase;text-decoration:none;color:var(--ink-soft);
  padding-block:.35rem;position:relative;
}
.nav a::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:var(--ink);transform:scaleX(0);transform-origin:left;
  transition:transform var(--t-fast) var(--ease);
}
.nav a:hover::after,.nav a:focus-visible::after{transform:scaleX(1)}
.nav a[aria-current="page"]{color:var(--ink)}
.nav a[aria-current="page"]::after{transform:scaleX(1);background:var(--muted)}

.lang{display:flex;gap:.5rem;font-family:var(--ui);font-size:.68rem;letter-spacing:.1em;color:var(--muted)}
.lang a{text-decoration:none}
.lang a[aria-current]{color:var(--ink);border-bottom:1px solid var(--ink)}
.lang span{opacity:.4}

.social{display:flex;gap:1rem;align-items:center}
.social a{color:var(--muted);transition:color var(--t-fast) var(--ease);display:inline-flex}
.social a:hover{color:var(--ink)}
.social svg{width:15px;height:15px;fill:currentColor}

.burger{display:none;background:none;border:0;padding:.5rem;cursor:pointer;color:var(--ink)}
.burger svg{width:22px;height:22px;stroke:currentColor;fill:none;stroke-width:1.2}

/* ---------- type ---------- */
h1,h2,h3{font-weight:400;margin:0}
/* Bodoni is the WORDMARK ONLY. Anything you read as words is Libre Baskerville. */
.h-display{
  font-family:var(--serif);
  font-size:clamp(1.45rem,2.85vw,2.45rem);line-height:1.36;letter-spacing:-.008em;
  padding-bottom:.08em;
}
.h-sec{
  font-family:var(--serif);
  font-size:clamp(1.12rem,1.72vw,1.82rem);line-height:1.45;letter-spacing:-.006em;
  text-wrap:balance;
}
.eyebrow{
  font-family:var(--ui);font-size:.62rem;font-weight:500;letter-spacing:.3em;
  text-transform:uppercase;color:var(--muted);margin:0 0 1.5rem;
}
/* balance = two lines of near-equal length instead of a long line and a stub.
   The column is capped in ch, which is font-relative, so the break holds at any width. */
.lede{font-size:clamp(1rem,1.4vw,1.13rem);line-height:1.85;color:var(--ink-soft);text-wrap:balance}
p{margin:0 0 1.4em}
p:last-child{margin-bottom:0}

/* ---------- buttons / links ---------- */
.btn{
  display:inline-block;font-family:var(--ui);font-size:.7rem;letter-spacing:.2em;
  text-transform:uppercase;text-decoration:none;
  background:var(--accent);color:#fff;padding:1.05rem 2.5rem;border:0;cursor:pointer;
  transition:background var(--t-fast) var(--ease);
}
.btn:hover,.btn:focus-visible{background:var(--accent-dark)}
.btn-text{
  display:inline-block;font-family:var(--ui);font-size:.7rem;letter-spacing:.2em;
  text-transform:uppercase;text-decoration:none;color:var(--ink);
  background:none;border:0;border-bottom:1px solid var(--ink);
  padding:0 0 .55rem;cursor:pointer;
  transition:color var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease);
}
.btn-text:hover,.btn-text:focus-visible{color:var(--accent-dark);border-color:var(--accent-dark)}
.back-link{
  font-family:var(--ui);font-size:.68rem;letter-spacing:.14em;text-transform:lowercase;
  color:var(--muted);text-decoration:none;display:inline-flex;align-items:center;gap:.6rem;
  transition:color var(--t-fast) var(--ease);
}
.back-link:hover{color:var(--ink)}

/* ---------- image fade (the only load motion) ---------- */
.ph{background:var(--surface);overflow:hidden;position:relative}
/* the hidden state is gated on html.js: if main.js never runs, the head script drops
   .js after 3s and every photo shows rather than staying invisible forever */
.js .ph img{opacity:0}
.ph img{transition:opacity var(--t-img) var(--ease)}
.ph img.loaded{opacity:1}

/* ---------- sections ---------- */
.sec{padding-block:clamp(4rem,9vw,8.5rem)}
.sec-tight{padding-block:clamp(2.5rem,5vw,4.5rem)}
.rule{border:0;border-top:1px solid var(--line);margin:0}

/* ---------- home ---------- */
/* Hero — the reference proportion: one very large frame filling the right side and
   running off the right edge, statement on the far left, corner line underneath. */
.hero{position:relative;overflow:hidden}
.hero-in{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(2rem,4vw,4.5rem);
  align-items:stretch;
  min-height:calc(100svh - 12.5rem);
  padding-block:clamp(1rem,2vw,2rem) 0;
}
.hero-copy{display:flex;flex-direction:column;justify-content:center}
/* One statement, one font, no italics. Her brief: short, strong overview. */
/* The lines are authored in build.py, one <span> per line, so no phrase gets split:
   "interior architecture", "Laura De Boeck" and each service stay whole. Below 900px
   the spans go inline again and the browser wraps it normally. */
.hero-statement{
  font-family:var(--serif);font-weight:400;font-style:normal;
  /* same size as the section 2 line — TJ, 25 Aug */
  font-size:clamp(1.35rem,2.02vw,2.35rem);line-height:1.34;letter-spacing:-.006em;
  margin:0;max-width:22em;text-wrap:pretty;
}
.hero-statement span{display:inline}
/* Only wide enough to hold the authored lines. Under this the browser wraps it. */
@media (min-width:1240px){
  .hero-statement{max-width:none;text-wrap:nowrap}
  .hero-statement span{display:block}
}
/* the frame bleeds past the right page margin, like the reference */
.hero-frame{
  display:flex;flex-direction:column;
  margin-right:calc(var(--pad) * -1);
}
.hero-media{
  position:relative;flex:1;min-height:clamp(420px,74svh,1150px);
  background:var(--surface);overflow:hidden;
}
.hero-media img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity 1200ms var(--ease);
}
.hero-media img.on{opacity:1}
.hero-dots{display:flex;gap:.5rem;margin-top:1rem;justify-content:flex-start}
.hero-dots i{
  width:14px;height:1px;background:var(--line);display:block;
  transition:background var(--t-fast) var(--ease);
}
.hero-dots i.on{background:var(--ink)}
@media (prefers-reduced-motion:reduce){
  .hero-media img{transition:none}
}
/* corner line: SEO tag left, live Belgium time right */
.hero-foot{
  display:flex;align-items:baseline;justify-content:space-between;
  gap:1.5rem;padding-block:clamp(1.75rem,3vw,2.75rem);
}
.hero-cue,.hero-clock{
  font-family:var(--ui);font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--muted);margin:0;
}
/* not a link — TJ, 26 Aug. It is a label, the arrow just says "more below". */
.hero-cue{margin:0;display:inline-flex;align-items:center;gap:.6rem}
.hero-cue::before{content:"\2193";font-size:.8rem;letter-spacing:0}
.hero-cue span{position:relative;display:inline-block}
.hero-clock{display:inline-flex;gap:.7rem;font-variant-numeric:tabular-nums}
.hero-clock time{color:var(--ink)}
.intro-grid{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(2rem,5vw,5rem);
}
.intro-grid .col{max-width:52ch}
.meta-list{list-style:none;margin:0;padding:0}
.meta-list li{
  font-family:var(--ui);font-size:.78rem;letter-spacing:.04em;
  color:var(--ink-soft);padding-block:.85rem;border-bottom:1px solid var(--line);
}
.meta-list li:first-child{border-top:1px solid var(--line)}

/* featured projects on home */
/* Six cards: the first and last run full width, the four between sit in pairs.
   Stops the section reading as one long identical list. */
.work-list{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  column-gap:var(--gap);row-gap:clamp(3.5rem,7vw,6.5rem);
}
.work-item.wide{grid-column:1 / -1}
.work-item:not(.wide) .ph{aspect-ratio:4/3}
.work-item{text-decoration:none;display:block}
.work-item .ph{aspect-ratio:16/9}
.work-item .ph img{width:100%;height:100%;object-fit:cover}
.work-cap{
  display:flex;align-items:baseline;justify-content:space-between;
  gap:2rem;padding-top:.95rem;
}
/* Project name = the clean face, bold. Tag = the same face, plain, grey, no caps. */
.work-name{
  font-family:var(--ui);font-weight:600;font-size:clamp(.78rem,.9vw,.92rem);
  letter-spacing:.02em;margin:0;
  transition:color var(--t-fast) var(--ease);
}
.work-tag{
  font-family:var(--ui);font-weight:400;font-size:clamp(.68rem,.76vw,.78rem);
  letter-spacing:.02em;text-transform:none;
  color:var(--muted);white-space:nowrap;
}
/* Hover = the whole card fades slightly, the JUMA pattern (opacity .8 over .3s).
   Pointer devices only, so a tap on mobile does not leave a card stuck faded. */
@media (hover:hover) and (pointer:fine){
  .work-item,.proj-card{transition:opacity .3s var(--ease)}
  .work-item:hover,.work-item:focus-visible,
  .proj-card:hover,.proj-card:focus-visible{opacity:.8}
}
@media (prefers-reduced-motion:reduce){
  .work-item,.proj-card{transition:none}
}
.work-more{margin-top:clamp(3rem,6vw,5rem);text-align:center}
.cta-band{text-align:center;max-width:48ch;margin-inline:auto}
.cta-band .h-sec{margin-bottom:2.25rem}

/* ---------- projects index (Victor pattern) ---------- */
.proj-grid{
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(1.75rem,3vw,2.75rem) var(--gap);
}
.proj-card{text-decoration:none;display:block}
.proj-card .ph{aspect-ratio:4/3}
.proj-card .ph img{width:100%;height:100%;object-fit:cover}
/* Same caption shape as the home cards: name left, tag small and right on one
   baseline, description on its own row under the name. The old stack (caps eyebrow,
   name, description) cost a whole row of height and left the card's width unused. */
.proj-meta{
  display:grid;grid-template-columns:minmax(0,1fr) auto;
  align-items:baseline;column-gap:1.5rem;padding-top:.95rem;
}
.proj-name{
  grid-column:1;
  font-family:var(--ui);font-weight:600;font-size:clamp(.82rem,.95vw,.95rem);
  letter-spacing:.02em;text-transform:none;margin:0;
}
.proj-cat{
  grid-column:2;justify-self:end;text-align:right;
  font-family:var(--ui);font-size:clamp(.68rem,.76vw,.78rem);font-weight:400;
  letter-spacing:.02em;text-transform:none;color:var(--muted);white-space:nowrap;
}
.proj-desc{
  grid-column:1/-1;margin:.45rem 0 0;max-width:56ch;
  font-family:var(--ui);font-size:.76rem;font-weight:400;line-height:1.9;
  letter-spacing:.01em;color:var(--muted);
}
.proj-card .proj-name{transition:color var(--t-fast) var(--ease)}


/* ---------- project detail ---------- */
.detail-head{
  display:grid;grid-template-columns:minmax(0,320px) minmax(0,1fr);
  gap:clamp(2rem,5vw,5rem);align-items:start;
  padding-block:clamp(1.5rem,3vw,2.5rem) clamp(3rem,6vw,5rem);
}
/* The whole side column is Montserrat, one size, one rhythm. No dashes, no markers —
   TJ, 26 Aug: "more minimal, no -, all one clean font, uniform". */
.detail-side{position:sticky;top:7.5rem;font-family:var(--ui)}
.detail-title{
  font-family:var(--ui);font-weight:500;
  font-size:clamp(1rem,1.15vw,1.18rem);letter-spacing:.02em;line-height:1.4;
  margin:1.75rem 0 .75rem;
}
.detail-meta{
  font-family:var(--ui);font-size:.66rem;font-weight:400;letter-spacing:.22em;
  text-transform:uppercase;color:var(--muted);margin:0 0 2.25rem;
}
.bullets{list-style:none;margin:0 0 2.25rem;padding:0}
.bullets li{
  font-family:var(--ui);font-size:.78rem;font-weight:400;line-height:2;
  letter-spacing:.01em;color:var(--ink);margin:0;
}
.detail-note{
  font-family:var(--ui);font-size:.78rem;font-weight:400;line-height:2;
  letter-spacing:.01em;color:var(--muted);margin:0;max-width:34ch;
}
.detail-lead img{width:100%}

/* photo rows — varied, no captions unless before/after */
.rows{display:flex;flex-direction:column;gap:clamp(2rem,4vw,3.5rem)}
.row{display:grid;gap:var(--gap)}
.row-1{grid-template-columns:minmax(0,1fr)}
.row-2{grid-template-columns:repeat(2,minmax(0,1fr))}
.row-3{grid-template-columns:repeat(3,minmax(0,1fr))}
.row-2-1{grid-template-columns:2fr 1fr}
.row-1-2{grid-template-columns:1fr 2fr}
.row .ph img{width:100%}
/* uneven rows: the narrow frame crops to the row height instead of leaving a gap */
.row-2-1 .ph,.row-1-2 .ph{height:100%}
.row-2-1 .ph img,.row-1-2 .ph img{height:100%;object-fit:cover}
.row.fixed .ph{aspect-ratio:3/4}
.row.fixed.land .ph{aspect-ratio:3/2}
.row.fixed .ph img{height:100%;object-fit:cover}
.cap{
  font-family:var(--ui);font-size:.58rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);padding-top:.6rem;
}

/* ---------- contact (Britt pattern) ---------- */
.contact-grid{
  display:grid;grid-template-columns:minmax(0,300px) minmax(0,1fr);
  gap:clamp(2.5rem,6vw,6rem);align-items:start;
}
.info-list{margin:2.5rem 0 0}
.info-row{padding-bottom:1.1rem;margin-bottom:1.1rem;border-bottom:1px solid var(--line)}
.info-row .lbl{
  font-family:var(--ui);font-size:.62rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);display:block;margin-bottom:.5rem;
}
.info-row .val{
  font-family:var(--ui);font-size:.8rem;line-height:1.95;letter-spacing:.01em;
  color:var(--ink);text-decoration:none;display:block;
}
.info-row .val a{text-decoration:none;color:inherit}
.info-row .val a:hover{color:var(--accent-dark)}
.info-row a.val:hover{color:var(--accent-dark)}

.form{margin-top:2.5rem;max-width:760px}
.field{margin-bottom:.85rem}
.field-2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.85rem}
.form input,.form select,.form textarea{
  width:100%;font-family:var(--ui);font-size:.8rem;letter-spacing:.01em;color:var(--ink);
  background:var(--surface);border:1px solid transparent;padding:1.15rem 1.35rem;
  border-radius:0;appearance:none;
  transition:border-color var(--t-fast) var(--ease),background var(--t-fast) var(--ease);
}
.form textarea{min-height:170px;resize:vertical;line-height:1.7}
.form input::placeholder,.form textarea::placeholder{color:var(--muted);opacity:1}
.form select{color:var(--muted)}
.form select.filled{color:var(--ink)}
.form :focus-visible{outline:none;border-color:var(--accent);background:#fff}
.select-wrap{position:relative}
.select-wrap::after{
  content:"";position:absolute;right:1.35rem;top:50%;width:7px;height:7px;
  border-right:1px solid var(--muted);border-bottom:1px solid var(--muted);
  transform:translateY(-70%) rotate(45deg);pointer-events:none;
}
.file-field{
  display:block;background:var(--surface);padding:1.15rem 1.35rem;cursor:pointer;
  font-family:var(--ui);font-size:.8rem;letter-spacing:.01em;color:var(--muted);
  transition:background var(--t-fast) var(--ease);
}
.file-field:hover{background:#efece8}
.file-field input{display:none}
/* spam honeypot — must stay reachable to bots but invisible and untabbable to people */
.form .hp{position:absolute!important;left:-9999px;width:1px;height:1px;opacity:0;pointer-events:none}
.form-note{
  font-family:var(--ui);font-size:.76rem;line-height:1.9;color:var(--muted);
  margin:.85rem 0 0;max-width:52ch;text-wrap:balance;
}
.consent{display:flex;gap:.75rem;align-items:flex-start;margin:1.75rem 0 2rem}
.consent input[type=checkbox]{
  appearance:none;-webkit-appearance:none;
  width:16px;height:16px;flex:none;margin:.28rem 0 0;padding:0;
  background:#fff;border:1px solid var(--line);border-radius:0;cursor:pointer;
  display:grid;place-content:center;
  transition:background var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease);
}
.consent input[type=checkbox]::after{
  content:"";width:9px;height:5px;
  border-left:1.5px solid #fff;border-bottom:1.5px solid #fff;
  transform:rotate(-45deg) translate(.5px,-1px);opacity:0;
  transition:opacity var(--t-fast) var(--ease);
}
.consent input[type=checkbox]:hover{border-color:var(--muted)}
.consent input[type=checkbox]:checked{background:var(--accent);border-color:var(--accent)}
.consent input[type=checkbox]:checked::after{opacity:1}
.consent input[type=checkbox]:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.consent label{cursor:pointer}
.consent label{font-family:var(--ui);font-size:.76rem;line-height:1.8;color:var(--ink-soft)}
.consent a{color:var(--ink)}

/* ---------- footer ---------- */
.site-foot{border-top:1px solid var(--line);padding-block:clamp(2.5rem,5vw,4rem) 2rem;margin-top:clamp(3rem,7vw,6rem)}
/* brand + address left, the three link groups clustered right.
   Four 1fr columns stretched the links edge-to-edge and left a hole in the middle. */
.foot-top{margin-bottom:clamp(2rem,4vw,3rem)}
.foot-grid{display:flex;align-items:flex-start;justify-content:space-between;gap:clamp(2rem,6vw,6rem);flex-wrap:wrap}
.foot-addr{
  font-style:normal;font-family:var(--ui);font-size:.72rem;color:var(--ink-soft);line-height:2;
}
.foot-links{
  display:flex;gap:clamp(2rem,4.5vw,4.5rem);
  font-family:var(--ui);font-size:.72rem;color:var(--ink-soft);line-height:2;
}
.foot-links a{display:block;text-decoration:none;white-space:nowrap}
.foot-links a:hover{color:var(--ink)}
.foot-bot{
  display:flex;justify-content:space-between;gap:1.5rem;flex-wrap:wrap;
  margin-top:2.5rem;padding-top:1.5rem;border-top:1px solid var(--line);
  font-family:var(--ui);font-size:.66rem;color:var(--muted);
}
.foot-bot a{text-decoration:none;transition:color var(--t-fast) var(--ease)}
.foot-bot a:hover{color:var(--ink)}

/* ---------- responsive ---------- */
@media (max-width:900px){
  .nav{
    display:none;position:absolute;top:100%;left:0;right:0;background:var(--ground);
    flex-direction:column;gap:0;padding:1rem var(--pad) 2rem;border-bottom:1px solid var(--line);
  }
  .nav.open{display:flex}
  .nav a{padding-block:.9rem;font-size:.85rem}
  .burger{display:inline-flex}
  .social{display:none}
  .head-in{position:relative}
  .intro-grid,.detail-head,.contact-grid{grid-template-columns:minmax(0,1fr)}
  .hero-in{min-height:0;grid-template-columns:minmax(0,1fr);gap:clamp(2rem,5vw,3rem)}
  .hero-copy{order:2}
  .hero-statement{max-width:22em}
  .hero-frame{order:1;margin-right:0}
  .hero-media{aspect-ratio:4/5;flex:none;min-height:0;width:100%}
  .hero-foot{flex-direction:column;align-items:flex-start;gap:1rem}
  .detail-side{position:static}
}
@media (max-width:620px){
  .proj-grid{grid-template-columns:minmax(0,1fr)}
  .feature-grid{grid-template-columns:minmax(0,1fr)}
  .row-2,.row-3,.row-2-1,.row-1-2,.field-2{grid-template-columns:minmax(0,1fr)}
  /* narrow cards: let the tag drop under the name instead of squeezing it */
  .proj-meta{grid-template-columns:minmax(0,1fr)}
  .proj-cat{grid-column:1;justify-self:start;text-align:left;white-space:normal;margin-top:.3rem}
  .proj-desc{margin-top:.55rem}
  /* display:contents so the three link groups become grid items alongside the
     address — a tidy 2x2 instead of the socials orphaned on their own row. */
  .foot-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:2rem 1.5rem}
  .foot-links{display:contents}
  .brand .name{font-size:1rem}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{transition-duration:0ms!important;animation-duration:0ms!important}
  .ph img{opacity:1}
}

/* Portrait source in a landscape frame: bias the crop up so the room shows,
   not the floor. */
.proj-card .ph img.tall,
.work-item .ph img.tall{object-position:50% 34%}

/* ---------- section heading: leads section 2's centred line into the photos ---------- */
.sec-head{
  text-align:center;max-width:46rem;
  margin:0 auto clamp(2.75rem,6vw,5.5rem);
}
.sec-title{
  /* same face as the hero statement — Bodoni read as a different font. TJ, 25 Aug */
  font-family:var(--serif);font-weight:400;
  font-size:clamp(1.9rem,3.9vw,3.5rem);line-height:1.1;letter-spacing:-.018em;
  margin:0;
}
.sec-sub{
  font-family:var(--ui);font-size:clamp(.85rem,.95vw,1rem);line-height:1.85;
  color:var(--muted);margin:clamp(1rem,1.6vw,1.6rem) auto 0;
  max-width:33em;text-wrap:balance;
}

/* ---------- section 2: the brand beat ----------
   Reference proportion: one large photo filling the right and running off the right
   edge and the bottom, a second only partly on screen at the left, her small L mark
   dead centre. Past halfway the photos leave and the mark becomes the line. */
.story{position:relative}
.story-track{position:relative;height:280svh}
.story-stage{
  position:sticky;top:0;height:100svh;overflow:hidden;
}
.story-shot{
  position:absolute;opacity:0;transform:translateY(3.5rem);
  transition:opacity 900ms var(--ease),transform 1100ms var(--ease);
}
.story-shot .ph{width:100%;height:100%;background:var(--surface);overflow:hidden}
.story-shot .ph img{width:100%;height:100%;object-fit:cover}
/* Widths are pure vw (the caps only bite past ~3300px) so the composition holds the
   SAME proportions on a laptop and on a large monitor. They used to be
   min(34vw,540px) / min(43vw,780px): below the px cap the photos grew with the window
   while the centred mark is sized off svh, so the gap between the mark and the right
   photo collapsed from 424px at 2560 to 38px at 1464. The vw values below are the
   measured 2560px proportions (540/2560 and 780/2560), which is the balance TJ approved.
   <!-- why: TJ 26 Aug, "I liked how it was exactly on the big screen, it needs to stay
        the same whether laptop or big screen" --> */
/* left: only partly on screen, cut by the left edge and the bottom */
.story-shot.s-a{
  left:calc(var(--pad) * -.35);top:46svh;
  width:min(21vw,700px);height:66svh;
}
/* right: the large one, cut by the right edge and the bottom */
.story-shot.s-b{
  right:0;top:9svh;
  width:min(30.5vw,1000px);height:104svh;transition-delay:140ms;
}
.story-core{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  z-index:2;display:grid;place-items:center;
  width:min(88vw,42rem);text-align:center;
}
.story-mark,.story-line{
  grid-area:1/1;justify-self:center;
  transition:opacity 800ms var(--ease),transform 1000ms var(--ease);
}
/* inline SVG now, not a raster — crisp at any size and drawable.
   main.js sets stroke-dasharray/offset on the two pen strokes from scroll progress. */
.story-mark{
  width:auto;height:clamp(84px,11svh,172px);
  color:var(--ink);overflow:visible;
  opacity:0;
}
.story-mark path{transition:none}
@media (prefers-reduced-motion:reduce){
  /* JS never runs here, so no dash is set and the mark is simply whole */
  .story-mark path{stroke-dasharray:none!important;stroke-dashoffset:0!important}
}
.story-line{
  font-family:var(--serif);font-size:clamp(1.35rem,2.02vw,2.35rem);line-height:1.4;
  text-align:center;margin:0 auto;width:100%;max-width:min(88vw,17em);
  text-wrap:balance;letter-spacing:-.006em;
  opacity:0;transform:translateY(1.25rem);
}
/* beat 1 */
.story-stage.is-in .story-shot{opacity:1;transform:none}
.story-stage.is-in .story-mark{opacity:1;transform:none}
/* beat 2 — photos and mark clear out first, the line lands after them */
.story-stage.is-two .story-shot{opacity:0;transform:translateY(-7rem)}
.story-stage.is-two .story-mark{opacity:0;transition-duration:420ms}
.story-stage.is-two .story-line{opacity:1;transform:none;transition-delay:340ms}
/* no motion: one static frame, the words win over the mark.
   The shots are absolute in the scrolling version, so this relays them out as a grid. */
.story-stage.no-motion{
  position:static;height:auto;overflow:visible;
  padding-block:clamp(4rem,10vw,8rem);
  max-width:var(--max);margin-inline:auto;padding-inline:var(--pad);
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  grid-template-areas:"a b" "core core";gap:var(--gap);
}
.story-track:has(.no-motion){height:auto}
.story-stage.no-motion .story-shot{
  position:static;width:100%;height:auto;left:auto;right:auto;top:auto;
  opacity:1;transform:none;
}
.story-stage.no-motion .story-shot .ph{aspect-ratio:3/4;height:auto}
.story-stage.no-motion .story-shot.s-a,.story-stage.no-motion .story-shot.s-b{
  position:static;width:100%;height:auto;left:auto;right:auto;top:auto;
}
.story-stage.no-motion .s-a{grid-area:a}
.story-stage.no-motion .s-b{grid-area:b;margin-top:clamp(1.5rem,6vw,3rem)}
.story-stage.no-motion .story-core{
  position:static;transform:none;grid-area:core;width:100%;
  margin-top:clamp(2.5rem,9vw,4rem);
}
.story-stage.no-motion .story-line{opacity:1;transform:none}
.story-stage.no-motion .story-mark{opacity:0}

@media (max-width:900px){
  .story-track{height:auto}
  .story-stage{
    position:static;height:auto;padding-block:clamp(4rem,14vw,7rem);
    max-width:var(--max);margin-inline:auto;padding-inline:var(--pad);
    display:grid;
    grid-template-columns:repeat(2,minmax(0,1fr));
    grid-template-areas:"a b" "core core";
    gap:clamp(1rem,4vw,2rem) var(--gap);
  }
  .work-list{grid-template-columns:minmax(0,1fr)}
  .work-item:not(.wide) .ph{aspect-ratio:16/9}
  .story-stage{overflow:visible}
  .story-shot{position:static;width:100%;height:auto;left:auto;right:auto;top:auto}
  .story-shot .ph{aspect-ratio:3/4;height:auto}
  .story-shot.s-a,.story-shot.s-b{
    position:static;width:100%;height:auto;left:auto;right:auto;top:auto;
    justify-self:stretch;
  }
  .story-shot.s-a{grid-area:a}
  .story-shot.s-b{grid-area:b;margin-top:clamp(1.5rem,6vw,3rem)}
  .story-core{
    position:static;transform:none;grid-area:core;width:100%;min-height:0;
    margin-top:clamp(2.5rem,9vw,4rem);
  }
  .story-mark{display:none}
  .story-line{opacity:1;transform:none;position:static}
}

/* ---------- about — portrait starts centre, scroll pushes it right, copy lands ----------
   --p (0..1) is written on .about-stage by main.js. Both the .no-motion block and the
   <900px block must reset position/width/left/opacity or the section collapses. */
.about{position:relative}
.about-track{position:relative;height:220svh}
.about-stage{
  --p:0;
  --w0:min(40vw,560px);
  --w1:min(30vw,450px);
  --w:calc(var(--w0) + (var(--w1) - var(--w0)) * var(--p));
  --lit:clamp(0,(var(--p) - .42) * 3.1,1);
  position:sticky;top:0;height:100svh;
  max-width:var(--max);margin-inline:auto;padding-inline:var(--pad);
}
.about-figure{
  position:absolute;margin:0;top:50%;width:var(--w);
  left:calc(var(--pad) + (100% - var(--pad) * 2 - var(--w)) * (.5 + .5 * var(--p)));
  transform:translateY(-50%);
}
.about-figure .ph{width:100%;height:clamp(380px,76svh,880px)}
.about-figure .ph img{width:100%;height:100%;object-fit:cover}

.about-copy{
  position:absolute;top:50%;left:var(--pad);
  width:min(40vw,760px);
  transform:translateY(-50%);
  translate:0 calc((1 - var(--lit)) * 1.7rem);
  opacity:var(--lit);
  pointer-events:none;
}
.about-stage.is-lit .about-copy{pointer-events:auto}
.about-statement{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(1.12rem,1.6vw,1.72rem);line-height:1.52;letter-spacing:-.006em;
  margin:0 0 clamp(1.5rem,2.5vw,2.4rem);
  /* even lines, no stub last line. Phrases that must never split are glued with
     &nbsp; in build.py — see the About note in handoff/laur.md before editing copy. */
  text-wrap:balance;
}
.about-note{
  font-family:var(--ui);font-weight:400;
  font-size:clamp(.8rem,.92vw,.92rem);line-height:2;letter-spacing:.01em;
  color:var(--ink-soft);
  max-width:50ch;margin:0 0 1.35em;
  text-wrap:pretty;
}
.about-sign{
  font-family:var(--ui);font-size:.62rem;font-weight:500;letter-spacing:.3em;
  text-transform:uppercase;color:var(--muted);white-space:nowrap;
  margin:clamp(1.7rem,3vw,2.6rem) 0 0;
}

/* reduced motion — one static two-column block, nothing moves */
.about-track:has(.no-motion){height:auto}
.about-stage.no-motion{
  position:static;height:auto;display:grid;align-items:center;
  grid-template-columns:minmax(0,1fr) minmax(0,.85fr);gap:clamp(2rem,5vw,5rem);
  padding-block:clamp(4rem,9vw,8.5rem);
}
.about-stage.no-motion .about-copy,
.about-stage.no-motion .about-figure{
  position:static;width:100%;left:auto;top:auto;
  transform:none;translate:none;opacity:1;pointer-events:auto;
}
.about-stage.no-motion .about-figure{order:2}
.about-stage.no-motion .about-figure .ph{height:auto;aspect-ratio:3/4}

@media (max-width:900px){
  .about-track{height:auto}
  .about-stage{
    position:static;height:auto;display:grid;grid-template-columns:minmax(0,1fr);
    gap:clamp(1.75rem,6vw,3rem);padding-block:clamp(4rem,9vw,8.5rem);
  }
  .about-copy,.about-figure{
    position:static;width:100%;left:auto;top:auto;
    transform:none;translate:none;opacity:1;pointer-events:auto;
  }
  .about-figure .ph{height:auto;aspect-ratio:3/4}
  /* the signature is nowrap on desktop; let it break rather than overflow on a phone */
  .about-sign{white-space:normal}
}

/* ---------- about page ---------- */
.wide-plate{aspect-ratio:16/9}
.wide-plate img{width:100%;height:100%;object-fit:cover}
@media (max-width:900px){ .wide-plate{aspect-ratio:4/3} }

/* ---------- page intro ----------
   The page eases in as the loading screen lifts, instead of simply appearing.
   Pure CSS, no JS: the loader ends at 1.9s (out starts 1.45s), so the intro
   starts at 1.55s and is revealed underneath the fading overlay — one continuous
   move. On every page after the first (html.seen, no loader) it starts at once.
   NOTE: the generic first-block rule fades ONLY. No transform — a transformed
   ancestor breaks `position:sticky`, and the project detail pages have a sticky
   left column. The rise is applied to the hero's own children, which have none. */
:root{--intro:1.55s}
.seen{--intro:.05s}
@keyframes pg-fade{from{opacity:0}to{opacity:1}}
@keyframes pg-rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
/* the header fades with the page — fade only, never a transform: it is sticky */
.site-head{animation:pg-fade .9s var(--ease) var(--intro) both}
main > *:first-child:not(.hero){animation:pg-fade .9s var(--ease) var(--intro) both}
.hero .hero-copy{animation:pg-rise 1s var(--ease) var(--intro) both}
.hero .hero-frame{animation:pg-rise 1.1s var(--ease) calc(var(--intro) + .1s) both}
.hero .hero-foot{animation:pg-fade .9s var(--ease) calc(var(--intro) + .3s) both}

/* ---------- reveal on scroll ----------
   A small lift as a block first comes into view, once, then the classes are
   removed on animationend so the element goes back to its normal styles —
   that matters for .work-item / .proj-card, whose hover fade would otherwise
   be overridden by the animation's forwards fill.
   Hidden state is gated on html.js, and the inline head script drops .js after
   3s if main.js never reported in, so a script failure cannot hide the page. */
.js .rv{opacity:0}
.js .rv.in{animation:pg-rise .8s var(--ease) both}
@media (prefers-reduced-motion:reduce){
  :root{--intro:0s}
  .site-head,
  main > *:first-child:not(.hero),
  .hero .hero-copy,.hero .hero-frame,.hero .hero-foot{animation:none}
  .js .rv,.js .rv.in{opacity:1;animation:none}
}

/* About page: the tall portrait sits alone between the story and the CTA.
   It replaced the "How I work" block, which was deleted because every claim in it
   was invented. Held until Laura sends her five phases. */
.about-plate{max-width:min(46vw,620px);margin-inline:auto}
.about-plate .ph{aspect-ratio:3/4}
.about-plate .ph img{width:100%;height:100%;object-fit:cover}
@media (max-width:900px){.about-plate{max-width:none}}
