/* ==========================================================================
   MK EVOLUTION DETAILING — Design System
   Deep ocean + electric tail. Colours drawn from the client's reference
   painting: turquoise light up top falling into deep indigo, with a tail
   running aqua → electric blue → magenta → violet.

   The signature device is "tail": that same four-stop gradient, shifting the
   way colour-change wrap film does when you walk past it. It drives headline
   fills, card edges, step numerals, the logo and the portfolio placeholders.
   ========================================================================== */

/* --- 1. TOKENS ----------------------------------------------------------- */
:root {
  /* Surfaces — deep water. Dark enough that the tail colours fluoresce. */
  --bg-deep:      #060B1A;
  --bg-base:      #0A1228;
  --bg-elevated:  #0F1A38;
  --bg-raised:    #16244A;
  --surface:      rgba(127, 240, 228, 0.06);
  --surface-hi:   rgba(127, 240, 228, 0.12);

  /* Type — cool neutrals that sit correctly against blue, never muddy grey */
  --fg:           #EAF2FF;   /* 17.42:1 on --bg-deep */
  --fg-muted:     #A8B6D4;   /*  9.63:1 on --bg-deep */
  --fg-dim:       #8DA0C4;   /*  7.43:1 on --bg-deep — small uppercase labels
                                 need the full 4.5:1, so this is not decorative grey */

  /* Aqua — the secondary accent. Icons, focus rings, live highlights. */
  --aqua:      #7FF0E4;   /* 14.47:1 on --bg-deep */
  --aqua-mid:  #22D3EE;   /* 10.85:1 */
  --blue:      #4FA8FF;   /*  7.83:1 */
  --violet:    #A855F7;   /*  4.96:1 */

  /* Magenta — still the brand's loud note. Lives in the tail gradient,
     the headline fills, the logo and the hero's ambient light. Not on buttons. */
  --magenta:     #FF2D78;   /* 5.51:1 on --bg-deep */
  --magenta-hi:  #FF5C9E;
  --magenta-deep:#D91B5C;

  /* Action — cyan. Every CTA on the site.
     NOTE: white text on cyan fails badly (1.81:1) — it must be dark ink.
     Dark ink on #22D3EE reads 10.55:1, nearly double what the magenta
     button managed, so the CTA is now the highest-contrast element here.
     Hover brightens to #5FE8E0 (12.81:1); contrast only improves. */
  --action:      var(--aqua-mid);  /* #22D3EE — dark ink on it: 10.55:1 */
  --action-hot:  #5FE8E0;          /* hover — dark ink on it: 12.81:1 */
  --action-ink:  #0A0F1F;          /* text that sits ON cyan */
  --action-glow: rgba(34, 211, 238, 0.40);

  /* The tail — signature gradient. Every stop clears 3:1 as large text. */
  --flip-1: #7FF0E4;   /* aqua highlight   14.47:1 */
  --flip-2: #4FA8FF;   /* electric blue     7.83:1 */
  --flip-3: #FF3D8B;   /* magenta           5.88:1 */
  --flip-4: #A855F7;   /* violet            4.96:1 */
  --flip: linear-gradient(100deg,
          var(--flip-1) 0%, var(--flip-2) 30%,
          var(--flip-3) 64%, var(--flip-4) 100%);

  --border:      rgba(127, 240, 228, 0.18);
  --border-hi:   rgba(127, 240, 228, 0.38);

  /* Type scale — fluid, no media queries needed */
  --step--1: clamp(0.83rem, 0.79rem + 0.18vw, 0.94rem);
  --step-0:  clamp(1rem, 0.95rem + 0.24vw, 1.13rem);
  --step-1:  clamp(1.2rem, 1.1rem + 0.5vw, 1.5rem);
  --step-2:  clamp(1.5rem, 1.3rem + 1vw, 2.1rem);
  --step-3:  clamp(1.95rem, 1.6rem + 1.7vw, 3rem);
  --step-4:  clamp(2.5rem, 1.9rem + 3vw, 4.5rem);
  --step-5:  clamp(3rem, 2rem + 5.4vw, 7.5rem);

  /* Space */
  --sp-1: 0.5rem;  --sp-2: 0.75rem; --sp-3: 1rem;   --sp-4: 1.5rem;
  --sp-5: 2rem;    --sp-6: 3rem;    --sp-7: 4rem;   --sp-8: 6rem;
  --sp-9: 8rem;

  --radius:    14px;
  --radius-lg: 22px;
  --shell:     1240px;

  /* Motion — one easing curve everywhere */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --dur:  340ms;

  --font-display: 'Archivo', system-ui, sans-serif;
  --font-body:    'Space Grotesk', system-ui, sans-serif;

  --header-h: 76px;   /* raised from 68 for the larger shield mark */
}

/* --- 2. RESET ------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  scroll-behavior: smooth;
  /* Offset anchor targets so the sticky header never covers a heading */
  scroll-padding-top: calc(var(--header-h) + 16px);
  -webkit-text-size-adjust: 100%;
  /* Belt-and-braces against sideways scroll on phones. Note this does NOT
     rescue position:fixed children — those must not be parked off-screen
     horizontally in the first place (see .drawer). */
  overflow-x: hidden;
}

