/* =========================================================
   \ wire. — redesign v2
   warm paper · Hanken Grotesk · scroll-scrubbed wire
   ========================================================= */

:root {
  --paper:   #E5DDD0;   /* matched to the wire video's cream */
  --paper-2: #EEE8DC;   /* cards / insets, a touch lighter */
  --ink:     #14130F;
  --muted:   #746D60;
  --faint:   #a99f8c;
  --line:    #D3C8B6;
  --line-2:  #C5B9A3;
  --accent:  #2e40c0;   /* royal blue — matched to the wire */
  --wire:    #4d72c0;
  --live:    #2f9e6f;
  --wa:      #25c66a;

  --serif: 'Hanken Grotesk', Arial, sans-serif;
  --mono:  'Hanken Grotesk', Arial, sans-serif;

  --pad: clamp(20px, 5.5vw, 96px);
  --lane: clamp(220px, 22vw, 340px);

  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --dur-fast: 150ms;
  --dur: 240ms;
  --dur-rev: 620ms;
}

* { box-sizing: border-box; }
/* no scroll-behavior:smooth here on purpose — the browser silently downgrades
   it to an instant jump when the OS has reduce-motion on; script.js drives
   scrolling itself (smoothScrollTo) so it isn't subject to that override */
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--mono);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
a { color: inherit; text-decoration: none; }
::selection { background: var(--accent); color: #fff; }

/* ---------- custom scrollbar (page + modal + any inner overflow) ----------
   Default browser scrollbars break the paper aesthetic — big, chrome-grey, and
   loud on the right edge. This uses ONLY ::-webkit-scrollbar-* selectors on
   purpose: setting scrollbar-color or scrollbar-width (the modern spec) makes
   Chrome silently opt into the standardised scrollbar API, which then IGNORES
   every ::-webkit-scrollbar-* rule below and keeps native up/down arrow
   buttons that can't be removed via CSS. Sticking to the legacy WebKit
   pseudos gives us full control on Chromium/Safari/Edge (~95% of visitors).
   Firefox users get the default scrollbar — acceptable trade-off. */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--line-2);
  border-radius: 999px;
  border: 2px solid var(--paper);
  transition: background 200ms var(--ease-out);
}
::-webkit-scrollbar-thumb:hover { background: var(--muted); }
/* kill the up/down arrow buttons — every variant, so no start/end/single/
   double button shows in any browser or DPI mode */
::-webkit-scrollbar-button,
::-webkit-scrollbar-button:vertical:start,
::-webkit-scrollbar-button:vertical:end,
::-webkit-scrollbar-button:horizontal:start,
::-webkit-scrollbar-button:horizontal:end {
  display: none;
  width: 0; height: 0;
  background: transparent;
}
::-webkit-scrollbar-corner { background: transparent; }
/* the modal has its own paper background, so its scrollbar thumb border needs
   to match that (--paper, same as the html rule) — nothing to override here */
/* .sheet inherits the global ::-webkit-scrollbar-* rules above; don't set
   scrollbar-width or scrollbar-color here or Chrome will opt into the modern
   scrollbar API for the modal and re-show native arrow buttons */

/* ---------- startup animation ---------- */
.intro {
  position: fixed; inset: 0; z-index: 200;
  background: var(--paper);
  overflow: hidden; display: flex; flex-direction: column; align-items: center; justify-content: center;
  opacity: 1; transition: opacity 400ms var(--ease-out);
}
.intro-mark {
  font-family: var(--serif); font-weight: 600; font-size: clamp(26px, 7vw, 38px);
  letter-spacing: -.02em; color: var(--ink); margin-bottom: 26px;
  opacity: 0; animation: introFade 420ms var(--ease-out) 80ms forwards;
}
.intro-mark .slash, .intro-mark .dot { color: var(--accent); }
.intro-track {
  position: relative; width: min(50vw, 180px); height: 3px; border-radius: 3px;
  background: var(--line-2); overflow: hidden;
  opacity: 0; animation: introFade 420ms var(--ease-out) 220ms forwards;
}
.intro-spark {
  position: absolute; top: 0; left: 0; height: 100%; width: 38%; border-radius: 3px;
  background: linear-gradient(90deg, transparent, var(--accent) 55%, transparent);
  filter: drop-shadow(0 0 5px var(--accent));
  animation: introSpark 1.15s ease-in-out 260ms infinite;
}
@keyframes introFade { to { opacity: 1; } }
@keyframes introSpark {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(380%); }
}
.intro.is-leaving { opacity: 0; pointer-events: none; }
.intro.hidden { display: none; }
@media (min-width: 981px) { .intro { display: none; } }   /* loading screen: mobile only */

