@font-face{font-family:'JetBrains Mono';src:url('f/jbm-400.woff2') format('woff2');font-weight:400 500;font-display:block}
/* Arts by Tadeo - locked direction, 2026-08-23
   Display: Tanker · Body: Erode · Utility: JetBrains Mono
   Material: Gallery Daylight · Reflections: reflections.css   */
@font-face{font-family:'Tanker';src:url('f/Tanker-Regular.woff2') format('woff2');font-weight:400;font-display:block}
@font-face{font-family:'Erode';src:url('f/Erode-Variable.woff2') format('woff2');font-weight:100 900;font-display:swap}

:root{
  --paper:#FBFBFB; --ink:#0F0F0F; --sub:#5E5E5E; --line:#E7E7E7; --wash:#F4F4F4;
  --display:'Tanker',Impact,sans-serif;
  --body:'Erode',Georgia,serif;
  --mono:'JetBrains Mono',ui-monospace,Menlo,monospace;
  --g:clamp(18px,4vw,64px);
  --rfx-angle:104deg;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--paper);color:var(--ink);font-family:var(--body);
  font-size:16.5px;line-height:1.68;-webkit-font-smoothing:antialiased}
img,video{display:block;max-width:100%}
a{color:inherit}
h1,h2,h3{font-family:var(--display);font-weight:400;margin:0;letter-spacing:-.015em;line-height:.94}
.wrap{padding-inline:var(--g)}

/* ---------- enquire ---------- */
.enq-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:clamp(30px,6vw,88px);
  padding:clamp(38px,7vh,80px) 0 clamp(54px,9vh,104px);align-items:start}
.enq-side{border-left:1px solid var(--line);padding-left:clamp(20px,3vw,42px)}
.enq-side h2{font-size:22px;margin:0 0 10px}
.enq-side p{color:var(--sub);font-size:14.5px;line-height:1.66;margin:0 0 22px;max-width:38ch}
.enq-side dl{margin:0;border-top:1px solid var(--line)}
.enq-side dl div{display:flex;justify-content:space-between;gap:14px;padding:10px 0;border-bottom:1px solid var(--line)}
.enq-side dt{font-family:var(--mono);font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;color:var(--sub)}
.enq-side dd{margin:0;font-family:var(--mono);font-size:11px}
.note{font-size:12.5px;color:var(--sub);margin-top:16px;max-width:44ch;line-height:1.6}

footer{border-top:1px solid var(--line);padding:28px var(--g) 48px;display:flex;justify-content:space-between;
  gap:20px;flex-wrap:wrap;align-items:baseline}
footer p{margin:0;color:var(--sub);font-size:12.5px}

.rv{opacity:0;transform:translateY(14px);transition:opacity .8s ease,transform .8s cubic-bezier(.2,.7,.3,1)}
.rv.in{opacity:1;transform:none}
:focus-visible{outline:2px solid var(--ink);outline-offset:3px}

@media (max-width:900px){
  .enq-grid{grid-template-columns:1fr}
  .enq-side{border-left:0;border-top:1px solid var(--line);padding-left:0;padding-top:28px}
}
@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
  .rv{opacity:1;transform:none}
}

/* ===========================================================================
   MOTION - line-by-line reveal
   Native scroll-driven animation where supported (Chrome/Edge 115+, FF 132+,
   Safari 18+); IntersectionObserver + .in class everywhere else. Only
   transform, opacity and filter are animated, so it stays on the compositor.
   =========================================================================== */
[data-lines] .ln{display:block;overflow:hidden}
[data-lines] .ln-i{display:block;will-change:transform,opacity}

/* base (pre-reveal) state, only once JS has split the text */
[data-lines].split .ln-i{transform:translateY(102%) rotate(.35deg);opacity:0;filter:blur(4px)}

@keyframes lineUp{
  from{transform:translateY(102%) rotate(.35deg);opacity:0;filter:blur(4px)}
  60% {opacity:1}
  to  {transform:none;opacity:1;filter:blur(0)}
}

/* --- native scroll-driven: each line animates as it enters the viewport --- */
@supports (animation-timeline: view()){
  [data-lines].split .ln-i{
    animation:lineUp linear both;
    animation-timeline:view();
    animation-range:entry 4% entry 34%;
  }
}
/* --- fallback: stagger by line index --- */
@supports not (animation-timeline: view()){
  [data-lines].split .ln-i{
    transition:transform .82s cubic-bezier(.22,.75,.24,1),
               opacity .6s ease, filter .7s ease;
    transition-delay:calc(var(--i) * 62ms);
  }
  [data-lines].split .ln.in .ln-i{transform:none;opacity:1;filter:blur(0)}
}