body {
  background: var(--bg-deep);
  color: var(--fg);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  /* Room for the mobile sticky call bar */
  padding-bottom: env(safe-area-inset-bottom);
}

img, svg, video { display: block; max-width: 100%; height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
h1, h2, h3, h4 { font-family: var(--font-display); line-height: 1.02; font-weight: 800; }

a { color: inherit; text-decoration: none; }

/* Visible focus for every keyboard user. Never removed. */
:focus-visible {
  outline: 2px solid var(--flip-1);
  outline-offset: 3px;
  border-radius: 4px;
}

::selection { background: var(--magenta); color: var(--action-ink); }

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

/* Skip link — first tab stop */
.skip {
  position: absolute; top: -100px; left: var(--sp-3); z-index: 200;
  background: var(--aqua); color: var(--action-ink); padding: 0.7rem 1.1rem;
  border-radius: 0 0 10px 10px; font-weight: 700; transition: top 180ms var(--ease);
}
.skip:focus { top: 0; }

/* --- 3. LAYOUT ----------------------------------------------------------- */
.shell { width: min(100% - 2.5rem, var(--shell)); margin-inline: auto; }
.section { padding-block: clamp(4rem, 9vw, 8rem); position: relative; }

.eyebrow {
  font-family: var(--font-body);
  font-size: 0.75rem; font-weight: 700;
  letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--fg-dim);
  display: flex; align-items: center; gap: 0.7rem;
  margin-bottom: var(--sp-3);
}
.eyebrow::before {
  content: ''; width: 30px; height: 2px; border-radius: 2px;
  background: var(--flip); flex: none;
}

.h-sec {
  font-size: var(--step-4);
  letter-spacing: -0.035em;
  text-transform: uppercase;
  max-width: 18ch;
}
.lede {
  color: var(--fg-muted); font-size: var(--step-1);
  max-width: 58ch; margin-top: var(--sp-4); line-height: 1.55;
}

/* --- 4. THE FLIP (signature) --------------------------------------------- */
/* Large display text only — gradient text needs size to stay legible, and
   at these sizes the 3:1 large-text contrast bar is cleared by every stop. */
.flip-text {
  background: var(--flip);
  background-size: 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: flipShift 9s var(--ease) infinite alternate;
}
@keyframes flipShift {
  from { background-position: 0% 50%; }
  to   { background-position: 100% 50%; }
}

.flip-rule { height: 2px; border: 0; background: var(--flip); border-radius: 2px; opacity: 0.85; }

/* Film-grain veil — 1 tiny inline SVG, keeps flat dark areas from banding */
.grain::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  opacity: 0.16; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
}

/* --- 5. BUTTONS ---------------------------------------------------------- */
.btn {
  --btn-bg: var(--action);
  display: inline-flex; align-items: center; justify-content: center;
  gap: 0.6rem;
  /* 52px tall — comfortably past the 44px touch minimum */
  min-height: 52px; padding: 0 1.6rem;
  /* Near-black ink on gold — 9.42:1, and the richer look than white-on-gold */
  background: var(--btn-bg); color: var(--action-ink);
  border: 0; border-radius: 100px;
  font-family: var(--font-body); font-weight: 700;
  font-size: var(--step-0); letter-spacing: -0.01em;
  cursor: pointer; position: relative; isolation: isolate;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              background var(--dur) var(--ease);
  box-shadow: 0 6px 22px -6px var(--action-glow);
  text-align: center;
}
.btn:hover { background: var(--action-hot); transform: translateY(-2px); box-shadow: 0 14px 34px -8px var(--action-glow); }
.btn:active { transform: translateY(0) scale(0.98); }

.btn--ghost {
  background: transparent; box-shadow: none;
  border: 1px solid var(--border-hi); color: var(--fg);
}
.btn--ghost:hover { background: var(--surface-hi); border-color: var(--fg-dim); transform: translateY(-2px); }

.btn--lg { min-height: 60px; padding: 0 2.1rem; font-size: var(--step-1); }
.btn svg { flex: none; }

/* Pulse ring on the primary phone CTA — draws the eye without moving layout */
.btn--call::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  border: 2px solid var(--action); z-index: -1;
  animation: ring 2.6s var(--ease) infinite;
}
@keyframes ring {
  0%        { opacity: 0.7; transform: scale(1); }
  70%, 100% { opacity: 0;   transform: scale(1.28); }
}

/* --- 6. HEADER ----------------------------------------------------------- */
.header {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  height: var(--header-h);
  display: flex; align-items: center;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              backdrop-filter var(--dur) var(--ease);
  border-bottom: 1px solid transparent;
}
.header[data-stuck='true'] {
  background: rgba(8, 8, 10, 0.82);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border-bottom-color: var(--border);
}
/* No width here — .shell already sets it. Declaring width:100% would win on
   source order and push the logo/CTA to the viewport edges, out of alignment
   with every section below. */
.header__in { display: flex; align-items: center; gap: var(--sp-4); }