/* ---------- wire lane (scroll-scrubbed video) ---------- */
.wire-lane {
  position: fixed; top: 0; right: 0; height: 100vh; width: var(--lane);
  z-index: 1; pointer-events: none; overflow: hidden;
  /* NO mask — mask fades produce a visible tone-mix band where the boundary
     reveals page paper through half-opaque video. The ::before overlay below
     does the blending with a paper-coloured fade instead, guaranteed to
     match the page bg exactly. */
}
/* desktop: fade the LEFT edge of the lane into paper so the transition
   between page and video is seamless. Mobile overrides this to a radial
   spotlight around the knot (see the mobile media query below). */
.wire-lane::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 3;
  background: linear-gradient(90deg,
    var(--paper) 0%,
    var(--paper) 24%,
    transparent 60%
  );
}
.wire-video { width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; }
.wire-lane { transition: opacity .45s ease; }
.wire-lane.at-foot { opacity: 0; }   /* wire ends before the footer, never spills across it */

/* ---------- pill nav ---------- */
.pillnav {
  position: fixed; top: 20px; left: 50%; transform: translateX(-50%); z-index: 100;
  display: flex; align-items: center; gap: 2px; padding: 6px;
  background: rgba(238, 232, 220, .72);
  backdrop-filter: blur(18px) saturate(1.15); -webkit-backdrop-filter: blur(18px) saturate(1.15);
  border: 1px solid rgba(20, 19, 15, .08); border-radius: 999px;
  box-shadow: 0 8px 24px rgba(20, 19, 15, .07);
  transition: background 320ms ease, box-shadow 320ms ease;
}
/* a touch more opaque once scrolled, so it always stays legible over whatever's behind it */
.pillnav.is-scrolled {
  background: rgba(238, 232, 220, .88);
  box-shadow: 0 8px 26px rgba(20, 19, 15, .1);
}
.pill-link {
  position: relative; z-index: 1;
  font-size: 12.5px; font-weight: 500; letter-spacing: .01em; color: rgba(20, 19, 15, .64);
  padding: 8px 16px; border-radius: 999px; transition: color var(--dur-fast) var(--ease-out);
}
.pill-link.is-active { color: var(--ink); font-weight: 700; }
.pill-link:hover:not(.is-active), .pill-link:focus-visible { color: var(--ink); }
.pill-link:focus-visible { outline: 1px solid var(--ink); outline-offset: 2px; }
.pill-indicator {
  position: absolute; top: 6px; left: 0; width: 0; height: calc(100% - 12px);
  background: rgba(255, 255, 255, .62); border-radius: 999px; z-index: 0;
  box-shadow: 0 1px 3px rgba(20, 19, 15, .06);
  will-change: transform, width;
  transition: transform 420ms cubic-bezier(.4, 0, .2, 1), width 420ms cubic-bezier(.4, 0, .2, 1);
}

/* ---------- brand mark (corner) ---------- */
.brand {
  position: fixed; top: 16px; left: calc(var(--pad) - 12px); z-index: 100;
  font-weight: 700; font-size: 21px; letter-spacing: -.01em; color: var(--ink);
  padding: 8px 12px; border-radius: 999px;
  background: rgba(238, 232, 220, .72);
  backdrop-filter: blur(18px) saturate(1.15); -webkit-backdrop-filter: blur(18px) saturate(1.15);
  box-shadow: 0 8px 24px rgba(20, 19, 15, .07);
  transition: opacity var(--dur) ease, background 320ms ease, box-shadow 320ms ease;
}
.brand:hover { opacity: .7; }
.brand .slash, .brand .dot { color: var(--accent); }
/* lift the backslash so its mass aligns with the lowercase x-height of "wire"
   instead of hanging low off its own baseline, and tighten the gap so the
   slash reads as part of the wordmark, not a separator before it. Applied
   to every place the mark renders — header pill, intro mark, footer. */
.brand .slash, .intro-mark .slash {
  display: inline-block;
  transform: translateY(-0.14em);
  margin-right: 0.06em;
}
.brand.is-scrolled { background: rgba(238, 232, 220, .88); }
.brand.small {
  position: static; font-size: 14px; padding: 0; background: none;
  backdrop-filter: none; -webkit-backdrop-filter: none; box-shadow: none;
}

/* ---------- page / lane gutter ---------- */
.page { position: relative; z-index: 2; }
@media (min-width: 981px) { .page { padding-right: var(--lane); } }

