/* ============================================================
 * DEFAULT ART DIRECTION — "bare"   (scoped html:not([data-variant]))
 *
 * Emptiness. No cards, no glass. Per-section silhouettes of shade instead of
 * containers, a knocked-out monument H1 whose aperture opens as it leaves, and
 * a ledger whose micro-labels hold in the margin while their rows scroll.
 * Baseline markup + one wrapper (.ledger) that every variant simply ignores.
 *
 * ------------------------------------------------------------
 * PAGE RHYTHM (why the min-heights are what they are)
 * ------------------------------------------------------------
 * Owner requirement: the address must clear the FIRST viewport. #hero is
 * 72svh (>=768; 82svh below) — inherited from tokens.css, NOT overridden here —
 * so #contact has to place "Get in touch" + labs@reko.studio inside whatever is
 * left. Three things buy that room, in order of how much they cost the design:
 *   1. the scroll hint leaves the flow (it was 96px of hero it did not need),
 *   2. the contact block drops its card padding and trims the section padding,
 *   3. the section itself stays compact (36svh) and stays CENTRED — so the band
 *      silhouette keeps sitting on the type it backs, no start-alignment hack.
 * Measured at 1056x729: hero 529, contact 262, address bottom 712, i.e. 17px of
 * clearance under the address in viewport one.
 *   hero 72 + contact 36 + reko 165 + footer (~78px) => 2.84 viewports measured
 *   (2.8+ across viewport heights), which is the scroll the page needs. The
 *   height budget lives in #reko because #reko is the section worth scrolling:
 *   four labelled groups, sticky margin labels, per-row reveals. Anything taken
 *   out of #reko has to come back out of the first viewport, so do not trade
 *   them against each other without re-measuring both.
 *
 * ------------------------------------------------------------
 * CONTRAST CONTRACT (recomputed for the bare default — no glass tint anywhere)
 * ------------------------------------------------------------
 * There is no --glass-tint-a under text in this direction, so the backing is
 * (a) the fluid, (b) the page scrim, (c) the per-section shade. Worst case =
 * the fluid pinned at the engine's soft-knee ceiling [0.400,0.345,0.440] sRGB,
 * which is L = 0.110 (fluid.js FLUID.CEILING; raising it lowers every ratio
 * below, so re-run this table if it ever moves).
 *
 * The OLD bare scrim (.38 centre pool -> 0 at 68%, vignette starting at 42%)
 * left a ring at ~20-30% radius where the two radials both fell to ~0: over a
 * ceiling-bright fluid that ring measured secondary 3.6:1, tertiary 3.6:1,
 * accent 4.0:1, H1 4.1:1 — all failing. Fixed by giving BOTH radials a floor
 * (the centre pool now lands on .08 instead of 0, the vignette starts at .16)
 * so the scrim's minimum effective alpha anywhere in the viewport is ~0.34.
 * The fluid itself is untouched — the ceiling is not dimmed.
 *
 *   backing L values (worst-case fluid underneath):
 *     A  fluid alone ................................ 0.110
 *     B  fluid + scrim at its viewport minimum ...... 0.050
 *     C  B + #contact band  (rgba(2,3,6,.40)) ....... 0.021
 *     D  B + #reko column   (rgba(2,3,6,.36)) ....... 0.023
 *
 *   token           L      over B    over C    over D
 *   primary  #EDF1F7 .876   9.3:1    13.0:1    12.7:1
 *   secondary#B3C0D1 .519   5.7:1     8.0:1     7.8:1
 *   tertiary #B6C2D2 .532   5.8:1     8.2:1     8.0:1
 *   accent   #6FD9F0 .593   6.4:1     9.1:1     8.8:1
 *
 *   H1 knockout (background-clip:text, white at the gradient's dimmest stop):
 *     at rest      (.76 alpha) over B .............. 6.1:1
 *     full aperture(.64 alpha) over B .............. 4.9:1
 *   Email knockout hover: white plate 21:1 vs #000; the screen-blended letters
 *   read the backdrop through the plate, worst case 6.6:1.
 *
 *   Hero text has no shade of its own (the direction gives the hero none), so
 *   it sits on B — it clears 4.5:1 on the scrim floor alone, and carries
 *   --bare-shadow on top for edge definition over a moving fluid.
 * ========================================================== */

@property --knock-open{ syntax:"<number>"; inherits:true; initial-value:0; }