.logo { display: flex; align-items: center; gap: 0.65rem; font-family: var(--font-display); font-weight: 900; }
.logo__mark { width: 46px; height: 46px; flex: none; object-fit: contain; }
/* Single-line wordmark — the subtitle was removed, so this is the whole
   lockup and can carry more weight than the old two-line version. */
.logo__txt {
  font-size: 1.35rem;
  letter-spacing: -0.045em;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
}
/* Strapline under the wordmark.
   0.5em, not a fixed rem — that's exactly half the parent's size and it keeps
   that ratio automatically at every breakpoint below, where .logo__txt shrinks.
   Body font at 500 against the display font at 900 is what makes it read
   thinner; dropping size alone would still look heavy. */
.logo__txt span {
  display: block;
  font-family: var(--font-body);
  /* 0.5em = exactly half the wordmark, which is what was asked for. But the
     wordmark steps down to 0.95rem on small phones, and half of that is 7.6px
     — too small to actually read. max() keeps the exact-half ratio wherever
     there's room and floors it at 10px where there isn't. */
  font-size: max(10px, 0.5em);
  font-weight: 500;
  letter-spacing: 0.16em;
  line-height: 1.2;
  color: var(--fg-dim);
  margin-top: 4px;
}

.nav { display: flex; gap: var(--sp-5); margin-left: auto; }
.nav a {
  font-size: 0.87rem; font-weight: 600; color: var(--fg-muted);
  position: relative; padding: 0.35rem 0; transition: color var(--dur) var(--ease);
}
.nav a::after {
  content: ''; position: absolute; left: 0; bottom: 0; height: 2px; width: 100%;
  background: var(--flip); border-radius: 2px;
  transform: scaleX(0); transform-origin: right;
  transition: transform var(--dur) var(--ease);
}
.nav a:hover { color: var(--fg); }
.nav a:hover::after { transform: scaleX(1); transform-origin: left; }

.header__cta { margin-left: var(--sp-4); }

/* --- Social icons -------------------------------------------------------- */
/* Sits between the nav and the call button. The links are 38px boxes around
   19px glyphs: the box is the tap target (and the hover surface), the glyph
   is what you see. */
.social { display: flex; align-items: center; gap: 4px; margin-left: var(--sp-3); }
.social a {
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border-radius: 10px;
  color: var(--fg-muted);
  border: 1px solid transparent;
  transition: color var(--dur) var(--ease),
              background var(--dur) var(--ease),
              border-color var(--dur) var(--ease);
}
.social a:hover,
.social a:focus-visible {
  color: var(--fg);
  background: var(--surface);
  border-color: var(--border);
}

/* Measured, not guessed: with the icons in, logo + nav + icons + call button
   need 1010px before the call button starts pushing past the shell's right
   edge (at 1024px it lands exactly on it, with zero slack). 1080px gives the
   row real breathing room and hands the job to the drawer copy below that.
   Re-measure this if the wordmark or the nav items change length. */
@media (max-width: 1080px) { .social { display: none; } }


.burger {
  display: none; margin-left: auto;
  width: 46px; height: 46px; background: var(--surface);
  border: 1px solid var(--border); border-radius: 12px;
  cursor: pointer;
  /* Flex column with an explicit gap gives a deterministic 7px pitch
     (2px bar + 5px gap) — which is exactly what the ±7px translate in the
     open state needs to converge the bars into a clean X.
     `grid` + `place-items:center` spread the three rows across the whole
     46px button (~15.7px pitch), so the bars never met and the "close"
     icon rendered as a chevron instead of an X. */
  flex-direction: column; align-items: center; justify-content: center; gap: 5px;
}
.burger span { display: block; width: 19px; height: 2px; background: var(--fg); border-radius: 2px;
  transition: transform 260ms var(--ease), opacity 200ms var(--ease); }
.burger[aria-expanded='true'] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger[aria-expanded='true'] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded='true'] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* The wordmark is long. Step it down before it can collide with the burger. */
@media (max-width: 940px) { .logo__txt { font-size: 1.15rem; } }
@media (max-width: 420px) {
  .logo__mark { width: 38px; height: 38px; }
  .logo__txt  { font-size: 0.95rem; letter-spacing: -0.05em; }
}

/* Mobile drawer
   IMPORTANT: the closed state must never translate horizontally.
   This element is position:fixed, so its containing block is the viewport and
   body{overflow-x:hidden} does NOT clip it — on iOS/Android a drawer parked at
   translateX(100%) sits at x = 100vw..200vw, doubles the effective page width,
   and the phone zooms out to fit, showing only the left half of the site.
   Desktop engines happen to clip it, which is why this only broke on phones.
   Fade + a short vertical slide gives the same feel with zero overflow. */