/* ---------- hero ---------- */
.hero {
  min-height: 88vh; display: flex; flex-direction: column; justify-content: center;
  padding: clamp(118px, 15vh, 168px) var(--pad) clamp(40px, 7vh, 80px);
}
.eyebrow {
  display: inline-block; font-size: 11px; letter-spacing: .22em; color: var(--accent);
  border: 1px solid var(--line-2); border-radius: 999px; padding: 7px 14px; margin-bottom: 28px;
  background: var(--paper-2);
}
.hero-title {
  margin: 0; font-family: var(--serif); font-weight: 500;
  font-size: clamp(44px, 8.6vw, 112px); line-height: .98; letter-spacing: -.035em;
  max-width: 14ch;
}
.hero-emphasis {
  font-style: normal; color: var(--ink); display: inline-block;
}
.hero-emphasis .letter {
  display: inline-block;
  will-change: opacity, transform;
  transform-origin: 50% 60%;
}
.hero-title .cursor {
  font-family: var(--mono); color: var(--accent); font-size: .8em; font-weight: 600;
  line-height: 0; vertical-align: .03em; display: inline-block;
  animation: blink 1.05s steps(1) infinite;
  will-change: transform, opacity;
}
.hero-sub {
  margin: 26px 0 0; max-width: 44ch; font-size: clamp(16px, 1.5vw, 18.5px); line-height: 1.6; color: #4a463d;
}
.hero-cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 32px; }

/* ---------- buttons (pills) ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--mono); font-size: 13px; letter-spacing: .01em;
  padding: 13px 22px; border-radius: 999px; border: 1px solid transparent;
  transition: transform var(--dur) var(--ease-out), background var(--dur) ease, color var(--dur) ease, border-color var(--dur) ease, box-shadow var(--dur) ease;
}
.btn .arr { transition: transform var(--dur) var(--ease-out); }
.btn:hover .arr { transform: translateX(4px); }
.btn-primary { background: var(--ink); color: var(--paper); }
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 10px 26px rgba(20,19,15,.18); }
.btn-ghost { border-color: var(--line-2); color: var(--ink); background: var(--paper-2); }
.btn-ghost:hover { border-color: var(--ink); transform: translateY(-2px); }
.btn-wa { background: var(--ink); color: var(--paper); }
.btn-wa:hover { transform: translateY(-2px); box-shadow: 0 10px 26px rgba(20,19,15,.18); }
.btn-email { border-color: var(--line-2); color: var(--ink); background: var(--paper-2); }
.btn-email:hover { border-color: var(--ink); transform: translateY(-2px); }

/* ---------- capabilities ---------- */
.caps { display:flex; align-items:baseline; gap:clamp(28px,5.5vw,84px); margin:0 var(--pad); padding:36px 0 44px; }
.cap { display:flex; align-items:baseline; gap:12px; }
.cap h3 { margin:0; font-family:var(--serif); font-weight:700; font-size:clamp(22px,2.4vw,28px); letter-spacing:-.02em; }
.cap p { margin:0; font-size:clamp(14px,1.3vw,16px); color:var(--muted); }
@media (max-width:780px) { .caps { align-items:flex-start; flex-direction:column; gap:18px; padding:32px 0; } }

/* ---------- section shared ---------- */
.work, .studio, .contact { padding: clamp(70px, 12vh, 140px) var(--pad); }
.label { display: inline-block; font-size: 11px; letter-spacing: .24em; color: var(--muted); margin-bottom: 20px; }
.sec-head { max-width: 620px; margin-bottom: clamp(38px, 6vh, 64px); }
.sec-head h2, .contact h2 {
  margin: 0 0 16px; font-family: var(--serif); font-weight: 400;
  font-size: clamp(28px, 4.5vw, 52px); line-height: 1.05; letter-spacing: -.015em;
}
.sec-head h2 em, .contact h2 em { font-style: italic; color: var(--accent); }
.sec-note { margin: 0; font-size: clamp(15px, 1.4vw, 17px); line-height: 1.65; color: #4a463d; max-width: 52ch; }

/* ---------- work carousel ---------- */
.work-carousel {
  position: relative;
  display: block;
  max-width: 1100px;
  margin: 0 auto;
}
.car-viewport {
  position: relative;
  height: clamp(520px, 62vh, 640px);
  overflow: visible;
}
/* arrows sit just outside the active card, not at the section edges */
.work-carousel > .car-nav {
  position: absolute; top: 50%;
  transform: translateY(-50%);
  z-index: 4;
}
.work-carousel > .car-nav.prev { left: calc(50% - min(280px, 46%) - 56px); }
.work-carousel > .car-nav.next { right: calc(50% - min(280px, 46%) - 56px); }
.work-carousel > .car-nav:hover { transform: translateY(-50%) scale(1.08); }
.work-carousel > .car-nav:disabled:hover { transform: translateY(-50%); }
.car-track {
  position: relative;
  width: 100%; height: 100%;
}
.car-nav {
  width: 44px; height: 44px; border-radius: 999px;
  background: var(--paper-2); border: 1px solid var(--line-2); color: var(--ink);
  display: grid; place-items: center; cursor: pointer;
  transition: background var(--dur) ease, transform var(--dur) var(--ease-out), border-color var(--dur) ease, opacity var(--dur) ease;
  z-index: 4;
}
.car-nav:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); transform: scale(1.08); }
.car-nav:disabled { opacity: .3; cursor: default; }
.car-nav:disabled:hover { background: var(--paper-2); color: var(--ink); border-color: var(--line-2); transform: none; }

