
:root {
  --paper:   #FFFFFF;
  --paper-2: #F4F2ED;   /* tinted band */
  --paper-3: #EAE7E0;

  --ink:   #141416;
  --ink-2: #55555E;     /* 7.6:1 on white */
  --ink-3: #757580;     /* 4.6:1 on white — the quietest text allowed */

  --rule:   rgba(20, 20, 22, .12);
  --rule-2: rgba(20, 20, 22, .26);

  --red:    #FF020A;  --red-t:    #DC0209;
  --orange: #FF7E0A;  --orange-t: #AC5507;
  --purple: #7A2E9C;  --purple-t: #7A2E9C;
  --cyan:   #00A0E3;  --cyan-t:   #0074A5;
  --navy:   #0C2A88;  --navy-t:   #0C2A88;
  --green:  #009846;  --green-t:  #007E3A;
  --yellow: #FECC00;

  /* the running ink — motion.js swaps all three per section */
  --accent:     #FF020A;
  --accent-ink: #DC0209;
  --on-accent:  #141416;

  --f: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --pad: clamp(20px, 5vw, 64px);
  --gut: clamp(28px, 5vw, 76px);
  --ease: cubic-bezier(.16, 1, .3, 1);

  --r:   22px;
  --r-s: 12px;

  /* the call and WhatsApp buttons: their size, and how far they sit in from
     the corners. The footer reads both to leave them room. */
  --fab: 56px;
  --fab-in: clamp(14px, 2vw, 24px);
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; background: var(--paper); }
html.has-smooth { scroll-behavior: auto; }


[id] { scroll-margin-top: 104px; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--f);
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-wrap: pretty;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
ul, ol { margin: 0; padding: 0; list-style: none; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.035em;
}

::selection { background: var(--accent); color: var(--on-accent); }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; border-radius: 3px; }

/* --- layout ------------------------------------------------------------- */
.wrap { width: 100%; max-width: 1400px; margin-inline: auto; padding-inline: var(--pad); }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

.skip {
  position: absolute; left: var(--pad); top: -80px; z-index: 200;
  background: var(--ink); color: #fff;
  padding: 14px 22px; border-radius: var(--r-s);
  transition: top .2s;
}
.skip:focus { top: 16px; }


.sheet { display: none; }


.display-l, .display-m, .display-s { font-weight: 800; }


.display-l { font-size: clamp(2.2rem, 4.7vw, 4.4rem); line-height: .98;  letter-spacing: -.042em; }
.display-m { font-size: clamp(2rem, 4.8vw, 3.9rem);   line-height: 1;    letter-spacing: -.038em; }
.display-s { font-size: clamp(1.25rem, 2.2vw, 1.8rem); line-height: 1.08; letter-spacing: -.028em; font-weight: 700; }

.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent-ink);
  transition: color .6s var(--ease);
}
.eyebrow::before {
  content: '';
  width: 9px; height: 9px; border-radius: 50%;
  background: currentColor;
  flex: none;
}

.lede  { font-size: clamp(1.05rem, 1.4vw, 1.28rem); line-height: 1.58; color: var(--ink-2); }
.muted { color: var(--ink-2); }
.small { font-size: 14.5px; }
.mono  { font-family: var(--mono); }

.link {
  color: var(--ink);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--rule-2);
  text-underline-offset: 4px;
  transition: color .3s, text-decoration-color .3s;
}
.link:hover { color: var(--accent-ink); text-decoration-color: currentColor; }


.ph {
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: .92em;
  border-bottom: 1px dashed var(--rule-2);
}


.btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 15px 28px;
  border-radius: 100px;
  font-size: 15px;
  font-weight: 700;
  transition: background-color .35s var(--ease), color .35s var(--ease), border-color .35s var(--ease);
}
.btn svg { flex: none; transition: transform .4s var(--ease); }
.btn:hover svg { transform: translateX(4px); }