@media (prefers-reduced-motion:reduce){
  [data-lines].split .ln-i{transform:none!important;opacity:1!important;filter:none!important;animation:none!important}
}


/* ---------------- mast2: the branded subpage masthead (2026-08-24) ----------------
   The landing's language, miniaturized: the wordmark plays the reverse
   letter arrival on load; the ACTIVE page is marked by an ink shard (a
   different fragment on every page - the never-same-shape law); other links
   grow the 〔 〕 caption brackets on hover; the divider is a crack line,
   its path unique per page. */
html{scrollbar-gutter:stable}
.mast2{display:flex;align-items:center;justify-content:space-between;
  padding:14px var(--g) 12px;position:sticky;top:0;z-index:950;
  background:var(--paper)}
.mast2 .crackline{position:absolute;left:0;right:0;bottom:-12px;height:12px}
.mast2 .mk{font-family:var(--display);font-size:21px;color:var(--ink);
  text-decoration:none;overflow:hidden;display:inline-block;line-height:1.05}
.mast2 .mk b{display:inline-block;font-weight:400;
  animation:mkUp .34s cubic-bezier(.2,.7,.2,1) both;
  animation-delay:calc(.26s + var(--i) * 26ms)}
@keyframes mkUp{from{transform:translateY(130%)}to{transform:translateY(0)}}
.mast2 nav{display:flex;gap:clamp(2px,0.8vw,10px);align-items:center;
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase}
/* every item carries IDENTICAL box metrics whether plain, hovered or shard -
   becoming the shard is a paint-only change, so nothing ever shifts */
/* FIXED-WIDTH boxes: identical for every item in every state - even a font
   swap cannot move them. Labels center inside. */
/* the box lock covers EVERY nav child - including a just-un-sharded bare
   span (the click handler strips classes; without this it collapsed to text
   width and jumped ~30px in the dying page's last frames) */
.mast2 nav>*{color:var(--ink);text-decoration:none;position:relative;
  width:92px;text-align:center;padding:7px 0 8px;display:inline-block}
.mast2 nav a:not(.on)::before{content:"〔";position:absolute;left:2px;top:7px;opacity:0;
  transform:translateX(4px);transition:opacity .25s ease,transform .25s ease;color:var(--sub)}
.mast2 nav a:not(.on)::after{content:"〕";position:absolute;right:2px;top:7px;opacity:0;
  transform:translateX(-4px);transition:opacity .25s ease,transform .25s ease;color:var(--sub)}
.mast2 nav a:not(.on):hover::before,.mast2 nav a:not(.on):hover::after{opacity:1;transform:none}
.mast2 nav .on{background:var(--ink);color:var(--paper);cursor:default}
.mast2 nav .on.sh-work{clip-path:polygon(3% 8%, 34% 0, 68% 6%, 100% 2%, 97% 55%, 100% 92%, 62% 100%, 26% 94%, 0 100%, 2% 46%)}
.mast2 nav .on.sh-story{clip-path:polygon(0 14%, 28% 4%, 62% 0, 98% 8%, 100% 60%, 94% 100%, 58% 94%, 30% 100%, 3% 92%, 1% 40%)}
.mast2 nav .on.sh-contact{clip-path:polygon(2% 0, 40% 8%, 74% 0, 100% 12%, 96% 58%, 100% 96%, 64% 92%, 34% 100%, 0 94%, 3% 50%)}
.crackline{display:block;width:100%;height:12px}
.crackline path+polyline,.crackline polyline{stroke:var(--ink);stroke-opacity:.2}
.crackline polyline{fill:none;stroke:var(--ink);stroke-opacity:.16;stroke-width:1;
  vector-effect:non-scaling-stroke}
@media (prefers-reduced-motion:reduce){
  .mast2 .mk b{animation:none!important;transform:none!important}
  .mast2 nav a::before,.mast2 nav a::after{transition:none}
}
@media (max-width:560px){
  .mast2 .mk{font-size:15px;white-space:nowrap}
  .mast2 nav{gap:2px;font-size:9.5px}
  .mast2 nav>*{width:72px}
  .mast2 nav a:not(.on)::before,.mast2 nav a:not(.on)::after{display:none}
}

/* ---- seamless navigation (2026-08-24) ---- */
/* cross-document view transitions: pages crossfade instead of hard-reloading,
   and the masthead morphs in place (feels persistent). No-support browsers
   just navigate normally. */