.car-dots {
  position: absolute; left: 50%; bottom: -34px; transform: translateX(-50%);
  display: flex; gap: 8px; z-index: 4;
}
.car-dots button {
  width: 7px; height: 7px; border-radius: 50%; padding: 0; border: 0;
  background: var(--line-2); cursor: pointer;
  transition: background var(--dur) ease, transform var(--dur) var(--ease-out), width var(--dur) var(--ease-out);
}
.car-dots button.is-active { background: var(--accent); width: 22px; border-radius: 999px; }

/* every card is absolute-positioned inside the track; JS assigns a
   position class (prev/active/next/hidden) that drives transform + opacity */
.card {
  position: absolute; top: 0; left: 50%;
  width: min(560px, 92%);
  background: var(--paper-2); border: 1px solid var(--line);
  border-radius: 16px; padding: clamp(20px, 2.4vw, 28px); overflow: hidden;
  transform: translateX(-50%) scale(0.55);
  opacity: 0; pointer-events: none;
  transition:
    transform 520ms var(--ease-out),
    opacity 420ms ease,
    box-shadow var(--dur) ease,
    border-color var(--dur) ease;
  will-change: transform, opacity;
  /* iOS: long-press was triggering the text-selection/callout menu which
     force-scaled the card and cut its top off. Disable both. */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.card.is-active {
  transform: translateX(-50%) scale(1);
  opacity: 1; pointer-events: auto; z-index: 3;
  box-shadow: 0 30px 70px rgba(20,19,15,.14);
  cursor: pointer;
}
.card.is-active:hover {
  transform: translateX(-50%) scale(1.03) translateY(-4px);
  box-shadow: 0 40px 90px rgba(20,19,15,.18);
  border-color: var(--line-2);
}
.card.is-prev {
  transform: translateX(calc(-50% - clamp(280px, 34vw, 420px))) scale(0.62);
  opacity: .42; pointer-events: auto; z-index: 2; cursor: pointer;
}
.card.is-next {
  transform: translateX(calc(-50% + clamp(280px, 34vw, 420px))) scale(0.62);
  opacity: .42; pointer-events: auto; z-index: 2; cursor: pointer;
}
.card.is-prev:hover, .card.is-next:hover { opacity: .65; }

.card-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; gap: 12px; flex-wrap: wrap; }
.status { font-size: 11.5px; letter-spacing: .18em; font-weight: 700; display: inline-flex; align-items: center; gap: 8px; text-transform: uppercase; }
.status.live { color: var(--live); font-size: 12.5px; }
.status.live i {
  width: 10px; height: 10px; border-radius: 50%; background: var(--live);
  box-shadow: 0 0 0 0 rgba(47,158,111,.55);
  animation: pulse2 1.6s infinite;
}
@keyframes pulse2 {
  0%   { box-shadow: 0 0 0 0 rgba(47,158,111,.55); }
  70%  { box-shadow: 0 0 0 11px rgba(47,158,111,0); }
  100% { box-shadow: 0 0 0 0 rgba(47,158,111,0); }
}
.status.internal { color: var(--faint); }
.status.soon {
  color: var(--accent);
  background: rgba(46,64,192,.09);
  border: 1px solid rgba(46,64,192,.2);
  border-radius: 999px; padding: 4px 10px;
}
.card-visit {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; letter-spacing: .04em; font-weight: 600;
  color: var(--accent);
  padding: 5px 12px; border-radius: 999px;
  border: 1px solid rgba(46,64,192,.35);
  background: rgba(46,64,192,.06);
  transition: background var(--dur) ease, color var(--dur) ease, transform var(--dur) var(--ease-out);
}
.card-visit:hover { background: var(--accent); color: #fff; transform: translateY(-1px); }
.card-visit .ext { font-size: 13px; line-height: 1; }

.card h3 { margin: 16px 0 4px; font-family: var(--serif); font-weight: 500; font-size: clamp(21px, 2.6vw, 28px); letter-spacing: -.01em; }
.kind { margin: 0 0 16px; font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
.feats { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.feats li { position: relative; padding-left: 18px; font-size: 13.5px; line-height: 1.55; color: #45413a; }
.feats li::before {
  content: ""; position: absolute; left: 4px; top: 0.62em;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent);
}

/* skill pills (cards + detail sheet) */
.tags { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.tags span {
  font-size: 10.5px; letter-spacing: .05em; color: var(--muted);
  border: 1px solid var(--line-2); border-radius: 999px;
  padding: 4px 11px; white-space: nowrap;
}

/* ---------- skeleton mockups ---------- */
.mock {
  aspect-ratio: 16 / 9; border-radius: 10px; border: 1px solid var(--line);
  background: #fff; padding: 14px; overflow: hidden; display: flex; gap: 12px;
  position: relative;
}
/* real screenshots — 16:9 box (matches skeleton mock aspect so cards line up),
   `contain` (not cover) with a paper background shows the WHOLE screenshot
   letterboxed instead of guessing which side to crop. Source screenshots
   vary in aspect (1.6:1 to 2.2:1); forcing a single crop hid different
   content on each card, so letterboxing is safer. */
.mock-shot {
  display: block; width: 100%; aspect-ratio: 16 / 9;
  object-fit: contain; object-position: center center;
  border-radius: 10px; border: 1px solid var(--line);
  background: var(--paper-2);
}
/* "Coming soon" chip overlay for mock skeletons that aren't a real project yet */
.mock-badge {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink); background: rgba(238, 232, 220, .82);
  border: 1px solid var(--line-2); border-radius: 999px;
  padding: 4px 10px; backdrop-filter: blur(6px);
}
.sk, .sk-accent {
  display: block; border-radius: 5px;
  background: linear-gradient(100deg, #ece8df 30%, #f6f3ec 50%, #ece8df 70%);
  background-size: 220% 100%; animation: shimmer 1.7s linear infinite;
}
.sk-accent { background: linear-gradient(100deg, rgba(46,64,192,.16) 30%, rgba(46,64,192,.30) 50%, rgba(46,64,192,.16) 70%); background-size: 220% 100%; }
@keyframes shimmer { to { background-position: -220% 0; } }

/* PO->SO: doc -> table */
.mock-doc { align-items: stretch; }
.mock-doc .doc { flex: 1.1; display: flex; flex-direction: column; gap: 8px; justify-content: center; }
.mock-doc .doc .l { height: 8px; width: 100%; }
.flow-arrow { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; color: var(--accent); }
.flow-arrow .dot-a { width: 10px; height: 10px; border-radius: 50%; }
.flow-arrow .bar-a { width: 4px; height: 26px; border-radius: 3px; }
.flow-arrow .arrowhead { font-size: 16px; }
.mock-doc .tablet { flex: 1; display: flex; flex-direction: column; gap: 7px; justify-content: center; background: var(--paper-2); border-radius: 6px; padding: 8px; }
.mock-doc .tablet .row { height: 9px; width: 100%; }
.mock-doc .tablet .total { height: 11px; width: 55%; align-self: flex-end; border-radius: 4px; }

/* Sai Water: QR + ledger */
.mock-ledger { align-items: center; }
.mock-ledger .qr { flex: 0 0 34%; aspect-ratio: 1; border-radius: 8px; background: var(--paper-2); display: grid; place-items: center; }
.mock-ledger .qr .sk-accent { width: 62%; aspect-ratio: 1; border-radius: 6px; }
.mock-ledger .ledger { flex: 1; display: flex; flex-direction: column; gap: 9px; }
.mock-ledger .ledger .row { height: 10px; }

/* Quotation: master table -> priced sheet */
.mock-quote { align-items: stretch; }
.mock-quote .q-master { flex: 0 0 40%; display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; align-content: center; background: var(--paper-2); border-radius: 6px; padding: 9px; }
.mock-quote .q-master .cell { height: 14px; border-radius: 3px; }
.mock-quote .q-sheet { flex: 1; display: flex; flex-direction: column; gap: 8px; justify-content: center; }
.mock-quote .q-sheet .row { height: 10px; width: 100%; }
.mock-quote .q-sheet .total { height: 13px; width: 52%; align-self: flex-end; border-radius: 4px; }

/* Common Man: dashboard */
.mock-dash { flex-direction: column; gap: 10px; }
.mock-dash .kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.mock-dash .kpis .tile { height: 30px; border-radius: 6px; }
.mock-dash .bars { flex: 1; display: flex; align-items: flex-end; gap: 8px; padding-top: 4px; }
.mock-dash .bars .b { flex: 1; border-radius: 4px 4px 2px 2px; }

/* Websites: browser + hero + thumbs */
.mock-site { flex-direction: column; gap: 9px; padding: 10px; }
.mock-site .browser { display: flex; align-items: center; gap: 6px; }
.mock-site .browser .d { width: 7px; height: 7px; border-radius: 50%; background: var(--line-2); }
.mock-site .browser .urlbar { flex: 1; height: 9px; margin-left: 6px; border-radius: 5px; }
.mock-site .site-hero { background: var(--paper-2); border-radius: 8px; padding: 12px; display: flex; flex-direction: column; gap: 7px; flex: 1; justify-content: center; }
.mock-site .site-hero.big { flex: 1.4; }
.mock-site .site-hero .h1 { height: 13px; width: 80%; }
.mock-site .site-hero .h2 { height: 9px; }
.mock-site .site-hero .pillbtn { height: 14px; width: 34%; border-radius: 999px; margin-top: 4px; }
.mock-site .thumbs { display: flex; gap: 8px; }
.mock-site .thumbs .th { flex: 1; aspect-ratio: 1; border-radius: 6px; }
.w40 { width: 40% !important; } .w50 { width: 50% !important; } .w60 { width: 60% !important; } .w70 { width: 70% !important; } .w80 { width: 80% !important; }

/* ---------- process (was: studio) ---------- */
.studio { }
/* process lead matches the other section h2s (sec-head h2 / contact h2) so all
   three top-of-section headlines share the same typography */
.process-lead {
  margin: 0 0 clamp(36px, 6vh, 60px); max-width: 22ch;
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(28px, 4.5vw, 52px); line-height: 1.05; letter-spacing: -.015em;
}
/* ---------- process list — plain numbered steps, no cards, no loop ---------- */
.process-list {
  list-style: none; margin: 0; padding: 0; max-width: 640px;
  display: grid; gap: clamp(18px, 2.4vh, 28px);
}
.process-list li {
  display: grid; grid-template-columns: auto 1fr; gap: clamp(16px, 3vw, 28px);
  align-items: baseline; padding-bottom: clamp(18px, 2.4vh, 28px);
  border-bottom: 1px solid var(--line);
  transform-origin: left center;
  transition: transform 380ms var(--ease-out);
}
.process-list li:last-child { border-bottom: 0; }
.step-n {
  font-size: 12px; letter-spacing: .16em; color: var(--faint);
  font-variant-numeric: tabular-nums; padding-top: 6px;
  transition: color 320ms var(--ease-out);
}
.process-list h4 {
  margin: 0 0 6px; font-family: var(--serif); font-weight: 500;
  font-size: clamp(22px, 3vw, 32px); letter-spacing: -.02em; line-height: 1.1;
  color: var(--ink);
  transition: color 320ms var(--ease-out);
}
.process-list p {
  margin: 0; font-size: clamp(14px, 1.35vw, 16.5px);
  line-height: 1.55; color: var(--muted);
}
/* scroll-driven highlight: as each row hits the viewport's read-line, its
   number and heading pop to accent blue */
.process-list li.is-active { transform: scale(1.06) translateY(-4px); }
.process-list li.is-active .step-n { color: var(--accent); }
.process-list li.is-active h4      { color: var(--accent); }

/* ---------- contact ---------- */
.contact { }
.contact-actions { display: flex; flex-wrap: wrap; gap: 12px; margin: 10px 0 22px; }
.contact-actions .btn { font-size: 14px; padding: 15px 26px; }
.wa-menu { position:relative; }
.wa-menu summary { list-style:none; cursor:pointer; }
.wa-menu summary::-webkit-details-marker { display:none; }
.wa-menu[open] .arr { transform:rotate(90deg); }
.wa-options {
  position:absolute; left:0; bottom:calc(100% + 12px); min-width:270px; z-index: 5;
  padding:8px; border-radius:16px; border:1px solid rgba(20,19,15,.08);
  background:rgba(238,232,220,.72);
  backdrop-filter: blur(20px) saturate(1.15); -webkit-backdrop-filter: blur(20px) saturate(1.15);
  box-shadow:0 18px 46px rgba(20,19,15,.16);
  opacity:0; transform: translateY(8px) scale(.97); pointer-events:none;
  transition: opacity 200ms var(--ease-out), transform 200ms var(--ease-out);
}
.wa-menu[open] .wa-options { opacity:1; transform:none; pointer-events:auto; }
.wa-options a {
  display:flex; align-items:center; gap:9px; padding:12px 14px; border-radius:11px;
  font-size:13px; color:var(--ink); transition: background var(--dur-fast) ease;
}
.wa-options a::before { content:""; width:7px; height:7px; border-radius:50%; background:var(--wa); flex:none; }
.wa-options a:hover, .wa-options a:focus-visible { background:rgba(255,255,255,.55); }

/* ---------- footer ---------- */
.foot {
  border-top: 1px solid var(--line); padding: 26px var(--pad);
  display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap;
  font-size: 10.5px; letter-spacing: .14em; color: var(--muted);
  position: relative; z-index: 3;   /* sit above the fixed wire lane column */
}
/* on desktop the .page wrapper has padding-right: var(--lane) so the wire
   column has room. That padding pinches the footer's separator line and its
   right-aligned copyright text away from the true page edge. Cancel it here
   with a negative margin so the footer + its border-top stretch all the way
   right, and add the same lane width back as padding so the "© 2026 · All
   rights reserved." copy sits flush with the same right edge everything else
   uses. */
@media (min-width: 981px) {
  .foot {
    margin-right: calc(var(--lane) * -1);
    padding-right: var(--pad);
  }
}
.foot .brand { color: var(--ink); }
.foot .brand .slash, .foot .brand .dot { color: var(--accent); }

/* ---------- reveal ---------- */
.reveal { opacity: 0; transform: translateY(20px); transition: opacity var(--dur-rev) var(--ease-out), transform var(--dur-rev) var(--ease-out); }
.reveal.in { opacity: 1; transform: none; }
.caps .cap:not(.in):nth-child(2) { transition-delay: .07s; }
.caps .cap:not(.in):nth-child(3) { transition-delay: .14s; }
.cols > div:not(.in):nth-child(2) { transition-delay: .08s; }
.cols > div:not(.in):nth-child(3) { transition-delay: .16s; }

@keyframes blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } }

/* ---------- mobile: wire behind hero ---------- */
@media (max-width: 980px) {
  /* wire sits above the page, everything stays transparent, so the knot is
     fully visible untangling on the landing */
  .wire-lane {
    width: 100%; opacity: 1;
    /* 100lvh (large viewport height) instead of 100svh — svh locks to the
       address-bar-visible height, so when iOS Safari HIDES its URL bar the
       viewport grows past the lane's fixed height and exposes a paper-colored
       strip at the bottom (that was the "horizontal two-tone line" on real
       iOS). lvh always fills the largest possible viewport, so no strip ever
       shows regardless of address-bar state. */
    /* fallback for browsers without lvh — plain 100vh first, then lvh so
       modern browsers use the largest-viewport unit (URL bar hidden height) */
    height: 100vh;
    height: 100lvh;
    /* NO mask on mobile — mask fades caused a visible tone-mix band where the
       mask boundary revealed page paper through half-opaque video. The ::before
       overlay below does the blending with a paper-coloured fade instead,
       which is guaranteed to match the page bg exactly. */
    -webkit-mask-image: none; mask-image: none;
  }
  /* RADIAL spotlight — the source video has a lighting gradient baked into
     its background (one side is subtly brighter than the other), which shows
     up as a vertical band anywhere it's full-bleed. Edge-only overlays could
     never cover it because the tone variation is mid-image, not at an edge.
     A radial paper mask centred on where the knot actually renders keeps
     ONLY that circle of video visible — everything else is pure paper, so
     no tone variation can show anywhere. */
  .wire-lane::before {
    content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 3;
    background: radial-gradient(
      ellipse 46% 38% at 74% 52%,
      transparent 0%,
      transparent 40%,
      var(--paper) 82%
    );
  }
  /* also nudge the canvas itself slightly translucent so any pixel that DOES
     bleed past the mask is blended with paper too — belt and braces. */
  .wire-lane .wire-video { opacity: .92; }
  /* on mobile, pull caps UP into the empty space between the buttons and the
     knot — the previous 16vh push landed them behind Safari's floating URL bar
     which cut off "Build" mid-word on real phones. This anchors them right
     under the buttons where there's real, always-visible screen real estate. */
  .caps { margin-top: 8px; padding-top: 4px; padding-bottom: 20px; gap: 14px; }
  .intro-track { width: min(60vw, 200px); }
  /* content is frosted glass so the untangling knot shows through it the whole
     scroll, while staying fully functional */
  .work .card {
    background: rgba(238, 232, 220, .82);
    border-color: rgba(20, 19, 15, .09);
  }
  /* on mobile: full-width viewport so the active card sits in the true
     centre of the phone screen (covering the wire knot behind it), with
     nav buttons floated over the edges instead of eating side columns */
  .work { padding-left: 0; padding-right: 0; }
  .work .sec-head { padding-left: var(--pad); padding-right: var(--pad); }
  .work-carousel {
    grid-template-columns: 1fr;
    gap: 0;
    padding: 0;
    position: relative;
  }
  .car-viewport {
    height: clamp(540px, 78vh, 700px);
    overflow: hidden;   /* prev/next cards must not spill past the screen */
  }
  .car-nav { display: none; }   /* mobile: swipe only */
  .car-viewport { height: clamp(500px, 72vh, 660px); }
  .card { width: min(340px, calc(100% - 48px)); padding: 16px; }
  .card h3 { font-size: 20px; }
  .card .feats li { font-size: 12.5px; }
  /* pull dots up and add breathing room so the fixed nav pill (bottom: 18px)
     doesn't sit on top of them */
  .car-dots { bottom: -18px; }
  .work { padding-bottom: 110px; }
  .card.is-prev { transform: translateX(calc(-50% - 82vw)) scale(0.5); opacity: 0; pointer-events: none; }
  .card.is-next { transform: translateX(calc(-50% + 82vw)) scale(0.5); opacity: 0; pointer-events: none; }
  .mock { background: rgba(255, 255, 255, .26); }
  .brand { display: block; top: 20px; font-size: 16px; }
  .pillnav { top: auto; bottom: 18px; }
  .hero { min-height: auto; justify-content: flex-start; padding-top: clamp(96px, 13vh, 128px); padding-bottom: 44px; }
  /* the wire runs the full page height here, so these divider borders were
     drawing as opaque horizontal lines directly across it (page content sits
     above the wire lane in stacking order) — drop them on mobile only, the
     frosted-glass cards already read as separated sections without them */
  .studio, .cols, .contact, .foot { border-top-color: transparent; }
}

/* ---------- clickable cards + detail sheet ---------- */
.work .card { cursor: pointer; }
.card-more {
  display: inline-flex; align-items: center; margin-top: 20px;
  font-size: 13.5px; letter-spacing: .04em; font-weight: 700;
  color: var(--accent); opacity: .92;
  transition: opacity var(--dur) ease, transform var(--dur) var(--ease-out);
}
.card.is-active:hover .card-more, .card:focus-visible .card-more { opacity: 1; transform: translateX(3px); }
.card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.sheet-overlay {
  position: fixed; inset: 0; z-index: 300;
  display: grid; place-items: center; padding: clamp(16px, 4vw, 48px);
  background: rgba(20, 19, 15, .34);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  opacity: 0; transition: opacity 260ms var(--ease-out);
}
.sheet-overlay.open { opacity: 1; }
.sheet-overlay[hidden] { display: none; }
.sheet {
  position: relative; width: min(640px, 100%); max-height: 88vh; overflow-y: auto;
  background: var(--paper); border: 1px solid var(--line);
  border-radius: 18px; padding: clamp(26px, 4vw, 44px);
  box-shadow: 0 30px 80px rgba(20, 19, 15, .28);
  transform: translateY(14px) scale(.985); transition: transform 300ms var(--ease-out);
}
.sheet-overlay.open .sheet { transform: none; }
.sheet-close {
  position: absolute; top: 14px; right: 16px; width: 34px; height: 34px;
  border: 1px solid var(--line-2); border-radius: 50%; background: var(--paper-2);
  color: var(--ink); font-size: 20px; line-height: 1; cursor: pointer;
  transition: background var(--dur) ease, transform var(--dur) var(--ease-out);
}
.sheet-close:hover { background: var(--line); transform: rotate(90deg); }
.sheet-top { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; }
.sheet h2 { margin: 0; font-family: var(--serif); font-weight: 600; font-size: clamp(26px, 4vw, 38px); letter-spacing: -.02em; }
.sheet-kind { margin: 4px 0 0; font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); }
/* lead sits under the client block; matched to the same body size as every
   other paragraph in the modal so the vertical rhythm is one size everywhere,
   with italic carrying the emphasis instead of a size jump */
.sheet-lead { margin: 18px 0 4px; font-size: 13.5px; line-height: 1.7; color: #45413a; font-style: italic; }
/* full-width screenshot inside the modal — same letterbox-on-paper treatment
   as the card mocks so it never crops content, just at a bigger canvas */
.sheet-shot {
  display: block; width: 100%; aspect-ratio: 16 / 9;
  object-fit: contain; object-position: center center;
  border-radius: 12px; border: 1px solid var(--line);
  background: var(--paper-2);
  margin: 20px 0 8px;
}
/* client block — matches the surrounding .sheet-block paragraphs so the modal
   has a single readable body-copy size throughout; the "Built for" LABEL is
   what visually separates it */
.sheet-client { margin-top: 18px; padding-top: 0; border-top: 0; }
.sheet-client p { font-size: 13.5px; line-height: 1.7; color: #45413a; margin: 0; }
.sheet-block { margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--line); }
.sheet-label { display: block; font-size: 12px; font-weight: 800; letter-spacing: .22em; text-transform: uppercase; color: var(--accent); margin-bottom: 10px; }
.sheet-block .feats li { position: relative; padding-left: 18px; }
.sheet-block .feats li::before {
  content: ""; position: absolute; left: 4px; top: 0.62em;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent);
}
.sheet-block > p { margin: 0; font-size: 13.5px; line-height: 1.7; color: #45413a; }
.sheet-block .feats { display: grid; gap: 9px; }
.sheet-block .feats li { font-size: 13.5px; color: #45413a; }
.sheet-visit { margin-top: 26px; }