.drawer {
  position: fixed; inset: var(--header-h) 0 0 0; z-index: 99;
  background: rgba(6, 11, 26, 0.97);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  padding: var(--sp-5) 0 var(--sp-8);
  display: flex; flex-direction: column; gap: var(--sp-2);
  opacity: 0; transform: translateY(-12px);
  visibility: hidden; pointer-events: none;
  transition: opacity 300ms var(--ease), transform 300ms var(--ease), visibility 300ms;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.drawer[data-open='true'] {
  opacity: 1; transform: none; visibility: visible; pointer-events: auto;
}
/* The column lives on .shell, not .drawer.
   .drawer's only child is the .shell wrapper, so flex-direction:column on the
   drawer stacks that single div and does nothing to the links inside it —
   they stay inline and run together on one line. The flex context has to be
   on the element that actually contains the <a>s. */
.drawer .shell {
  display: flex;
  flex-direction: column;
}
.drawer a {
  display: block;                /* belt-and-braces: never inline */
  font-family: var(--font-display); font-size: var(--step-2);
  text-transform: uppercase; letter-spacing: -0.03em;
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--border);
  min-height: 52px;              /* comfortable thumb target */
}
/* The call button block at the bottom of the drawer is not a nav link */
.drawer .hero__actions { margin-top: var(--sp-5); }
.drawer .hero__actions a { border-bottom: 0; padding: 0; }

/* Phone copy, inside the drawer. Two equal buttons on one row.
   Same specificity as `.drawer a` (0,1,1 both), so this has to come after it
   in the file — otherwise that rule's display:block wins and the icon stacks
   on top of the word instead of sitting beside it. */
.drawer__social { display: flex; gap: var(--sp-2); margin-top: var(--sp-4); }
.drawer__social a {
  display: flex; align-items: center; justify-content: center; gap: 0.55rem;
  flex: 1; min-height: 52px;
  padding: 0;
  border: 1px solid var(--border);
  border-bottom: 1px solid var(--border);   /* overrides the divider rule above */
  border-radius: 12px;
  background: var(--surface);
  color: var(--fg-muted);
  font-size: 0.9rem; font-weight: 600;
}
.drawer__social a:hover { color: var(--fg); }

/* --- 7. HERO ------------------------------------------------------------- */
/* =========================================================================
   HERO BACKDROP — PHOTO vs GRADIENT  (how to switch)
   -------------------------------------------------------------------------
   In index.html the hero is:   <section class="hero grain" data-photo="on">

     data-photo="on"   photo backdrop, gradient glow dimmed behind it
     data-photo="off"  ORIGINAL gradient-only look, exactly as before

   That one attribute is the whole switch. Nothing is deleted to turn the
   photo on — the original colours below are untouched and still active, the
   photo simply layers over them. Flip it back any time.

   ORIGINAL GRADIENT VALUES (for reference — these are still live):
     page background   --bg-deep  #060B1A
     blob 1  --flip-2 electric blue  58vw  opacity .55
     blob 2  --flip-1 aqua           46vw  opacity .38
     blob 3  --magenta               44vw  opacity .45
     blob 4  --flip-4 violet         34vw  opacity .34
   With data-photo="on" the blobs are dimmed via --blob-scale (see below);
   their colours and sizes are not changed.

   Photo tuning knobs — all on :root, safe to adjust:
     (the image file itself is the <img src> in index.html)
     --hero-photo-opacity  how strong the photo reads      (default .34)
     --hero-photo-dim      darkness of the tint over it    (default .74)
     --hero-photo-pos      framing, e.g. "center 60%"
   ========================================================================= */
:root {
  /* the file itself is set on the <img> in index.html, not here */
  --hero-photo-opacity: .52;   /* was .34 — photo reads noticeably stronger */
  --hero-photo-dim: .60;       /* was .74 — lighter wash over it */
  --hero-photo-pos: center 58%;
  --blob-scale: 1;            /* 1 = original glow strength */
}

.hero {
  position: relative; min-height: 100svh;
  display: grid; align-items: center;
  padding-top: calc(var(--header-h) + var(--sp-6));
  padding-bottom: var(--sp-7);
  overflow: hidden;
}
.hero__bg { position: absolute; inset: -10% 0 0 0; z-index: 0; }

/* Photo layer. Hidden unless data-photo="on".
   If the image file is missing the element simply renders transparent and
   you see the original gradient — no broken-image state, ever. */
.hero__photo {
  display: none;
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden;
}
.hero__photo img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: var(--hero-photo-pos);
  opacity: var(--hero-photo-opacity);
  /* Desaturate slightly so the shop's real-world colours don't fight the
     site's cyan/magenta palette. */
  /* less desaturation than before so the shop's colour comes through */
  filter: grayscale(.14) contrast(1.08) brightness(.96);
}
/* Dark wash directly over the photo — this is what makes the headline
   readable regardless of what's in the picture. */
.hero__photo::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(180deg,
      rgba(6,11,26,calc(var(--hero-photo-dim) * .85)) 0%,
      rgba(6,11,26,calc(var(--hero-photo-dim) * .55)) 45%,
      rgba(6,11,26,var(--hero-photo-dim)) 100%),
    /* Text-protection column. The headline lives on the left, so this stays
       strong there and falls away to almost nothing on the right — that's how
       the photo gets brighter without costing any headline legibility. */
    linear-gradient(90deg,
      rgba(6,11,26,.88) 0%,
      rgba(6,11,26,.72) 26%,
      rgba(6,11,26,.20) 62%,
      rgba(6,11,26,.06) 100%);
}