@view-transition{navigation:auto}
@media (prefers-reduced-motion:reduce){
  @view-transition{navigation:none}
}
/* the mini wordmark arrival plays ONCE per session - the .mk-seen class is
   set from sessionStorage before first paint on subsequent pages */
.mk-seen .mast2 .mk b{animation:none}
/* a prerendered document paints and animates before the visitor arrives:
   hold the arrival at frame zero until activation removes .pre */
html.pre .mast2 .mk b{animation:none}
/* each nav item morphs to its counterpart across pages: the clicked link
   becomes a shard at click time (JS below) and the browser animates it into
   the new page's marker */

/* ---- the little blank beat on subpage arrival (Tim 2026-08-24): paper
   covers the first fractions of a second, then lifts and the page's
   animations begin - the landing curtain, miniaturized ---- */
/* the curtain covers everything EXCEPT the nav bar: mast + crack ride above
   it, so the bar reads persistent through the blank beat */
.shutter2{position:fixed;inset:0;z-index:900;background:var(--paper);
  pointer-events:none;opacity:1;transition:opacity .22s ease}
html.pg-ready .shutter2{opacity:0}
/* gallery: the crack svg overlaps the ink hero - white cap above the stroke,
   ink visible below it: the crack IS the seam */

/* ---- mobile parity (2026-08-31) ----------------------------------------
   Phone-only. Every rule is inside a max-width query or resolves to a no-op
   off-phone, and the block is verified by
   ~/.agents/skills/mobile-parity/scripts/gate.sh - computed style + geometry
   identical at 1280/1512/1920/2560, every element, before and after.

   NOT fixed here, deliberately, because both would be visible design changes
   rather than invisible hit-area growth - they need Tim's call:
     - .mast2 nav>* is 66x31 on a phone. Apple asks 44 tall. It already has
       padding:7px 0 8px, so "adding padding" silently REPLACES that and makes
       the target smaller; and growing it inflates the painted .on shard, which
       is the black pill in the mast. 66x31 clears the WCAG 2.2 AA floor (24px).
     - .mast2 .mk (the wordmark, 80x16) sits next to the nav; growing its box
       upward would overlap it. */
@media (max-width:760px){
  /* Trailing links measured 19px tall - UNDER the WCAG 2.2 AA 24px floor.
     Grow the hit area UPWARD only: padding-top with an equal negative
     margin-top leaves the text and its border-bottom underline exactly where
     they were, and .out has 52px+ of clear space above it to grow into. */
  .out a{display:inline-block;padding-top:25px;margin-top:-25px}
  footer a{display:inline-block;padding-top:25px;margin-top:-25px}

  /* The home indicator covers the last ~34px of the screen. env() is 0px on
     every desktop browser, so this is structurally a no-op off-phone. */
  footer{padding-bottom:calc(48px + env(safe-area-inset-bottom, 0px))}

  /* --- masthead buttons, 2026-08-31 ------------------------------------
     The 2026-08-30 pass left these at 66x31 because growing them inflates
     the painted .on shard, and that is a visible change. Tim asked for the
     buttons to be adjusted, so a visible phone-side change is now the ask:
     the nav items become real 44px buttons and the shard grows with them.
     flex centering rather than padding - the base rule is `padding:7px 0 8px`,
     and `padding-block` REPLACES that shorthand rather than adding to it,
     which is how a "bigger" target ends up 1px smaller. */
  .mast2 nav>*{display:flex;align-items:center;justify-content:center;
    min-height:44px;padding:0}

  /* The wordmark measured 79.7x15.8 - under the WCAG 2.2 AA 24px floor, and
     with no equivalent home control elsewhere on the page, so not exempt.
     It cannot simply take padding: .mk uses overflow:hidden to mask the
     per-letter mkUp reveal, and a taller clip box shows the letters sliding
     in from below. So swap the mask to mask-image, which is PAINT ONLY -
     hit-testing ignores a mask, unlike clip-path or overflow - and the
     visible band stays exactly where it was while the anchor becomes 44px.
     If a browser ignores mask-image the only cost is seeing the letters
     arrive once per session; the link still works and still measures 44. */
  .mast2 .mk{overflow:visible;padding:15px 0;margin:-15px 0;
    -webkit-mask-image:linear-gradient(#000,#000);-webkit-mask-repeat:no-repeat;
    -webkit-mask-size:100% calc(100% - 30px);-webkit-mask-position:0 15px;
    mask-image:linear-gradient(#000,#000);mask-repeat:no-repeat;
    mask-size:100% calc(100% - 30px);mask-position:0 15px}
}