html:not([data-variant]){
  --knock-open:0;
  --fs-h1:clamp(2.3rem, 5.6vw + .35rem, 5.5rem);
  --h1-track:-.03em; --h1-lh:1.03; --h1-measure:15ch; --h1-wrap:balance;
  --gap-eyebrow:22px; --gap-h1:26px;
  /* --hero-minh deliberately NOT set: tokens.css owns it (82svh / 72svh). */
  --contact-minh:36svh; --reko-minh:165svh;
  --group-gap:44px;
  /* ONE centred column for the whole page: hero, contact and reko share this
     width AND this inset, so every text block starts at the same x and the
     three sections sit on one axis. */
  --bare-col:min(100%, 820px); --bare-inset:clamp(28px, 4vw, 40px);
  --pool-band:.40; --pool-col:.36;
  --glass-tint-a:0;
  /* the ledger's margin column */
  --ledger-label:108px; --ledger-gap:22px;
  /* the bar now owns the notch strip (base.css), so the sticky label has to
     clear the same strip or it parks under the status bar */
  --ledger-top:calc(var(--topbar-h) + env(safe-area-inset-top, 0px) + 20px);
}
/* MOBILE EXCEPTION to the budget above. 165svh is a DESKTOP figure: it buys
   scroll for a ledger whose rows are single lines. On a phone the folded rows
   make the ledger ~1180px of real content regardless of viewport height, while
   165svh keeps growing with the screen — measured dead column below the last
   row: 101px at 390, 187px at 414, 246px at 430 and 736px at 768x1024. Letting
   content drive removes all of it and still leaves 2.1-3.2 viewports of page,
   because the ledger alone is ~1.3-1.9 viewports on these screens. */
@media (max-width:900px){
  html:not([data-variant]){ --reko-minh:auto; }
}
@media (min-width:768px){
  html:not([data-variant]){ --group-gap:56px; }
}
@media (min-width:1024px){
  html:not([data-variant]){ --group-gap:64px; --ledger-label:124px; --ledger-gap:28px; }
}
@media (min-width:1440px){
  html:not([data-variant]){ --group-gap:72px; }
}

/* --- no containers anywhere ---------------------------------------------- */
html:not([data-variant]) .glass{
  background:none; box-shadow:none;
  -webkit-backdrop-filter:none; backdrop-filter:none;
}
html:not([data-variant]) .glass::before,
html:not([data-variant]) .glass::after,
html:not([data-variant]) .noise{ display:none; }
/* (a) text inset from the shade edge — background and type never start at the
   same x/y. (b) same width + same inset in all three sections, so the H1, the
   address and the ledger rows share one left edge on one centred axis. */
html:not([data-variant]) .card-hero{ padding-inline:var(--bare-inset); max-width:var(--bare-col); }
html:not([data-variant]) .card-slim{ padding:var(--bare-inset); max-width:var(--bare-col); }
/* 820 - 2x40 = 740 of ledger, comfortably over the 620 the sticky labels want,
   and still narrow enough that a right-aligned tag lands close to its row. */
html:not([data-variant]) #reko .card-slim{ max-width:var(--bare-col); }

/* The scroll hint is a nudge for a visitor who cannot see that the page
   continues. In this direction the address is already in the first viewport,
   so the nudge has nothing left to say — and its 60px rule was both a stray
   mark above "Get in touch" and 96px of hero height that pushed the address
   towards the fold. The variants (100svh hero, nothing below it) keep it. */
html:not([data-variant]) #hero{ position:relative; }
html:not([data-variant]) .scroll-hint{ display:none; }
/* no card, so no card padding: the block padding only pushed the address down.
   The section's own padding is trimmed for the same reason — every pixel here
   is a pixel of clearance under the address in the first viewport. */
html:not([data-variant]) #contact .card-slim{ padding-block:0; }
html:not([data-variant]) #contact{ padding-block:56px 64px; }

/* --- per-section shade silhouettes: hero none, contact band, reko column --- */
html:not([data-variant]) #contact,
html:not([data-variant]) #reko{ position:relative; }
html:not([data-variant]) #contact::before{
  content:""; position:absolute; left:0; right:0; top:50%;
  height:min(88%, 620px); transform:translateY(-50%); pointer-events:none;
  /* (a) the band is taller and wider than the type it sits behind */
  background:linear-gradient(180deg,
    rgba(2,3,6,0) 0%, rgba(2,3,6,var(--pool-band)) 24%,
    rgba(2,3,6,var(--pool-band)) 76%, rgba(2,3,6,0) 100%);
}
/* 1080px wide with 6% ramps => a 950px flat core, wider than the 820px card,
   so no row ever sits on the ramp where the shade is only partly there. */