.btn--solid { background: var(--accent); color: var(--on-accent); }
.btn--solid:hover { background: var(--ink); color: #fff; }

.btn--ghost { border: 1.5px solid var(--rule-2); color: var(--ink); }
.btn--ghost:hover { background: var(--ink); border-color: var(--ink); color: #fff; }

.btn--invert { background: var(--ink); color: #fff; }
.btn--invert:hover { background: var(--accent); color: var(--on-accent); }


.cbtn {
  flex: none;
  display: grid; place-items: center;
  width: clamp(44px, 4.4vw, 52px); aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(255, 255, 255, .2);
  color: inherit;
  transition: background-color .4s var(--ease), color .4s var(--ease), transform .4s var(--ease);
}

.chip {
  display: inline-flex; align-items: center;
  padding: 8px 16px;
  border: 1.5px solid var(--rule);
  border-radius: 100px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  transition: border-color .3s, color .3s;
}
.chip:hover { border-color: var(--ink); color: var(--ink); }


.hdr {
  position: fixed; top: 0; left: 0; right: 0; z-index: 120;
  padding-block: 14px;
  transition: padding .35s var(--ease), background-color .35s var(--ease), box-shadow .35s var(--ease);
}
.hdr.is-stuck {
  padding-block: 8px;
  background: rgba(255, 255, 255, .9);
  backdrop-filter: blur(16px) saturate(140%);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  box-shadow: 0 1px 0 var(--rule);
}

.hdr__bar { display: flex; align-items: center; gap: 22px; }
.hdr__logo { flex: none; padding-block: 3px; }


.hdr__logo img { height: 48px; width: auto; transition: height .35s var(--ease); }
.hdr.is-stuck .hdr__logo img { height: 40px; }

.nav { display: flex; align-items: center; gap: clamp(12px, 1.8vw, 26px); margin-inline: auto; }
.nav a {
  position: relative;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink-2);
  padding-block: 6px;
  transition: color .3s;
}
.nav a::after {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  border-radius: 2px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: right;
  transition: transform .4s var(--ease), background-color .6s var(--ease);
}
.nav a:hover { color: var(--ink); }
.nav a:hover::after { transform: scaleX(1); transform-origin: left; }
.nav a[aria-current='page'] { color: var(--ink); }
.nav a[aria-current='page']::after { transform: scaleX(1); }

.hdr__tel {
  flex: none;
  background: var(--ink); color: #fff;
  font-size: 14.5px; font-weight: 700;
  padding: 13px 24px;
  border-radius: 100px;
  transition: background-color .35s var(--ease), color .35s var(--ease);
}
.hdr__tel:hover { background: var(--accent); color: var(--on-accent); }

.burger { display: none; width: 46px; height: 46px; align-items: center; justify-content: center; }
.burger span { display: block; width: 25px; height: 2.5px; border-radius: 2px; background: var(--ink); position: relative; transition: background .2s; }
.burger span::before, .burger span::after {
  content: ''; position: absolute; left: 0; width: 25px; height: 2.5px; border-radius: 2px;
  background: var(--ink); transition: transform .3s var(--ease);
}
.burger span::before { top: -7px; }
.burger span::after  { top: 7px; }
body.menu-open .burger span { background: transparent; }
body.menu-open .burger span::before { transform: translateY(7px) rotate(45deg); }
body.menu-open .burger span::after  { transform: translateY(-7px) rotate(-45deg); }

.drawer {
  position: fixed; inset: 0; z-index: 110;
  background: var(--paper);
  padding: 106px var(--pad) 40px;
  overflow-y: auto;
  clip-path: inset(0 0 100% 0);
  transition: clip-path .6s var(--ease);
}
body.menu-open .drawer { clip-path: inset(0 0 0 0); }
.drawer a {
  font-size: clamp(1.6rem, 7vw, 2.3rem);
  font-weight: 800;
  letter-spacing: -.035em;
  transition: color .3s, padding-left .35s var(--ease);
}
.drawer a:hover { color: var(--accent-ink); padding-left: 10px; }
.drawer li { border-bottom: 1px solid var(--rule); }
.drawer li a { padding-block: 15px; display: flex; align-items: baseline; gap: 16px; }
.drawer .num { font-family: var(--mono); font-weight: 500; font-size: 12px; color: var(--ink-3); letter-spacing: .1em; }


.hero { padding-top: clamp(120px, 15vw, 168px); padding-bottom: clamp(40px, 5vw, 64px); }
.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: clamp(30px, 5vw, 70px);
  align-items: center;
}

.hero__slug {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 8px 18px 8px 8px;
  border: 1.5px solid var(--rule);
  border-radius: 100px;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin-bottom: clamp(20px, 2.6vw, 28px);
}
.hero__pip { width: 22px; height: 22px; border-radius: 50%; background: var(--accent); flex: none; transition: background-color .6s var(--ease); }


.hero__title { font-size: clamp(2.2rem, 5.1vw, 4.5rem); line-height: .98; letter-spacing: -.045em; }

.hero__title em { font-style: normal; color: var(--accent-ink); transition: color .6s var(--ease); }

.hero__lede    { max-width: 42ch; margin-top: 22px; }
.hero__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: clamp(24px, 3vw, 32px); }


.swatch { display: flex; gap: 6px; margin-top: clamp(26px, 3.4vw, 38px); }
.swatch i { flex: 1; height: 8px; border-radius: 100px; display: block; }


.line { display: block; overflow: hidden; padding-bottom: .08em; margin-bottom: -.08em; }
.line > span { display: block; transform: translateY(105%); }
.js .line > span { animation: rise 1s var(--ease) both; }
@keyframes rise { to { transform: none; } }


.collage { display: grid; grid-template-columns: repeat(6, 1fr); gap: 12px; }
.collage a { overflow: hidden; border-radius: 16px; background: var(--paper-2); display: block; }
.collage img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var(--ease); }
.collage a:hover img { transform: scale(1.06); }
.collage__1 { grid-column: span 4; aspect-ratio: 4 / 3; }
.collage__2 { grid-column: span 2; aspect-ratio: 3 / 4; }
.collage__3 { grid-column: span 2; aspect-ratio: 1; }
.collage__4 { grid-column: span 4; aspect-ratio: 16 / 10; }