.hero[data-photo='on'] .hero__photo { display: block; }
/* Pull the glow back so it reads as light ON the photo, not a competing wash */
.hero[data-photo='on'] { --blob-scale: .45; }
/* Ambient light blobs — slow drift, transform only */
/* Underwater light. Larger + brighter than a typical ambient wash so the
   tail colours actually register on a phone screen in daylight. */
.blob {
  position: absolute; border-radius: 50%; filter: blur(75px);
  /* multiplied by --blob-scale so photo mode dims the whole glow with one
     number, without altering any of these individual values */
  opacity: calc(0.55 * var(--blob-scale));
  will-change: transform;
}
.blob--1 { width: 58vw; height: 58vw; background: var(--flip-2); top: -12%; left: -14%;
           animation: drift1 22s ease-in-out infinite alternate; }
.blob--2 { width: 46vw; height: 46vw; background: var(--flip-1); top: 18%;  right: -12%;
           opacity: calc(0.38 * var(--blob-scale)); animation: drift2 27s ease-in-out infinite alternate; }
/* Pinned to magenta, not --action: the buttons went cyan, but the hero's
   ambient light should keep the painting's pink glow. */
.blob--3 { width: 44vw; height: 44vw; background: var(--magenta); bottom: -16%; left: 26%;
           opacity: calc(0.45 * var(--blob-scale)); animation: drift1 19s ease-in-out infinite alternate-reverse; }
.blob--4 { width: 34vw; height: 34vw; background: var(--flip-4); top: 44%; left: 8%;
           opacity: calc(0.34 * var(--blob-scale)); animation: drift2 24s ease-in-out infinite alternate-reverse; }
@keyframes drift1 { to { transform: translate3d(8%, 10%, 0) scale(1.14); } }
@keyframes drift2 { to { transform: translate3d(-10%, 6%, 0) scale(1.1); } }

/* Vignette keeps text legible over any photo dropped in behind it */
.hero__veil {
  position: absolute; inset: 0; z-index: 2;
  background:
    radial-gradient(120% 80% at 50% 0%, transparent 20%, rgba(5,5,6,0.55) 70%, var(--bg-deep) 100%),
    linear-gradient(180deg, rgba(5,5,6,0.35) 0%, transparent 30%, rgba(5,5,6,0.9) 92%);
}
.hero__in { position: relative; z-index: 3; }

.hero h1 {
  font-size: var(--step-5);
  letter-spacing: -0.05em;
  text-transform: uppercase;
  max-width: 15ch;
}
.hero h1 .line { display: block; overflow: hidden; }
.hero h1 .line > span { display: block; }

.hero__sub {
  color: var(--fg-muted); font-size: var(--step-1);
  max-width: 46ch; margin-top: var(--sp-4);
}
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-6); }

.hero__scroll {
  position: absolute; bottom: var(--sp-5); left: 50%; z-index: 3;
  transform: translateX(-50%);
  display: grid; justify-items: center; gap: 0.5rem;
  font-size: 0.68rem; letter-spacing: 0.24em; text-transform: uppercase; color: var(--fg-dim);
}
.hero__scroll i {
  display: block; width: 1px; height: 42px; background: linear-gradient(var(--fg-dim), transparent);
  animation: scrollHint 2.2s var(--ease) infinite;
  transform-origin: top;
}
@keyframes scrollHint { 0%,100% { transform: scaleY(0.4); opacity: 0.3; } 50% { transform: scaleY(1); opacity: 1; } }

/* --- 8. MARQUEE ---------------------------------------------------------- */
/* Seamless infinite marquee.
   The trick is geometry, not timing. TWO identical tracks sit side by side and
   both slide left by exactly 100% of their OWN width. When track 1 finishes
   fully off-screen, track 2 has landed precisely where track 1 started — so
   the loop restart is invisible and the strip never runs empty.
   The seam gap is the track's own padding-right, NOT a gap on .marquee:
   a parent gap is not included in the track's width, so translateX(-100%)
   would undershoot by exactly that gap and visibly jump each cycle. */
.marquee {
  border-block: 1px solid var(--border);
  background: var(--bg-base); overflow: hidden; padding-block: var(--sp-3);
  display: flex; gap: 0;
  /* Fade the ends so it reads as continuous, not clipped */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track {
  display: flex; align-items: center; gap: var(--sp-5); flex: none;
  padding-right: var(--sp-5);      /* becomes the seam between the two tracks */
  animation: slide 34s linear infinite; will-change: transform;
}
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes slide {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}
.marquee__item {
  display: flex; align-items: center; gap: var(--sp-3);
  font-family: var(--font-display); font-weight: 700; font-size: 0.95rem;
  text-transform: uppercase; letter-spacing: 0.05em; color: var(--fg-dim); white-space: nowrap;
}
.marquee__item::after { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--action); }

/* --- 9. STATS ------------------------------------------------------------ */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--border);
  border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; }