html:not([data-variant]) #reko::before{
  content:""; position:absolute; top:0; bottom:0; left:50%;
  width:min(100%, 1080px); transform:translateX(-50%); pointer-events:none;
  background:linear-gradient(90deg,
    rgba(2,3,6,0) 0%, rgba(2,3,6,var(--pool-col)) 6%,
    rgba(2,3,6,var(--pool-col)) 94%, rgba(2,3,6,0) 100%);
}
/* The reko column continues behind the footer: #reko::before ends at the
   section box, and without this the footer sits on bare fluid — a visible
   seam right where the page should settle. Same width, same gradient, so
   the two halves read as one surface down to the document edge. */
html:not([data-variant]) .site-footer{ position:relative; }
html:not([data-variant]) .site-footer::before{
  content:""; position:absolute; top:0; bottom:0; left:50%; z-index:-1;
  width:min(100%, 1080px); transform:translateX(-50%); pointer-events:none;
  background:linear-gradient(90deg,
    rgba(2,3,6,0) 0%, rgba(2,3,6,var(--pool-col)) 6%,
    rgba(2,3,6,var(--pool-col)) 94%, rgba(2,3,6,0) 100%);
}

/* --- the contact band: ONE hairline, under the block, the only rule on the
   page. There is deliberately NOTHING above "Get in touch".
   This pseudo-element is also glass.css's rim (.glass::after), which the bare
   `display:none` above switches off — but re-declaring `display:block` here
   revives the WHOLE rim declaration, and its `inset:0` + `padding:1px` pinned
   this hairline to the TOP of the card, i.e. straight above the heading. Every
   one of those inherited properties has to be unwound explicitly. */
html:not([data-variant]) .card-contact{ position:relative; }
html:not([data-variant]) .card-contact::after{
  content:""; display:block; position:absolute; pointer-events:none;
  top:auto; left:0; right:0; bottom:-22px;
  width:auto; height:1px; padding:0; border-radius:0;
  -webkit-mask:none; mask:none;
  transform-origin:0 50%;
  background:linear-gradient(90deg,
    rgba(255,255,255,.16), rgba(255,255,255,.04) 58%, rgba(255,255,255,0));
}

/* --- monument H1: knocked out of a vertical wash, aperture on --knock-open - */
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  @media (prefers-contrast: no-preference) and (prefers-reduced-transparency: no-preference){
    html:not([data-variant]) h1{
      color:transparent; -webkit-text-fill-color:transparent;
      background-image:linear-gradient(170deg,
        rgb(237 241 247 / calc(.96 - .06 * var(--knock-open))) 0%,
        rgb(237 241 247 / calc(.88 - .10 * var(--knock-open))) 44%,
        rgb(237 241 247 / calc(.76 - .12 * var(--knock-open))) 100%);
      -webkit-background-clip:text; background-clip:text;
      text-shadow:none;
    }
  }
}
/* the hero is the one block with no shade of its own — the scrim carries the
   ratio, the shadow carries the edge against a moving fluid */
html:not([data-variant]) .card-hero .eyebrow,
html:not([data-variant]) .card-hero .intro{ text-shadow:var(--bare-shadow); }

/* --- the email is the loudest thing on the page -------------------------- */
html:not([data-variant]) .rows .value{
  font-size:clamp(1.5rem, 5.2vw, 3.25rem);
  font-weight:600; letter-spacing:-.032em; line-height:1.04;
}
html:not([data-variant]) .rows .vtext{
  background-size:100% 2px;
  background-image:linear-gradient(rgba(255,255,255,.14),rgba(255,255,255,.14));
}
html:not([data-variant]) .rows .row-grid{ min-height:auto; }
/* (c) the pill hugs the ADDRESS, nothing else: 10px/16px of inset clears the
   ascenders and the @ that dips under the baseline at line-height 1.04, and the
   matching negative margin keeps it out of the flow, so hover only paints —
   it never re-lays the row out. The single max-content track is what makes it
   fit-content: glass.css gives .knock a --grid-lead track at >=768 for the
   two-cell rows this row does not have, and that track (plus justify-self:
   stretch) is what used to smear the white plate across the whole column. */