.band { background: var(--ink); color: #fff; }
/* Four across, two by two on a phone. An auto-fit track put all four in one
   column at 375px, a band nearly 470px tall, and left a 3 + 1 orphan in
   between. The stats at the outer edges take the page's own edge padding,
   so the first number lines up with the text above it. */
.stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.stat {
  padding: clamp(26px, 3.4vw, 46px) clamp(18px, 2.2vw, 30px);
  border-right: 1px solid rgba(255, 255, 255, .15);
}
.stat:first-child { padding-left: var(--pad); }
.stat:last-child { padding-right: var(--pad); border-right: 0; }
.stat__n {
  display: flex; align-items: baseline;
  font-size: clamp(2.3rem, 5vw, 4rem);
  font-weight: 800; line-height: 1; letter-spacing: -.045em;
  /* the suffix would otherwise shuffle sideways as the digits count up */
  font-variant-numeric: tabular-nums;
}
.stat__n i { font-style: normal; color: var(--yellow); }
.stat__l {
  display: block; margin-top: 9px;
  font-size: 11.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: rgba(255, 255, 255, .7);
}
a.stat__l {
  text-decoration: underline; text-underline-offset: 5px;
  text-decoration-color: rgba(255, 255, 255, .3);
  transition: color .3s var(--ease), text-decoration-color .3s var(--ease);
}
a.stat__l:hover { color: #fff; text-decoration-color: currentColor; }
/* the default ring is ink, which is no ring at all on this band */
.band a:focus-visible { outline-color: #fff; }


.shead {
  display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between;
  gap: 20px 40px;
  margin-bottom: clamp(30px, 4vw, 52px);
}
.shead p { max-width: 38ch; }
.shead__l { min-width: 0; }
.shead .eyebrow { margin-bottom: 14px; }


.idx { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(12px, 1.6vw, 20px); }

.idx__row {
  position: relative;
  display: flex; flex-direction: column; justify-content: space-between; gap: 36px;
  min-height: clamp(230px, 24vw, 300px);
  padding: clamp(24px, 2.8vw, 36px);
  border-radius: var(--r);
  background: var(--c);
  color: var(--on);
  overflow: hidden;
  isolation: isolate;
  transition: transform .5s var(--ease), box-shadow .5s var(--ease);
}
.idx__row:hover { transform: translateY(-7px); box-shadow: 0 24px 44px -26px color-mix(in srgb, var(--c) 80%, transparent); }


.idx__num {
  position: absolute; right: -.06em; bottom: -.34em; z-index: -1;
  font-size: 11rem; font-weight: 800; line-height: 1; letter-spacing: -.06em;
  color: color-mix(in srgb, var(--on) 16%, transparent);
  pointer-events: none;
}
.idx__main { min-width: 0; }
.idx__name { display: block; }
.idx__dot { display: none; }
.idx__blurb { display: block; margin-top: 10px; font-size: 14.5px; opacity: .84; max-width: 30ch; }
.idx__chips { display: none; }
.idx__go { align-self: flex-start; }
.idx__row:hover .cbtn { background: var(--on); color: var(--c); transform: translate(4px, -4px); }


.method { background: var(--paper-2); padding-block: clamp(56px, 7.5vw, 108px); }

.method__grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(14px, 2vw, 26px); }
.method__card {
  background: var(--paper);
  border-radius: var(--r);
  padding: clamp(24px, 2.8vw, 36px);
  transition: transform .5s var(--ease), box-shadow .5s var(--ease);
}
.method__card:hover { transform: translateY(-6px); box-shadow: 0 22px 40px -28px rgba(20, 20, 22, .4); }
.method p.method__n {
  display: grid; place-items: center;
  width: 48px; aspect-ratio: 1;
  border-radius: 14px;
  background: var(--accent); color: var(--on-accent);
  font-size: 17px; font-weight: 800;
  margin-bottom: 18px;
  transition: background-color .6s var(--ease), color .6s var(--ease);
}
.method h3 { margin-bottom: 10px; }
.method p { color: var(--ink-2); font-size: 15px; }


.work { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(12px, 1.6vw, 20px); }

.piece {
  display: block;
  border-radius: 18px;
  overflow: hidden;
  background: var(--paper-2);
  transition: transform .5s var(--ease), box-shadow .5s var(--ease);
}
.piece:hover { transform: translateY(-6px); box-shadow: 0 22px 40px -26px rgba(20, 20, 22, .4); }
.piece__art { display: block; overflow: hidden; aspect-ratio: 1; position: relative; }
.piece__art img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var(--ease); }
.piece:hover .piece__art img, .piece:focus-visible .piece__art img { transform: scale(1.06); }

.piece__client {
  position: absolute; left: 12px; bottom: 12px;
  padding: 6px 13px;
  border-radius: 100px;
  background: rgba(255, 255, 255, .94);
  color: var(--ink);
  font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  opacity: 0; transform: translateY(8px);
  transition: opacity .35s var(--ease), transform .35s var(--ease);
}
.piece:hover .piece__client, .piece:focus-visible .piece__client { opacity: 1; transform: none; }

.piece__cap {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 14px 18px 18px;
  background: var(--paper);
}
.piece__name { display: block; font-size: 15px; font-weight: 700; }
.piece__meta { font-size: 10.5px; font-weight: 700; letter-spacing: .11em; text-transform: uppercase; color: var(--ink-3); white-space: nowrap; }

.idx-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; background: var(--rule); border-radius: var(--r); overflow: hidden; }
.idx-list li { background: var(--paper-2); padding: 18px 22px; display: flex; gap: 14px; align-items: baseline; }
.idx-list .n { font-family: var(--mono); font-size: 12px; color: var(--accent-ink); min-width: 26px; }


.studio { padding-block: clamp(56px, 7.5vw, 108px); }
.studio__grid { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: var(--gut); align-items: center; }

.deets { border-top: 1.5px solid var(--rule); }
.deets > div {
  display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); gap: 16px;
  padding-block: 18px;
  border-bottom: 1.5px solid var(--rule);
}
.deets dt { font-size: 11.5px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-3); }
.deets dd { margin: 0; line-height: 1.7; }
.deets dd a:hover { color: var(--accent-ink); }


.cta { padding-bottom: clamp(20px, 3vw, 40px); scroll-margin-top: 104px; }
.cta__inner {
  position: relative;
  overflow: hidden;
  border-radius: var(--r);
  background: var(--ink);
  color: #fff;
  padding: clamp(36px, 5.5vw, 76px);
}
.cta__inner::before {
  content: '';
  position: absolute; left: 50%; bottom: -70%;
  width: min(900px, 120vw); aspect-ratio: 1;
  transform: translateX(-50%);
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 42%, transparent), transparent 62%);
  pointer-events: none;
  transition: background .8s var(--ease);
}
.cta__inner > * { position: relative; }