.stat { background: var(--bg-base); padding: var(--sp-5) var(--sp-4); text-align: center; }
.stat__n {
  font-family: var(--font-display); font-weight: 900;
  font-size: var(--step-3); letter-spacing: -0.04em; line-height: 1;
  display: block;
}
.stat__l { font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--fg-dim); margin-top: 0.6rem; }

/* --- 10. SERVICES -------------------------------------------------------- */
/* 320px min lands on 3 columns at full shell width — six cards fill two clean
   rows instead of orphaning a short third row. */
.svc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--sp-3); margin-top: var(--sp-7); }
.svc {
  position: relative; isolation: isolate; overflow: hidden;
  background: var(--bg-elevated);
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: var(--sp-5);
  transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
/* Iridescent edge that wakes on hover — the film catching light */
.svc::before {
  content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit; padding: 1px;
  background: var(--flip);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0; transition: opacity var(--dur) var(--ease);
}
.svc:hover { transform: translateY(-5px); }
.svc:hover::before { opacity: 1; }
.svc:focus-within::before { opacity: 1; }

.svc__ico {
  width: 46px; height: 46px; border-radius: 12px;
  display: grid; place-items: center; margin-bottom: var(--sp-4);
  background: var(--surface); border: 1px solid var(--border); color: var(--aqua);
}
.svc h3 { font-size: var(--step-2); letter-spacing: -0.03em; text-transform: uppercase; }
.svc p  { color: var(--fg-muted); margin-top: var(--sp-2); font-size: var(--step--1); line-height: 1.6; }
.svc__list { list-style: none; padding: 0; margin: var(--sp-4) 0 0; display: grid; gap: 0.45rem; }
.svc__list li { display: flex; gap: 0.55rem; font-size: var(--step--1); color: var(--fg-muted); }
.svc__list li::before { content: '—'; color: var(--action); flex: none; }
.svc__price { margin-top: var(--sp-4); padding-top: var(--sp-3); border-top: 1px solid var(--border);
  font-size: var(--step--1); color: var(--fg-dim); }
.svc__price b { color: var(--fg); font-family: var(--font-display); font-size: var(--step-1); letter-spacing: -0.02em; }

/* --- 11. PORTFOLIO ------------------------------------------------------- */
.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: var(--sp-5); }
.chip {
  min-height: 44px; padding: 0 1.15rem;
  background: transparent; border: 1px solid var(--border); border-radius: 100px;
  color: var(--fg-muted); font-size: 0.85rem; font-weight: 600; cursor: pointer;
  transition: all var(--dur) var(--ease);
}
.chip:hover { border-color: var(--border-hi); color: var(--fg); }
.chip[aria-pressed='true'] { background: var(--fg); color: var(--bg-deep); border-color: var(--fg); }

/* ---- gallery: two view modes ------------------------------------------
   .gal-wrap[data-view="grid"]     -> normal wrapping grid (a category filter)
   .gal-wrap[data-view="carousel"] -> one horizontal row, 3 across, arrows ("All")
   main.js sets data-view when a filter chip is clicked. */
.gal-wrap { position: relative; margin-top: var(--sp-5); }

.gal { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--sp-3); }

/* CAROUSEL. Built on native scroll-snap rather than a JS animation loop:
   trackpad, touch swipe, shift+wheel and keyboard all work for free, and if
   JS ever fails it degrades to a plain scrollable row instead of breaking. */
.gal-wrap[data-view='carousel'] .gal {
  display: flex;
  gap: var(--sp-3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;              /* Firefox */
  -ms-overflow-style: none;
  /* room so the lifted hover state isn't clipped by the scroll container */
  padding: 6px 2px 10px;
}
.gal-wrap[data-view='carousel'] .gal::-webkit-scrollbar { display: none; }

.gal-wrap[data-view='carousel'] .gal__item {
  /* --per-view is set per breakpoint below */
  flex: 0 0 calc((100% - (var(--per-view) - 1) * var(--sp-3)) / var(--per-view));
  scroll-snap-align: start;
  /* Force one shared aspect in the row. The portrait shots are 4:5 in grid
     mode, but mixed heights in a single flex row look broken. */
  aspect-ratio: 4 / 3;
}

:root { --per-view: 3; }

/* Arrows */
.gal-nav {
  position: absolute; top: 50%; z-index: 5;
  transform: translateY(-50%);
  width: 52px; height: 52px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(10, 18, 40, 0.88);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  border: 1px solid var(--border-hi);
  color: var(--fg); cursor: pointer;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease),
              opacity var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.gal-nav:hover { background: var(--action); color: var(--action-ink);
  border-color: var(--action); transform: translateY(-50%) scale(1.06); }
.gal-nav:active { transform: translateY(-50%) scale(0.96); }
.gal-nav--prev { left: -18px; }
.gal-nav--next { right: -18px; }

/* Hidden entirely in grid mode, and greyed out at the ends of the row */
.gal-wrap[data-view='grid'] .gal-nav { display: none; }
.gal-nav[disabled] { opacity: 0.28; pointer-events: none; }
.gal__item {
  position: relative; overflow: hidden; border-radius: var(--radius-lg);
  border: 1px solid var(--border); background: var(--bg-elevated);
  aspect-ratio: 4 / 3;
  transition: transform 420ms var(--ease), opacity 300ms var(--ease);
}
.gal__item[hidden] { display: none; }
.gal__item--tall { aspect-ratio: 4 / 5; }
.gal__item:hover { transform: translateY(-4px); }

/* Placeholder that looks deliberate: iridescent film swatch until a photo lands */
.gal__ph { position: absolute; inset: 0; background: var(--flip); background-size: 220% 220%;
  animation: flipShift 12s var(--ease) infinite alternate; opacity: 0.55; }
.gal__ph::after { content: ''; position: absolute; inset: 0;
  background: linear-gradient(135deg, rgba(5,5,6,0.25), rgba(5,5,6,0.8)); }
.gal__item img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform 700ms var(--ease); }
.gal__item:hover img { transform: scale(1.06); }