html:not([data-variant]) .knock{
  grid-template-columns:minmax(0,max-content);
  width:fit-content;
  padding:10px 16px; margin:-10px -16px;
  border-radius:var(--r-hit);
  justify-self:start;
}

/* --- the ledger: micro-labels hold in the margin -------------------------
   .ledger is an inline-size container, so the switch is driven by the space
   the rows actually have, not by the viewport. Below 620px of container the
   labels stay stacked above their rows exactly as before. No container-query
   support (or no CSS at all): same stacked fallback, everything visible. */
html:not([data-variant]) .ledger{ text-shadow:var(--bare-shadow); }
@supports (container-type:inline-size){
  html:not([data-variant]) .ledger{ container-type:inline-size; container-name:ledger; }
}
/* the trailing arrow tracks the name instead of flying to the ledger's edge,
   so the hover pill stays the size of the link it belongs to */
html:not([data-variant]) .ledger .quiet-link{ max-width:420px; }

@container ledger (min-width:620px){
  html:not([data-variant]) .ledger .group{
    display:flex; align-items:flex-start; gap:var(--ledger-gap);
  }
  /* align-items:flex-start is what makes this sticky work: the label keeps its
     own height while its containing block stays the full group, so it holds
     from the group's first row to its last and then releases. */
  html:not([data-variant]) .ledger .microlabel{
    flex:0 0 var(--ledger-label);
    margin:0; padding-block:13px 0;
    position:sticky; top:var(--ledger-top);
  }
  html:not([data-variant]) .ledger .group > :not(.microlabel){
    flex:1 1 auto; min-width:0;
  }
  /* the unlabelled group keeps the rows column's left edge */
  html:not([data-variant]) .ledger .group-plain{
    padding-inline-start:calc(var(--ledger-label) + var(--ledger-gap));
  }
}

html:not([data-variant]) .scrim{
  background:
    radial-gradient(ellipse 76% 58% at 50% 44%,
      rgba(5,7,12,.40) 0%, rgba(5,7,12,.16) 64%, rgba(5,7,12,.08) 100%),
    radial-gradient(ellipse 120% 90% at 50% 50%,
      rgba(2,3,6,.16) 0%, rgba(2,3,6,.22) 44%, rgba(2,3,6,.82) 100%);
}

/* --- motion tiers: view() rows, scroll() aperture, IO fallback ------------ */
@keyframes bare-row-in{ from{ opacity:0; transform:translateY(10px); } to{ opacity:1; transform:none; } }
@keyframes bare-rule-draw{ 0%{ transform:scaleX(0); } 30%{ transform:scaleX(1); } 100%{ transform:scaleX(1); } }
@keyframes bare-hero-leave{ from{ --knock-open:0; transform:translateY(0); } to{ --knock-open:1; transform:translateY(-26px); } }
@keyframes bare-year-settle{ from{ opacity:0; transform:translateX(-5px); } to{ opacity:1; transform:none; } }

@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference){
    html:not([data-variant]) .card-contact::after{
      animation:bare-rule-draw linear both;
      animation-timeline:view(); animation-range:cover 2% cover 34%;
    }
    html:not([data-variant]) #reko .row-grid,
    html:not([data-variant]) #reko .quiet-list > li{
      animation:bare-row-in linear both;
      animation-timeline:view(); animation-range:entry 12% entry 92%;
    }
    /* the year column lands a beat after its row — opacity + 5px, no layout */
    html:not([data-variant]) #reko .exp-year{
      animation:bare-year-settle linear both;
      animation-timeline:view(); animation-range:entry 20% entry 76%;
    }
    /* NOT the groups: a transform on a group would drag its sticky label with
       it, and the rows already carry the reveal. */
    html:not([data-variant]) #reko .group,
    html:not([data-variant]) #reko .card-slim{ animation:none; opacity:1; }
  }
}
@supports (animation-timeline:scroll()){
  @media (prefers-reduced-motion:no-preference){
    html:not([data-variant]) .hero-inner{
      animation:bare-hero-leave linear both;
      animation-timeline:scroll(root block); animation-range:0 72svh;
    }
  }
}
@media (prefers-reduced-motion:reduce){
  html:not([data-variant]) h1{
    color:var(--text-primary); -webkit-text-fill-color:var(--text-primary);
    background-image:none; text-shadow:var(--bare-shadow);
  }
}