.cta__inner--ink { background: var(--c); color: var(--on); }
.cta__inner--ink::before { display: none; }
.cta__inner--ink .muted { color: inherit; opacity: .82; }
.cta__grid { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 40px; }
.cta__actions { display: flex; flex-direction: column; gap: 16px; min-width: 260px; }
.cta__grid--split { display: grid; grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr); gap: clamp(30px, 5vw, 64px); align-items: start; }
.cta__direct { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 20px; margin-top: 28px; }
.cta__inner .muted { color: rgba(255, 255, 255, .72); }
.cta .eyebrow { color: #fff; }
.cta .btn--ghost { border-color: rgba(255, 255, 255, .34); color: #fff; }
.cta .btn--ghost:hover { background: #fff; border-color: #fff; color: var(--ink); }
.cta .ph { color: rgba(255, 255, 255, .6); border-bottom-color: rgba(255, 255, 255, .3); }


.enq {
  display: flex; flex-direction: column; gap: 16px;
  padding: clamp(22px, 2.8vw, 34px);
  border-radius: var(--r);
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .16);
}
.enq__row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.enq__f { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.enq__l { font-size: 11.5px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase; color: rgba(255, 255, 255, .74); }
.enq__l i { font-style: normal; color: #FF8A8F; }   /* 6.2:1 on the dark block */

.enq input, .enq select, .enq textarea {
  width: 100%;
  font: inherit; font-size: 16px;
  color: #fff;
  background: rgba(0, 0, 0, .28);
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: var(--r-s);
  padding: 13px 15px;
  transition: border-color .3s, box-shadow .3s;
}
.enq textarea { resize: vertical; min-height: 118px; line-height: 1.55; }
.enq select {
  appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5l5-5' stroke='%23ffffff' stroke-opacity='.7' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 15px center;
  padding-right: 40px;
}
.enq select option { background: var(--ink); color: #fff; }
.enq ::placeholder { color: rgba(255, 255, 255, .5); opacity: 1; }
.enq input:focus, .enq select:focus, .enq textarea:focus {
  outline: none;
  border-color: #fff;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .18);
}
.enq [aria-invalid="true"] { border-color: #FF8A8F; box-shadow: 0 0 0 3px rgba(255, 138, 143, .2); }


.enq__trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.enq__send { align-self: flex-start; margin-top: 4px; background: #fff; color: var(--ink); }
.enq__send:hover { background: var(--accent); color: var(--on-accent); }
.enq__send[disabled] { opacity: .55; pointer-events: none; }

.enq__note { margin-top: 2px; min-height: 1.4em; line-height: 1.6; color: rgba(255, 255, 255, .8); }
.enq__note.is-ok  { color: #7BE8A6; }   /* 9.7:1 on the dark block */
.enq__note.is-bad { color: #FF8A8F; }


/* The bottom padding leaves room for the call and WhatsApp buttons. Scrolled
   all the way down, the legal line is the last thing on the page, and 28px
   alone put its two ends under the two buttons. */
.ftr {
  border-top: 1.5px solid var(--rule);
  padding-block: clamp(44px, 6vw, 76px) calc(28px + var(--fab) + var(--fab-in) + env(safe-area-inset-bottom, 0px));
  margin-top: clamp(40px, 6vw, 80px);
}
.ftr__grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr; gap: clamp(28px, 5vw, 64px); padding-bottom: 40px; }
.ftr img { height: 64px; width: auto; margin-bottom: 18px; }
.ftr h3 { font-size: 11.5px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 14px; }
.ftr a:hover { color: var(--accent-ink); }
.ftr__links li { margin-bottom: 9px; }
.ftr__legal {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 12px;
  padding-top: 22px;
  border-top: 1.5px solid var(--rule);
  font-size: 11.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3);
}


.shero { position: relative; overflow: hidden; padding-top: clamp(124px, 15vw, 180px); padding-bottom: clamp(44px, 6vw, 80px); }

.shero__n {
  position: absolute;
  right: clamp(0px, 2vw, 34px); top: 28%;
  z-index: 0;
  font-size: clamp(10rem, 24vw, 22rem);
  font-weight: 800; line-height: .75; letter-spacing: -.06em;
  color: color-mix(in srgb, var(--accent) 12%, transparent);
  pointer-events: none; user-select: none;
}
.shero > .wrap { position: relative; z-index: 1; }
.shero__crumb { display: flex; gap: 10px; align-items: center; font-size: 11.5px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-3); }
.shero__crumb a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 4px; }
.shero h1 { margin-block: clamp(20px, 2.6vw, 32px) clamp(18px, 2.2vw, 28px); }
.shero__lede { font-size: clamp(1.08rem, 1.6vw, 1.4rem); line-height: 1.46; max-width: 42ch; color: var(--ink-2); }
.shero__chips { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 30px; }


.sec { padding-block: clamp(52px, 7vw, 100px); }
.sec--band { background: var(--paper-2); }

.two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gut); }
.two--wide { gap: clamp(34px, 6vw, 96px); }

/* --- what you get ------------------------------------------------------- */
.dl li { display: flex; gap: 14px; align-items: flex-start; padding: 14px 0; border-bottom: 1.5px solid var(--rule); font-size: 16.5px; }
.dl svg { flex: none; margin-top: 5px; color: var(--accent-ink); transition: color .6s var(--ease); }

/* --- notes -------------------------------------------------------------- */
.notes { display: flex; flex-direction: column; gap: 24px; }
.notes li { padding-left: 20px; border-left: 3px solid var(--rule); transition: border-color .3s; }
.notes li:hover { border-left-color: var(--accent); }
.notes strong { display: block; margin-bottom: 5px; font-weight: 700; }
.notes span { color: var(--ink-2); font-size: 16px; }

/* --- specs -------------------------------------------------------------- */
.specs { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1px; background: var(--rule); border-radius: var(--r); overflow: hidden; }
.specs > div { background: var(--paper); padding: 26px 24px 32px; }
.sec--band .specs > div { background: var(--paper-2); }
.specs dt { font-size: 11.5px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 9px; }
.specs dd { margin: 0; font-family: var(--mono); font-size: 15px; }

/* --- steps -------------------------------------------------------------- */
.steps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(16px, 2.4vw, 30px); }
.steps p.steps__n {
  display: grid; place-items: center;
  width: 46px; aspect-ratio: 1; border-radius: 14px;
  background: var(--accent); color: var(--on-accent);
  font-size: 17px; font-weight: 800;
  margin-bottom: 16px;
  transition: background-color .6s var(--ease), color .6s var(--ease);
}
.steps h3 { margin-bottom: 8px; }
.steps p { color: var(--ink-2); font-size: 15px; }

/* --- technical figures -------------------------------------------------- */
.figure { overflow-x: auto; padding-bottom: 6px; }
.figure svg { display: block; }
.figwrap { display: flex; flex-wrap: wrap; gap: var(--gut); align-items: center; }
.figwrap__text { flex: 1 1 290px; min-width: 260px; display: flex; flex-direction: column; gap: 18px; }

/* --- pickers / panels --------------------------------------------------- */
.picker { display: flex; flex-wrap: wrap; gap: 9px; margin-bottom: 32px; }
.picker button {
  font-size: 12.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-2);
  border: 1.5px solid var(--rule); border-radius: 100px;
  padding: 10px 18px;
  transition: color .3s, border-color .3s, background-color .3s;
}
.picker button:hover { border-color: var(--ink); color: var(--ink); }
.picker button[aria-selected='true'] { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.panel[hidden] { display: none; }
.panel__meta { display: flex; flex-wrap: wrap; gap: 24px 48px; margin-top: 26px; }
.panel__meta p:last-child { font-family: var(--mono); font-size: 15px; }
.panel__note { margin-top: 20px; max-width: 62ch; color: var(--ink-2); font-size: 16.5px; }

/* --- faq ---------------------------------------------------------------- */
.faq { border-top: 1.5px solid var(--rule); }
.faq__item { border-bottom: 1.5px solid var(--rule); }
.faq__q {
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  width: 100%; text-align: left;
  padding-block: 24px;
  font-size: clamp(1.05rem, 1.6vw, 1.28rem); font-weight: 700; letter-spacing: -.025em;
  transition: color .3s;
}
.faq__q:hover { color: var(--accent-ink); }
.faq__q svg { flex: none; color: var(--accent-ink); transition: transform .35s var(--ease), color .6s var(--ease); }
.faq__q[aria-expanded='true'] svg { transform: rotate(45deg); }
.faq__a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .4s var(--ease); }
.faq__item.is-open .faq__a { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p { padding-bottom: 26px; max-width: 64ch; color: var(--ink-2); font-size: 16.5px; }

/* --- next service ------------------------------------------------------- */
.next { padding-bottom: clamp(30px, 4vw, 56px); }
.next > a {
  display: block;
  border-radius: var(--r);
  background: var(--c);
  color: var(--on);
  padding: clamp(28px, 4vw, 56px) clamp(24px, 3vw, 44px);
  transition: transform .5s var(--ease), box-shadow .5s var(--ease);
}
.next > a:hover { transform: translateY(-6px); box-shadow: 0 24px 44px -26px color-mix(in srgb, var(--c) 80%, transparent); }
.next__inner { display: flex; align-items: center; justify-content: space-between; gap: 28px; }
.next .eyebrow { color: inherit; opacity: .78; }
.next svg { flex: none; transition: transform .45s var(--ease); }
.next > a:hover svg { transform: translateX(12px); }

/* ==========================================================================
   Motion vocabulary. The CSS owns what each entrance looks like; motion.js
   only decides when. Every hiding rule sits behind .js so nothing can be
   left invisible if the script never runs.
   ========================================================================== */

.js [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  transition:
    opacity .8s var(--ease) var(--d, 0ms),
    transform .8s var(--ease) var(--d, 0ms),
    clip-path .9s var(--ease) var(--d, 0ms);
}
.js [data-reveal].is-in { opacity: 1; transform: none; }

/* uncovered from behind its own edge */
.js [data-reveal='mask'] { opacity: 1; transform: none; clip-path: inset(0 100% 0 0); }
.js [data-reveal='mask'].is-in { clip-path: inset(0 0 0 0); }

/* ink laid down top to bottom */
.js [data-reveal='wipe'] { opacity: 1; transform: none; clip-path: inset(0 0 100% 0); }
.js [data-reveal='wipe'].is-in { clip-path: inset(0 0 0 0); }

/* the frame arrives, the picture settles into it */
.js [data-reveal='settle'] { opacity: 0; transform: none; }
.js [data-reveal='settle'].is-in { opacity: 1; }
.js [data-reveal='settle'] > * { transform: scale(1.06); transition: transform 1.2s var(--ease) var(--d, 0ms); }
.js [data-reveal='settle'].is-in > * { transform: none; }

/* --- staggered children -------------------------------------------------- */
.js [data-stagger] { opacity: 1; transform: none; }
.js [data-stagger] > * {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  transition: opacity .75s var(--ease) var(--sd, 0ms), transform .75s var(--ease) var(--sd, 0ms);
}
.js [data-stagger].is-in > * { opacity: 1; transform: none; }

/* --- headings built out of masked lines ---------------------------------- */
.js [data-reveal='lines'] { opacity: 1; transform: none; }
.js [data-reveal='lines'] > * { opacity: 1; transform: none; transition: none; }
.js [data-reveal='lines'] .line > span {
  transform: translateY(105%);
  animation: none;
  transition: transform .9s var(--ease) var(--sd, 0ms);
}
.js [data-reveal='lines'].is-in .line > span { transform: none; }

/* --- headings split into characters -------------------------------------- */
/* motion.js wraps each character in .ch, grouped into a .wd per word.

   .wd has to be unbreakable: an inline-block per character otherwise gives
   the browser a break opportunity between every pair of letters, and a
   three-line headline re-wraps mid-word. */
.wd { display: inline-block; white-space: nowrap; }
.ch { display: inline-block; }
.js [data-reveal='chars'] { opacity: 1; transform: none; }
.js [data-reveal='chars'] .ch { transform: translateY(110%) rotate(3deg); transition: transform .85s var(--ease) var(--cd, 0ms); }
.js [data-reveal='chars'].is-in .ch { transform: none; }

/* --- scroll progress ----------------------------------------------------- */
.prog {
  position: fixed; top: 0; left: 0; right: 0; z-index: 130;
  height: 3px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  pointer-events: none;
  transition: background-color .6s var(--ease);
}

/* --- parallax ------------------------------------------------------------ */
/* motion.js writes --fy; the element only has to agree to use it. */
[data-float] { transform: translate3d(0, var(--fy, 0), 0); }

/* --- magnets ------------------------------------------------------------- */
[data-magnet] {
  transform: translate3d(var(--mx, 0), var(--my, 0), 0);
  transition: transform .4s var(--ease);
}
[data-magnet]:active { transition-duration: .08s; }

/* --- card tilt ----------------------------------------------------------- */
[data-tilt] {
  transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transform-style: preserve-3d;
  transition: transform .5s var(--ease);
}
/* the tiles already lift on hover; the two transforms cannot both own it */
.idx__row[data-tilt]:hover { transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(-7px); }

/* --- pictures ------------------------------------------------------------ */
/* One frame component for every photograph on the site. The aspect ratio is
   reserved before the file loads, so nothing on the page jumps when it does.
   Set --ar to width/height: 1.5 for 3:2, 0.75 for a portrait 3:4. */
.media {
  position: relative;
  overflow: hidden;
  border-radius: 16px;
  background: var(--paper-2);
  aspect-ratio: var(--ar, 1.5);
}
.media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }

/* A slow push while the picture is on screen. Scoped to a hover so it never
   runs on a phone, where it would only cost battery. */
.media--zoom img { transition: transform 1.1s var(--ease); }
.media--zoom:hover img { transform: scale(1.045); }

/* Waiting for a photograph. This has to look like a decision rather than a
   broken image: the frame, the hatching, and a plain note saying what
   belongs here. Drop a file in and the whole block goes away. */
.media--waiting {
  display: grid;
  place-items: center;
  background:
    repeating-linear-gradient(-45deg, transparent 0 11px, rgba(20, 20, 22, .05) 11px 22px),
    var(--paper-2);
}
.media--waiting .media__note {
  font: 700 .66rem/1.5 var(--f);
  letter-spacing: .09em; text-transform: uppercase;
  color: var(--ink-3); text-align: center;
  padding: 14px 18px; max-width: 26ch;
}
.media__cap {
  display: flex; justify-content: space-between; gap: 16px;
  margin-top: 11px;
  font: 700 .7rem/1.5 var(--f);
  letter-spacing: .05em;
  color: var(--ink-3);
}
.media__cap b { font-weight: 700; color: var(--ink-2); }
.media__note b { display: inline-block; margin-top: 6px; color: var(--ink-2); font-weight: 700; letter-spacing: .04em; }

/* --- the gallery --------------------------------------------------------- */
/* Columns rather than grid, because a grid row is as tall as its tallest
   item: mixed shapes leave holes under the short ones. Columns close up
   instead. */
.gallery { columns: 3; column-gap: clamp(16px, 2.2vw, 30px); }
.media-item { break-inside: avoid; -webkit-column-break-inside: avoid; width: 100%; margin: 0 0 clamp(16px, 2.2vw, 30px); }

/* ==========================================================================
   The work — index, grid, lightbox.
   ========================================================================== */

/* --- the client index ----------------------------------------------------- */
.widx { border-top: 1.5px solid var(--rule); }
.widx__row {
  position: relative;
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(14px, 2vw, 34px);
  padding-block: clamp(14px, 1.8vw, 24px);
  border-bottom: 1.5px solid var(--rule);
  transition: padding-left .5s var(--ease), color .3s var(--ease);
}
.widx__n { font-family: var(--mono); font-size: 11.5px; color: var(--ink-3); transition: color .3s var(--ease); }
.widx__name { font-size: clamp(1.4rem, 3.2vw, 2.6rem); font-weight: 800; line-height: 1.04; letter-spacing: -.038em; min-width: 0; }
.widx__work { font-size: 11px; font-weight: 700; letter-spacing: .11em; text-transform: uppercase; color: var(--ink-3); white-space: nowrap; transition: color .3s var(--ease); }

@media (hover: hover) and (pointer: fine) {
  .widx__row:hover { padding-left: clamp(12px, 1.6vw, 24px); color: var(--accent-ink); }
  .widx__row:hover .widx__n, .widx__row:hover .widx__work { color: var(--accent-ink); }
}
.widx__row:focus-visible { padding-left: clamp(12px, 1.6vw, 24px); color: var(--accent-ink); }

/* the preview that follows the cursor */
.widx__peek {
  position: fixed; top: 0; left: 0; z-index: 60;
  width: clamp(230px, 22vw, 330px);
  margin: 0;
  opacity: 0;
  pointer-events: none;
  transform: translate3d(var(--px, 0), var(--py, 0), 0) scale(.94);
  transition: opacity .3s var(--ease), transform .3s var(--ease);
}
.widx__peek img { width: 100%; height: auto; display: block; border-radius: 12px; background: var(--paper-2); box-shadow: 0 30px 60px -28px rgba(20, 20, 22, .55); }
.widx.is-peeking .widx__peek { opacity: 1; transform: translate3d(var(--px, 0), var(--py, 0), 0) scale(1); }

/* On a touch screen there is no hover to preview with, so each row carries a
   small picture of its own instead of promising one that never arrives. */
.widx__thumb { display: none; }
@media (hover: none), (pointer: coarse), (max-width: 860px) {
  .widx__peek { display: none; }
  .widx__row { grid-template-columns: 2.6rem minmax(0, 1fr) 68px; }
  .widx__thumb { display: block; }
  .widx__thumb img { width: 68px; height: 48px; object-fit: cover; border-radius: 6px; background: var(--paper-2); }
  .widx__work { display: none; }
}

/* --- the grid -------------------------------------------------------------- */
.wgrid { columns: 3; column-gap: clamp(14px, 1.8vw, 24px); }
.wcell { break-inside: avoid; -webkit-column-break-inside: avoid; width: 100%; margin: 0 0 clamp(18px, 2.2vw, 32px); }
.wcell__img { position: relative; overflow: hidden; border-radius: 14px; background: var(--paper-2); cursor: zoom-in; }
.wcell__img img { width: 100%; height: auto; display: block; transition: transform 1s var(--ease); }
@media (hover: hover) and (pointer: fine) { .wcell__img:hover img { transform: scale(1.035); } }
.wcell__img:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.wcell__cap { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; margin-top: 10px; }
.wcell__client { font-size: 15px; font-weight: 700; }
.wcell__work { font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); white-space: nowrap; }
.wcell[hidden] { display: none; }
@media (max-width: 1020px) { .wgrid { columns: 2; } }
@media (max-width: 620px)  { .wgrid { columns: 1; } }