.gal__meta {
  position: absolute; inset: auto 0 0 0; z-index: 2;
  padding: var(--sp-5) var(--sp-4) var(--sp-4);
  background: linear-gradient(transparent, rgba(5,5,6,0.92));
  transform: translateY(12px); opacity: 0;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.gal__item:hover .gal__meta, .gal__item:focus-within .gal__meta { transform: translateY(0); opacity: 1; }
.gal__meta h3 { font-size: var(--step-1); text-transform: uppercase; letter-spacing: -0.02em; }
.gal__meta p { font-size: 0.78rem; color: var(--fg-muted); letter-spacing: 0.08em; text-transform: uppercase; }
/* On touch there is no hover — always show the caption */
@media (hover: none) {
  .gal__meta { transform: none; opacity: 1; }
}


/* Carousel: how many cards fit, per breakpoint. Arrows tuck inside the row
   once there's no outside gutter left for them. */
@media (max-width: 1100px) {
  :root { --per-view: 2; }
  .gal-nav--prev { left: 6px; }
  .gal-nav--next { right: 6px; }
}
@media (max-width: 620px) {
  /* 1.15 rather than 1 — the sliver of the next card is what tells people
     there's more to swipe, which arrows alone don't communicate on touch. */
  :root { --per-view: 1.15; }
  .gal-nav { width: 44px; height: 44px; }
  .gal-nav--prev { left: 2px; }
  .gal-nav--next { right: 2px; }
}

/* --- 12. SPLIT / WHY ----------------------------------------------------- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-8); align-items: center; }
.why-list { list-style: none; padding: 0; margin: var(--sp-6) 0 0; display: grid; gap: var(--sp-4); }
.why-list li { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-3); align-items: start; }
.why-list svg { color: var(--action); margin-top: 3px; }
.why-list b { display: block; font-family: var(--font-display); font-size: var(--step-1);
  text-transform: uppercase; letter-spacing: -0.02em; }
.why-list span { color: var(--fg-muted); font-size: var(--step--1); }

.media-card {
  position: relative; border-radius: var(--radius-lg); overflow: hidden;
  border: 1px solid var(--border); aspect-ratio: 4 / 5; background: var(--bg-elevated);
}
.media-card img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* --- 13. TESTIMONIALS ---------------------------------------------------- */
/* Multi-column, not grid. Reviews vary a lot in length — one is four lines,
   another is one. In a grid every card in a row stretches to the tallest,
   leaving big empty gaps. Columns let each card be its own height and flow
   naturally, and 5 items don't leave an orphan the way 4-up grid would. */
.quotes { columns: 3; column-gap: var(--sp-3); margin-top: var(--sp-7); }
.quote { background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--sp-5);
  display: block;
  break-inside: avoid;              /* never split a review across columns */
  -webkit-column-break-inside: avoid;
  margin-bottom: var(--sp-3); }
.quote__stars { display: flex; gap: 2px; color: var(--flip-4); }
.quote p { font-size: var(--step-0); line-height: 1.6; margin-block: var(--sp-3) var(--sp-4); }
.quote footer { display: flex; align-items: center; gap: var(--sp-3); }

/* Google CTA under the reviews */
.reviews-cta { margin-top: var(--sp-6); text-align: center; }
.reviews-note { color: var(--fg-dim); font-size: var(--step--1); margin-top: var(--sp-3); }

@media (max-width: 1000px) { .quotes { columns: 2; } }
@media (max-width: 640px)  { .quotes { columns: 1; } }
.quote__av { width: 40px; height: 40px; border-radius: 50%; background: var(--flip);
  display: grid; place-items: center; font-family: var(--font-display); font-weight: 900;
  color: var(--bg-deep); flex: none; }
.quote__who b { display: block; font-size: 0.9rem; }
.quote__who span { font-size: 0.76rem; color: var(--fg-dim); }