/* --- google reviews ---------------------------------------------------------- */
/* The work grid's columns on a wide screen. On a phone they become a row you
   swipe along: six tall screenshots stacked in one column would be most of
   the page's scroll. The next card shows at the edge, so the row reads as
   one that moves. It runs to the screen edges and snaps to the page margin. */
/* Google's review screenshots are white, and on a white page they have no
   edge. The hairline says where each one starts and stops. */
.wgrid--reviews .wcell__img { box-shadow: 0 0 0 1px var(--rule-2); }
/* Columns balance by count, so two or four reviews in three columns left the
   third empty. Two columns fill evenly for those counts. */
@media (min-width: 1021px) {
  .wgrid--reviews:has(> .wcell:nth-child(2):last-child),
  .wgrid--reviews:has(> .wcell:nth-child(4):last-child) { columns: 2; }
}
@media (max-width: 620px) {
  .wgrid--reviews {
    columns: auto;
    display: flex; align-items: flex-start; gap: 12px;
    overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    margin-inline: calc(var(--pad) * -1);
    padding-inline: var(--pad);
    scroll-padding-inline: var(--pad);
    scrollbar-width: none;
    /* A scroller clips at its padding box, which cut the top off the focus
       ring. The padding gives the ring room; the margin takes it back. */
    padding-block: 6px; margin-block: -6px;
  }
  .wgrid--reviews::-webkit-scrollbar { display: none; }
  .wgrid--reviews .wcell { flex: 0 0 78%; margin: 0; scroll-snap-align: start; }
}

/* --- the filter ------------------------------------------------------------ */
.wfilter { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: clamp(24px, 3vw, 40px); }
.wfilter button {
  font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-2);
  border: 1.5px solid var(--rule); border-radius: 999px;
  padding: 10px 18px;
  transition: color .3s var(--ease), border-color .3s var(--ease), background-color .3s var(--ease);
}
.wfilter button b { font-weight: 700; color: var(--ink-3); margin-left: 5px; transition: color .3s var(--ease); }
.wfilter button:hover { border-color: var(--ink); color: var(--ink); }
.wfilter button.is-on { background: var(--ink); border-color: var(--ink); color: #fff; }
.wfilter button.is-on b { color: rgba(255, 255, 255, .64); }

/* --- the lightbox ---------------------------------------------------------- */
.lbox {
  position: fixed; inset: 0; z-index: 300;
  display: grid;
  /* minmax(0, 1fr), not 1fr. A bare 1fr is minmax(auto, 1fr), whose minimum
     is the content size — so a portrait photograph pushes the track taller
     than the viewport instead of being scaled down into it. Measured: a
     1511x1700 file rendered 1458px tall in an 820px window, running off the
     bottom of the screen. */
  grid-template-rows: minmax(0, 1fr) auto;
  background: rgba(10, 10, 12, .96);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  visibility: hidden;
  /* Hiding waits for the fade to finish; showing is instant.

     Transitioning visibility over the same .35s as the opacity leaves the
     computed value at `hidden` for the whole fade — and a visibility:hidden
     element refuses focus without raising anything. Measured: focus() called
     on the close button, computed visibility still `hidden`, activeElement
     still BODY. The keyboard was left out on the grid behind the overlay. */
  transition: opacity .35s var(--ease), visibility 0s linear .35s;
}
.lbox.is-open { opacity: 1; visibility: visible; transition: opacity .35s var(--ease), visibility 0s; }
/* Flex rather than grid centring, and that is the other half of the fix:
   the picture sizes itself with max-height: 100%, and a percentage only
   resolves against a definite height. A grid item lands in an auto-sized
   implicit row, so the percentage was circular and resolved to no limit at
   all. A flex container with a definite height gives it something real to
   measure against. */
.lbox__stage {
  display: flex; align-items: center; justify-content: center;
  min-height: 0;
  padding: clamp(46px, 5vw, 70px) clamp(16px, 5vw, 80px) 10px;
}
.lbox__stage img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; border-radius: 10px; transform: scale(.97); transition: transform .4s var(--ease); }
.lbox.is-open .lbox__stage img { transform: none; }
.lbox__bar {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 14px clamp(16px, 5vw, 80px) clamp(18px, 3vw, 30px);
  font-size: 11.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: rgba(255, 255, 255, .72);
}
.lbox__cap { color: #fff; }
.lbox__nav { display: flex; gap: 8px; }
.lbox button {
  color: #fff;
  border: 1.5px solid rgba(255, 255, 255, .3);
  border-radius: 50%;
  width: 42px; height: 42px;
  display: grid; place-items: center;
  transition: border-color .3s var(--ease), background-color .3s var(--ease), color .3s var(--ease);
}
.lbox button:hover { border-color: #fff; background: #fff; color: var(--ink); }
.lbox button:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.lbox__close { position: absolute; top: clamp(12px, 2vw, 22px); right: clamp(12px, 2vw, 22px); }

/* --- call and WhatsApp --------------------------------------------------------- */
/* Pinned to the bottom corners of every page: call on the left, WhatsApp on
   the right. Each is a plain link, so a tap goes straight to the dialer or
   into a WhatsApp chat, with or without the script.

   z-index 100 puts them over the page and under the drawer (110) and the
   lightbox (300). Both of those also hide them outright, which takes them
   out of the tab order as well as out of sight.

   Both keep a fixed colour. The call button is ink, like the phone pill in
   the header. It used to wear the running ink, and that made it vanish on
   every panel painted in the same ink: red on the red call-to-action panel,
   orange on the orange service tile. It also turned WhatsApp-green beside
   WhatsApp through the green sections. WhatsApp is green because people know
   it by the colour as much as by the glyph. It is the darkened green, not
   WhatsApp's own #25D366: white on that is 2:1 and the glyph washes out.
   White on #007E3A is 5.2:1.

   The white ring keeps each button's shape on anything: on the dark band, on
   the dark enquiry panel, on a green tile.

   The entrance is CSS, not motion.js. It needs no script to finish, so it
   cannot leave them invisible, which is the rule the .js gate exists for. */
.fabs {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 100;
  display: flex; justify-content: space-between; align-items: flex-end;
  padding: 0 var(--fab-in) calc(var(--fab-in) + env(safe-area-inset-bottom, 0px));
  /* the strip between the two buttons must not swallow taps on the page */
  pointer-events: none;
  /* Showing waits a moment. Moving from one form field to the next drops
     :focus for a single frame, and an instant show made the buttons visible
     and tappable, still at opacity 0, over the send button for 300ms. */
  transition: opacity .3s var(--ease) .12s, visibility 0s linear .12s;
}
.fab {
  pointer-events: auto;
  display: inline-flex; align-items: center;
  height: var(--fab); min-width: var(--fab);
  padding-inline: 16px;
  border-radius: 999px;
  font-size: 14.5px; font-weight: 700; white-space: nowrap;
  box-shadow: 0 0 0 2px #fff, 0 12px 28px -12px rgba(20, 20, 22, .6), 0 2px 6px rgba(20, 20, 22, .2);
  transition: background-color .35s var(--ease), color .35s var(--ease), transform .25s var(--ease);
  animation: fab-in .8s var(--ease) .45s backwards;
}
.fab svg { flex: none; }
.fab:active { transform: scale(.94); }
.fab--call { background: var(--ink); color: #fff; }
.fab--wa { background: var(--green-t); color: #fff; flex-direction: row-reverse; padding-inline: 15px; animation-delay: .6s; }
@keyframes fab-in { from { opacity: 0; transform: translateY(28px) scale(.6); } }

/* The label is folded away, which leaves a round icon button. It opens on a
   hover or a keyboard focus, and once, briefly, on the first page of a
   visit, when main.js adds .is-peek. Without the script they stay round,
   and the aria-label says what each one does either way. */
.fab__l {
  max-width: 0; overflow: hidden; opacity: 0;
  transition: max-width .55s var(--ease), opacity .3s var(--ease), margin .55s var(--ease);
}
.fabs.is-peek .fab__l,
.fab:focus-visible .fab__l { max-width: 9em; opacity: 1; margin-inline: 10px 6px; }
.fabs.is-peek .fab--wa .fab__l,
.fab--wa:focus-visible .fab__l { margin-inline: 6px 10px; }
@media (hover: hover) and (pointer: fine) {
  .fab:hover .fab__l { max-width: 9em; opacity: 1; margin-inline: 10px 6px; }
  .fab--wa:hover .fab__l { margin-inline: 6px 10px; }
  .fab--call:hover { background: var(--accent); color: var(--on-accent); }
  .fab--wa:hover { background: #006A31; }
}

/* They pass over white and over the dark band, so the ring is two rings:
   ink shows on white, and the white gap shows on the dark. */
.fab:focus-visible {
  outline: 3px solid var(--ink); outline-offset: 3px;
  box-shadow: 0 0 0 3px #fff, 0 12px 28px -12px rgba(20, 20, 22, .6);
}

/* Out of the way while the menu or a picture is open, and while someone is
   typing in the form. A phone keyboard lifts fixed buttons up over the
   fields. Hiding waits for the fade; showing is instant. */
body.menu-open .fabs,
body:has(.lbox.is-open) .fabs,
body:has(.enq :focus) .fabs {
  opacity: 0; visibility: hidden;
  transition: opacity .3s var(--ease), visibility 0s linear .3s;
}

/* --- responsive --------------------------------------------------------- */
@media (max-width: 1080px) {
  .nav { display: none; }
  .burger { display: flex; }
  .hdr__bar { justify-content: space-between; }
  .hdr__tel { display: none; }
  .idx { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .work { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .method__grid, .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 1000px) {
  .hero__grid { grid-template-columns: minmax(0, 1fr); gap: clamp(36px, 6vw, 56px); }
  .hero__lede { max-width: 56ch; }
  .studio__grid, .cta__grid--split { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 860px) {
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stat:nth-child(odd) { padding-left: var(--pad); }
  .stat:nth-child(even) { padding-right: var(--pad); border-right: 0; }
  .stat:nth-child(-n + 2) { border-bottom: 1px solid rgba(255, 255, 255, .15); }
  .two { grid-template-columns: minmax(0, 1fr); }
  .gallery { columns: 2; }
  .specs, .idx-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .shero__n { display: none; }
  .next__inner { flex-direction: column; align-items: flex-start; gap: 20px; }
}

@media (max-width: 640px) {
  body { font-size: 16px; }
  .idx, .method__grid, .steps, .specs, .idx-list { grid-template-columns: minmax(0, 1fr); }
  .work { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gallery { columns: 1; }
  .ftr__grid { grid-template-columns: minmax(0, 1fr); gap: 34px; }
  .deets > div { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .cta__actions { width: 100%; }
  .enq__row { grid-template-columns: minmax(0, 1fr); }
  .enq__send { width: 100%; justify-content: center; }
  .collage__1, .collage__2, .collage__3, .collage__4 { grid-column: span 6; aspect-ratio: 4 / 3; }
  .idx__num { font-size: 8rem; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  /* every variant, not just the default one — a clip-path left half closed
     would hide content just as completely as opacity 0 */
  .js [data-reveal],
  .js [data-stagger] > * { opacity: 1; transform: none; clip-path: none; }
  /* these have to out-specify the rules that hide them, so they are written
     at the same weight rather than relying on the cascade */
  .js .line > span,
  .js [data-reveal='lines'] .line > span { transform: none; }
  .js [data-reveal='chars'] .ch { transform: none; }
  .js [data-reveal='settle'] > * { transform: none; }
  [data-float], [data-magnet], [data-tilt] { transform: none; }
  .widx__peek { display: none; }
  .prog { display: none; }
  /* The rule above shortens the entrance but not its delay, and the delay
     is spent at the first keyframe, invisible. So the entrance goes
     entirely. */
  .fab { animation: none; }
}

@media print {
  .hdr, .drawer, .next, .prog, .fabs { display: none; }
  body { font-size: 11pt; }
}