/* --- 14. FAQ ------------------------------------------------------------- */
.faq { margin-top: var(--sp-6); border-top: 1px solid var(--border); }
.faq details { border-bottom: 1px solid var(--border); }
.faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-4) 0; cursor: pointer; list-style: none;
  font-family: var(--font-display); font-size: var(--step-1);
  text-transform: uppercase; letter-spacing: -0.02em;
  min-height: 44px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ''; flex: none; width: 12px; height: 12px;
  border-right: 2px solid var(--action); border-bottom: 2px solid var(--action);
  transform: rotate(45deg) translateY(-3px);
  transition: transform var(--dur) var(--ease);
}
.faq details[open] summary::after { transform: rotate(-135deg) translateY(-3px); }
.faq details p { color: var(--fg-muted); padding-bottom: var(--sp-4); max-width: 70ch; }

/* --- 15. LOCATION -------------------------------------------------------- */
.loc { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-6); margin-top: var(--sp-6); }
.loc__card { background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--sp-5); }
/* Appointment-only. Replaced the old day-by-day hours table — the shop
   schedules around each booking, so a fixed weekly grid would be wrong. */
.appt {
  display: flex; align-items: center; gap: 0.6rem;
  margin-top: var(--sp-3);
  font-family: var(--font-display); font-weight: 800;
  font-size: var(--step-2); letter-spacing: -0.03em;
  text-transform: uppercase; line-height: 1;
}
.appt svg { color: var(--aqua); flex: none; }
.appt-note {
  color: var(--fg-muted); font-size: var(--step--1);
  margin-top: var(--sp-2); max-width: 42ch;
}

.map { border-radius: var(--radius-lg); overflow: hidden; border: 1px solid var(--border);
  min-height: 320px; background: var(--bg-elevated); position: relative; }
.map iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%; border: 0;
  /* No colour filter — stock Google map. Inverting it looked bad over
     real tiles, so the map keeps its native colours. */
}

/* --- 16. FOOTER ---------------------------------------------------------- */
.footer { border-top: 1px solid var(--border); background: var(--bg-base);
  padding-block: var(--sp-7) var(--sp-6); margin-top: var(--sp-6); }
.footer__grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr; gap: var(--sp-6); }
.footer h4 { font-size: 0.75rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--fg-dim); font-family: var(--font-body); font-weight: 700; margin-bottom: var(--sp-3); }
.footer ul { list-style: none; padding: 0; display: grid; gap: 0.6rem; }
.footer a { color: var(--fg-muted); font-size: var(--step--1); transition: color var(--dur) var(--ease); }
.footer a:hover { color: var(--fg); }
.footer__bar { margin-top: var(--sp-6); padding-top: var(--sp-4); border-top: 1px solid var(--border);
  display: flex; flex-wrap: wrap; gap: var(--sp-3); justify-content: space-between;
  font-size: 0.78rem; color: var(--fg-dim); }

/* --- 17. STICKY MOBILE CALL BAR ------------------------------------------ */
/* The primary conversion path on phones. Always reachable, thumb-height. */
.callbar {
  position: fixed; inset: auto 0 0 0; z-index: 95;
  display: none; gap: 0.6rem; padding: 0.6rem 0.9rem;
  padding-bottom: calc(0.6rem + env(safe-area-inset-bottom));
  background: rgba(8, 8, 10, 0.93);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--border);
  transform: translateY(110%);
  transition: transform 380ms var(--ease);
}
.callbar[data-show='true'] { transform: translateY(0); }
.callbar .btn { flex: 1; min-height: 50px; padding: 0 1rem; font-size: 0.95rem; }

/* --- 18. REVEAL ---------------------------------------------------------- */
/* Set by JS only when IntersectionObserver is supported, so content is never
   trapped invisible if the script fails to run. */
.js-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 700ms var(--ease), transform 700ms var(--ease);
  transition-delay: var(--d, 0ms);
}
.js-reveal [data-reveal].is-in { opacity: 1; transform: none; }

/* --- 19. RESPONSIVE ------------------------------------------------------ */
@media (max-width: 1024px) {
  .split, .loc { grid-template-columns: 1fr; gap: var(--sp-6); }
  .footer__grid { grid-template-columns: 1fr 1fr; }
  .stats { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 860px) {
  .nav, .header__cta { display: none; }
  .burger { display: flex; }
  .callbar { display: flex; }
  /* Keep the last section clear of the fixed call bar */
  body { padding-bottom: 86px; }
  .hero { min-height: 92svh; }
  .hero__scroll { display: none; }
}
@media (max-width: 560px) {
  .shell { width: min(100% - 1.75rem, var(--shell)); }
  .footer__grid { grid-template-columns: 1fr; }
  .hero__actions .btn { width: 100%; }
  .gal { grid-template-columns: 1fr; }
  .gal__item--tall { aspect-ratio: 4 / 3; }
}

/* --- 20. REDUCED MOTION -------------------------------------------------- */
/* Honour the OS setting: kill decorative motion, keep everything readable. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .js-reveal [data-reveal] { opacity: 1 !important; transform: none !important; }
  .blob { animation: none; }
  .marquee__track { animation: none; }
}

/* --- 21. PRINT ----------------------------------------------------------- */
@media print {
  .header, .callbar, .drawer, .hero__scroll, .marquee, .blob { display: none !important; }
  body { background: #fff; color: #000; }
}
