@charset "utf-8";
/* ==========================================================================
   NIALEEM — one stylesheet, no framework.

   CONTENTS
   00  Design tokens  ← EDIT COLOURS, FONTS AND SPACING HERE
   01  Reset & base
   02  Typography helpers
   03  Buttons
   04  Loader
   05  Navigation
   06  Hero
   07  Sections & headings
   08  About
   09  Service cards
   10  Package card (web + graphic design)
   11  Portfolio
   12  Testimonials
   13  FAQ accordion
   14  Contact & form
   15  Footer
   16  Gallery lightbox
   17  Reveal animations
   18  Reduced motion / print
   ========================================================================== */


/* ==========================================================================
   00 · DESIGN TOKENS   ⬅⬅⬅  START HERE
   Change a value once and it updates everywhere on the site.
   ========================================================================== */
:root{

  /* ---- Brand colours -------------------------------------------------- */
  /* BLUE is the site colour and stands for WEB DESIGN.                     */
  --brand:        #3D9BF0;   /* glows, borders, decorative accents          */
  --brand-text:   #6BB6F7;   /* links and small accent text (readable)      */
  --brand-rgb:    61,155,240;
  --btn-a:        #1E6EC2;   /* button gradient — top-left                  */
  --btn-b:        #12518F;   /* button gradient — bottom-right              */


  /* ---- Surfaces -------------------------------------------------------
     Cards sit a clear step ABOVE the page, not a whisper above it. If cards
     ever look like they're melting into the background again, raise these
     two values before touching anything else.                              */
  --bg:           #080B12;   /* page background (never pure black)          */
  --bg-alt:       #0C111A;   /* alternating section background              */
  --card:         #151D2C;   /* card background                             */
  --card-2:       #1D2739;   /* raised / hovered card                       */

  /* ---- Text ----------------------------------------------------------- */
  --ink:          #E9EEF6;   /* headings and body                           */
  --ink-2:        #A3B0C2;   /* secondary copy                              */
  /* Lifted when the card surfaces were raised — on the lighter cards the
     old #7C8AA0 fell to 4.28:1, just under the 4.5:1 minimum.              */
  --ink-3:        #8996AC;   /* labels, captions                            */

  /* ---- Lines ---------------------------------------------------------- */
  --line:         rgba(255,255,255,.12);
  --line-2:       rgba(255,255,255,.20);

  /* ---- Type ----------------------------------------------------------- */
  /* HK Grotesk is already in /webfonts — nothing loads from the internet.
     To swap fonts, change these two lines (and add the @font-face if new). */
  --font:      'HK_Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-alt:  'HK_Grotesk_alt', var(--font);

  /* ---- Rhythm --------------------------------------------------------- */
  --wrap:      1240px;                        /* max content width          */
  --gutter:    clamp(20px, 5vw, 40px);        /* page side padding          */
  --sec-y:     clamp(56px, 6.2vw, 88px);      /* space BELOW each section   */
  --sec-top:   clamp(46px, 5vw, 74px);        /* space ABOVE each section   */
  --radius:    18px;
  --radius-sm: 12px;
  --radius-btn:9px;                           /* buttons — not pills        */

  /* ---- Motion --------------------------------------------------------- */
  --ease:      cubic-bezier(.16,1,.3,1);      /* expo-out: the premium one  */
  --fast:      .18s;
  --mid:       .34s;
  --slow:      .7s;
  /* How long one hero image dissolves into the next. The gap between
     slides is set separately, in js/site.js (var DELAY).                   */
  --hero-fade: 1.9s;

  /* ---- Depth ---------------------------------------------------------- */
  --shadow:    0 1px 2px rgba(0,0,0,.5), 0 16px 40px -14px rgba(0,0,0,.9);
  --shadow-lg: 0 2px 4px rgba(0,0,0,.5), 0 40px 72px -26px rgba(0,0,0,.95);
  --glow:      0 0 0 1px rgba(61,155,240,.28), 0 18px 50px -18px rgba(30,110,194,.55);

  --nav-h:     74px;
}

/* HK Grotesk — files already live in /webfonts */
@font-face{ font-family:'HK_Grotesk'; font-display:swap; font-weight:400; font-style:normal;
  src:url('../webfonts/hkgrotesk-regular-webfont.woff2') format('woff2'),
      url('../webfonts/hkgrotesk-regular-webfont.woff') format('woff'); }
@font-face{ font-family:'HK_Grotesk'; font-display:swap; font-weight:400; font-style:italic;
  src:url('../webfonts/hkgrotesk-italic-webfont.woff2') format('woff2'),
      url('../webfonts/hkgrotesk-italic-webfont.woff') format('woff'); }
@font-face{ font-family:'HK_Grotesk'; font-display:swap; font-weight:600; font-style:normal;
  src:url('../webfonts/hkgrotesk-semibold-webfont.woff2') format('woff2'),
      url('../webfonts/hkgrotesk-semibold-webfont.woff') format('woff'); }
@font-face{ font-family:'HK_Grotesk_alt'; font-display:swap; font-weight:400; font-style:normal;
  src:url('../webfonts/hkgrotesk-regular-webfont-alt.woff2') format('woff2'),
      url('../webfonts/hkgrotesk-regular-webfont-alt.woff') format('woff'); }


/* ==========================================================================
   01 · RESET & BASE
   ========================================================================== */
*,*::before,*::after{ box-sizing:border-box; }
*{ margin:0; }

html{
  scroll-behavior:smooth;
  scroll-padding-top:calc(var(--nav-h) + 12px);
  -webkit-text-size-adjust:100%;
}

body{
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font);
  font-size:clamp(1rem, .96rem + .2vw, 1.0625rem);   /* 16 → 17px */
  line-height:1.72;
  font-weight:400;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
  /* Very fine noise so large dark areas don't band or look plasticky */
  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='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.028'/%3E%3C/svg%3E");
}

body.is-locked{ overflow:hidden; }

img,svg,video{ display:block; max-width:100%; }
img{ height:auto; }

a{ color:var(--brand-text); text-decoration:none; }

button,input,textarea,select{ font:inherit; color:inherit; }
button{ background:none; border:0; cursor:pointer; }

ul{ list-style:none; padding:0; }

::selection{ background:rgba(61,155,240,.32); color:#fff; }

/* Focus ring — visible, on brand, never removed */
:focus-visible{
  outline:2px solid var(--brand);
  outline-offset:3px;
  border-radius:4px;
}

.skip-link{
  position:fixed; top:10px; left:10px; z-index:9999;
  padding:12px 20px; border-radius:999px;
  background:var(--brand-text); color:#04070c; font-weight:600;
  transform:translateY(-160%); transition:transform var(--mid) var(--ease);
}
.skip-link:focus{ transform:translateY(0); }

.wrap{
  width:100%; max-width:var(--wrap);
  margin-inline:auto;
  padding-inline:var(--gutter);
}
.wrap--narrow{ max-width:900px; }

/* Screen-reader only */
.sr{ position:absolute!important; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }


/* ==========================================================================
   02 · TYPOGRAPHY HELPERS
   ========================================================================== */
h1,h2,h3,h4{
  font-weight:600;
  line-height:1.1;
  letter-spacing:-.025em;
  text-wrap:balance;
}
p{ text-wrap:pretty; }

/* "Established 2003" mark — the legacy signal at the top of About.
   Small, set in caps with wide tracking, so it reads as a maker's mark
   rather than as a marketing claim. */
.estab{
  display:flex; align-items:center; flex-wrap:wrap;
  gap:12px;
  /* Scales down rather than wrapping onto a second line, but never below
     11px — the tracking gives way first, because losing letter-spacing costs
     far less legibility than shrinking the type. */
  font-size:clamp(.69rem, .5rem + .5vw, .79rem);
  letter-spacing:clamp(0.5px, 0.1px + 0.13vw, 2.3px);
  margin-bottom:clamp(22px,3vw,34px);
  font-weight:600;
  text-transform:uppercase;
  color:var(--ink-3);
  line-height:1.5;
  white-space:nowrap;
}
.estab__rule{
  width:clamp(16px,5vw,54px); height:1px; flex:none;
  background:linear-gradient(90deg,transparent,var(--brand));
}
.estab strong{
  font-weight:600;
  color:var(--brand-text);
  font-variant-numeric:tabular-nums;
}
.estab__sep{ opacity:.45; }

.lead{
  font-size:clamp(1.6rem, 1.05rem + 2.4vw, 2.9rem);
  line-height:1.22;
  letter-spacing:-.03em;
  font-weight:600;
  max-width:19ch;
  margin-bottom:clamp(40px,6vw,68px);
}
.lead em{
  font-style:normal;
  background:linear-gradient(100deg,var(--brand-text),#A9D4FF 55%,var(--brand-text));
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
}


/* ==========================================================================
   03 · BUTTONS
   ========================================================================== */
.btn{
  --btn-y:15px;
  position:relative;
  display:inline-flex; align-items:center; justify-content:center; gap:10px;
  min-height:52px;                       /* comfortably above the 44px min */
  padding:var(--btn-y) 30px;
  border-radius:var(--radius-btn);
  font-weight:600; font-size:1rem; letter-spacing:.005em;
  text-align:center; white-space:nowrap;
  cursor:pointer; overflow:hidden;
  transition:transform var(--fast) var(--ease),
             box-shadow var(--mid) var(--ease),
             background-color var(--mid) var(--ease),
             border-color var(--mid) var(--ease);
  will-change:transform;
}
.btn:active{ transform:scale(.97); }

.btn--primary{
  color:#fff;
  background:linear-gradient(135deg,var(--btn-a),var(--btn-b));
  box-shadow:0 1px 0 rgba(255,255,255,.18) inset,
             0 10px 30px -12px rgba(30,110,194,.9);
}
/* Sheen that sweeps across on hover */
.btn--primary::after{
  content:''; position:absolute; inset:0;
  background:linear-gradient(115deg,transparent 30%,rgba(255,255,255,.28) 50%,transparent 70%);
  transform:translateX(-130%);
  transition:transform .8s var(--ease);
}
.btn--primary:hover{ box-shadow:0 1px 0 rgba(255,255,255,.22) inset, 0 16px 44px -12px rgba(45,140,235,1); }
.btn--primary:hover::after{ transform:translateX(130%); }

.btn--ghost{
  color:var(--ink);
  border:1px solid var(--line-2);
  background:rgba(255,255,255,.03);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
}
.btn--ghost:hover{ border-color:var(--brand); background:rgba(61,155,240,.1); }

.btn--block{ display:flex; width:100%; }

/* Loading state used by the contact form */
.btn__spin{
  width:18px; height:18px; border-radius:50%;
  border:2px solid rgba(255,255,255,.35); border-top-color:#fff;
  display:none; animation:spin .7s linear infinite;
}
.btn.is-busy{ pointer-events:none; opacity:.75; }
.btn.is-busy .btn__spin{ display:block; }
@keyframes spin{ to{ transform:rotate(360deg); } }


/* ==========================================================================
   04 · LOADER
   ========================================================================== */
.loader{
  position:fixed; inset:0; z-index:9000;
  display:grid; place-items:center;
  background:var(--bg);
  transition:opacity .5s var(--ease), visibility .5s;
}
.loader.is-done{ opacity:0; visibility:hidden; }
.loader__mark{ display:grid; gap:20px; justify-items:center; }
.loader__mark img{ width:150px; opacity:.9; }
.loader__bar{ width:150px; height:2px; background:var(--line); border-radius:2px; overflow:hidden; }
.loader__bar span{
  display:block; height:100%; width:40%;
  background:linear-gradient(90deg,transparent,var(--brand),transparent);
  animation:load 1.05s var(--ease) infinite;
}
@keyframes load{ from{ transform:translateX(-120%);} to{ transform:translateX(320%);} }


/* ==========================================================================
   05 · NAVIGATION
   ========================================================================== */
.nav{
  position:fixed; inset:0 0 auto 0; z-index:900;
  padding-top:env(safe-area-inset-top);
  transition:transform var(--mid) var(--ease), background var(--mid) var(--ease);
}
.nav::before{                       /* the frosted panel, faded in on scroll */
  content:''; position:absolute; inset:0;
  background:rgba(8,11,18,.72);
  backdrop-filter:blur(16px) saturate(150%);
  -webkit-backdrop-filter:blur(16px) saturate(150%);
  border-bottom:1px solid var(--line);
  opacity:0; transition:opacity var(--mid) var(--ease);
}
.nav.is-stuck::before{ opacity:1; }
.nav.is-hidden{ transform:translateY(-100%); }

.nav__inner{
  position:relative; z-index:2;
  display:flex; align-items:center; gap:20px;
  height:var(--nav-h);
  max-width:var(--wrap); margin-inline:auto;
  padding-inline:var(--gutter);
}
.nav__logo img{ width:150px; height:auto; }
.nav__logo{
  margin-right:auto;
  display:flex; align-items:center; min-height:46px;   /* full tap target */
  transition:opacity var(--fast);
}
.nav__logo:hover{ opacity:.75; }

.nav__links{ display:flex; align-items:center; gap:4px; }
.nav__home{ display:none; }   /* shown only in the mobile menu */
.nav__links a{
  position:relative;
  padding:10px 14px;
  color:var(--ink-2); font-size:.95rem; font-weight:500;
  border-radius:999px;
  transition:color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.nav__links a::after{                       /* underline that grows from the middle */
  content:''; position:absolute; left:14px; right:14px; bottom:4px; height:1.5px;
  background:var(--brand); border-radius:2px;
  transform:scaleX(0); transform-origin:50%;
  transition:transform var(--mid) var(--ease);
}
.nav__links a:hover{ color:var(--ink); }
.nav__links a:hover::after,
.nav__links a.is-current::after{ transform:scaleX(1); }
.nav__links a.is-current{ color:var(--ink); }

.nav__links a.nav__cta{
  margin-left:10px;
  border-radius:var(--radius-btn);
  padding:11px 22px!important;
  color:#fff!important;
  background:linear-gradient(135deg,var(--btn-a),var(--btn-b));
  box-shadow:0 8px 22px -12px rgba(30,110,194,.95);
  transition:transform var(--fast) var(--ease), box-shadow var(--mid) var(--ease);
}
.nav__cta::after{ display:none; }
.nav__cta:hover{ transform:translateY(-1px); box-shadow:0 14px 30px -12px rgba(45,140,235,1); }

.nav__tools{ display:flex; align-items:center; gap:10px; }

/* Burger (mobile only) */
.burger{
  display:none;
  width:44px; height:44px; border-radius:50%;
  border:1px solid var(--line-2); background:rgba(255,255,255,.03);
  place-items:center; align-content:center; justify-items:center; gap:5px;
}
.burger span{
  display:block; width:18px; height:1.7px; border-radius:2px; background:var(--ink);
  transition:transform var(--mid) var(--ease), opacity var(--fast);
}
.burger[aria-expanded="true"] span:first-child{ transform:translateY(3.35px) rotate(45deg); }
.burger[aria-expanded="true"] span:last-child{ transform:translateY(-3.35px) rotate(-45deg); }

/* Scroll progress hairline */
.nav__progress{
  position:absolute; left:0; bottom:0; height:2px; width:100%;
  transform:scaleX(0); transform-origin:0 50%;
  background:linear-gradient(90deg,var(--btn-b),var(--brand),#A9D4FF);
  z-index:3;
}


/* ==========================================================================
   06 · HERO
   --------------------------------------------------------------------------
   Only two things crossfade: the photographs, and the wording that sits in
   .hero__rotator. Everything else — the wash, the glow, the tagline and the
   scroll cue — is drawn once and stays put.

   The three wording blocks share a single grid cell, so the rotator is as tall
   as the longest of them and the tagline underneath never moves.
   ========================================================================== */
.hero{
  position:relative;
  min-height:100svh;
  display:grid; place-items:center;
  padding:calc(var(--nav-h) + 26px) var(--gutter) var(--hero-foot);
  overflow:hidden;
  isolation:isolate;
  /* Room reserved at the bottom for .hero__bottom. Overridden per breakpoint. */
  --hero-foot:104px;
}

/* --- the photographs ----------------------------------------------------- */
.hero__slides{ position:absolute; inset:0; z-index:0; }

.hero__slide{
  position:absolute; inset:0;
  opacity:0; visibility:hidden;
  /* Long, linear dissolve. Linear (not eased) is what makes a crossfade read
     as a soft dissolve rather than a switch — eased curves spend too long
     near full opacity and you see both images fighting in the middle. */
  transition:opacity var(--hero-fade) linear, visibility var(--hero-fade);
}
.hero__slide.is-active{ opacity:1; visibility:visible; }

.hero__img{
  position:absolute; inset:0;
  background-size:cover; background-position:center;
  filter:saturate(1.18) contrast(1.06);   /* this is a design site — let the
                                             photography actually show */
  transform:scale(1.06);
  transition:transform 7s linear;    /* slow drift, roughly one slide's life */
}
.hero__slide.is-active .hero__img{ transform:scale(1.14); }

/* --- the wash, drawn once over all the photographs ----------------------- */
/* Deliberately much lighter than a blanket overlay: heavy only at the very
   top (under the nav) and at the very bottom (where it meets the page
   colour), and thin across the middle so the photograph keeps its colour.
   Because it sits on .hero rather than on each slide, it stays exactly the
   same density all the way through a crossfade. */
.hero::before{
  content:''; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    linear-gradient(180deg,
      rgba(8,11,18,.82) 0%,
      rgba(8,11,18,.34) 22%,
      rgba(8,11,18,.30) 55%,
      rgba(8,11,18,.62) 82%,
      var(--bg) 100%),
    radial-gradient(105% 62% at 50% 50%, transparent 30%, rgba(8,11,18,.42) 100%);
}

/* --- the words ----------------------------------------------------------- */
.hero__content{
  position:relative; z-index:3; isolation:isolate;
  max-width:900px; width:100%;
  text-align:center;
}
/* A soft pool of darkness behind the words. This is what allows the wash to
   be light enough to see the photograph: the contrast is won locally, right
   under the text, instead of by dimming the whole image. */
.hero__content::before{
  content:''; position:absolute; z-index:-1; pointer-events:none;
  inset:-16% -10%;
  background:radial-gradient(58% 58% at 50% 50%,
    rgba(6,9,15,.78) 0%, rgba(6,9,15,.55) 52%, rgba(6,9,15,0) 100%);
}

/* all three wording blocks occupy the same cell */
.hero__rotator{ display:grid; }
/* The wording hands over in ONE move.

   It used to run three animations at once — this block over 1.9s, plus the
   eyebrow and the headline each sliding 26px on their own delays. Between the
   old fade-out ending and the fade-in starting there was a 100ms window with
   nothing on screen at all. That stutter is what read as "not smooth".

   Now: the outgoing block fades out over .5s and the incoming one begins at
   exactly .5s. No blank gap, no two headlines ghosting together, no sliding. */
.hero__copy{
  grid-area:1 / 1;
  opacity:0; visibility:hidden;
  transition:opacity .5s ease-in, visibility .5s;
}
.hero__copy.is-active{
  opacity:1; visibility:visible;
  transition:opacity .9s ease-out .5s, visibility 0s;
}

/* This line carries the message, so it gets a pale blue plate rather than the
   near-invisible grey pill it had. Text is white for maximum legibility over
   whatever photo sits behind it. */
.hero__eyebrow{
  display:inline-flex; align-items:center; gap:10px;
  margin-bottom:22px; padding:9px 20px;
  border:1px solid rgba(109,183,250,.42);
  border-radius:999px;
  /* Blue tint over a dark backing. The backing is what guarantees the white
     text stays readable no matter how bright the photo behind it is. */
  background:linear-gradient(135deg, rgba(61,155,240,.32), rgba(61,155,240,.18)),
             rgba(8,11,18,.55);
  backdrop-filter:blur(14px) saturate(140%);
  -webkit-backdrop-filter:blur(14px) saturate(140%);
  box-shadow:0 0 0 1px rgba(8,11,18,.25),
             0 8px 26px -10px rgba(30,110,194,.85),
             inset 0 1px 0 rgba(255,255,255,.22);
  color:#fff;
  font-size:.8rem; font-weight:600;
  letter-spacing:.13em; text-transform:uppercase; line-height:1.4;
}
/* small pulsing dot, so the plate reads as "live" rather than a static label */
.hero__eyebrow::before{
  content:''; flex:none;
  width:6px; height:6px; border-radius:50%;
  background:#BFE0FF;
  box-shadow:0 0 0 3px rgba(191,224,255,.22);
}

.hero__title{
  font-size:clamp(2.6rem, 1.15rem + 6.4vw, 5.9rem);
  letter-spacing:-.045em;
  line-height:1.04;
  margin-bottom:0;
  color:#fff;
  /* Solid white with a soft shadow rather than a gradient fill — a gradient
     can't take a text-shadow, and the shadow is what lets the wash behind be
     light enough to see the photograph. */
  text-shadow:0 2px 18px rgba(4,7,12,.85), 0 1px 3px rgba(4,7,12,.7);
}



/* ambient light blobs */
.hero__glow{ position:absolute; inset:0; z-index:2; pointer-events:none; overflow:hidden; }
.hero__glow i{
  position:absolute; display:block; border-radius:50%;
  filter:blur(90px); opacity:.4;
}
.hero__glow i:nth-child(1){
  width:min(52vw,620px); aspect-ratio:1; left:-12%; top:8%;
  background:radial-gradient(circle,rgba(30,110,194,.9),transparent 68%);
  animation:drift1 22s ease-in-out infinite alternate;
}
.hero__glow i:nth-child(2){
  width:min(46vw,540px); aspect-ratio:1; right:-10%; bottom:2%;
  background:radial-gradient(circle,rgba(61,155,240,.65),transparent 68%);
  animation:drift2 27s ease-in-out infinite alternate;
}
@keyframes drift1{ to{ transform:translate3d(14%,10%,0) scale(1.16); } }
@keyframes drift2{ to{ transform:translate3d(-12%,-9%,0) scale(1.12); } }

/* The hero's bottom cluster. Only the scroll cue lives here now — the slides
   advance by themselves and the two buttons have been removed. */
.hero__bottom{
  position:absolute; z-index:3;
  left:50%; transform:translateX(-50%);
  bottom:calc(22px + env(safe-area-inset-bottom));
  display:flex; justify-content:center;
}

/* Scroll cue — a small outlined circle with a down arrow, gently bouncing. */
.hero__scroll{
  position:relative;
  width:44px; height:44px;
  display:grid; place-items:center;
  color:rgba(255,255,255,.55);
  transition:color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.hero__scroll::before{                 /* the ring */
  content:''; position:absolute; inset:5px;
  border:1px solid rgba(255,255,255,.28);
  border-radius:50%;
  transition:border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.hero__scroll span{                    /* the arrow, drawn in CSS */
  position:relative;
  width:7px; height:7px;
  margin-top:-2px;
  border-right:1.5px solid currentColor;
  border-bottom:1.5px solid currentColor;
  transform:rotate(45deg);
}
.hero__scroll{ animation:cueBounce 2.4s var(--ease) infinite; }
@keyframes cueBounce{
  0%,72%,100%{ transform:translateY(0); }
  82%        { transform:translateY(5px); }
  91%        { transform:translateY(1px); }
}
.hero__scroll:hover{ color:#fff; }
.hero__scroll:hover::before{ border-color:var(--brand); background:rgba(61,155,240,.14); }


/* ==========================================================================
   07 · SECTIONS & HEADINGS
   ========================================================================== */
/* Sections carry less air above their heading than below their content —
   the heading reads as attached to what follows it, and the page is tighter
   overall. Change --sec-top for the gap above, --sec-y for the gap below. */
.section{
  position:relative;
  padding-top:var(--sec-top);
  padding-bottom:var(--sec-y);
}
.section--alt{ background:var(--bg-alt); }
/* soft gradient seam instead of a hard 1px rule */
.section--alt::before,
.section--alt::after{
  content:''; position:absolute; left:0; right:0; height:1px;
  background:linear-gradient(90deg,transparent,var(--line-2) 20%,var(--line-2) 80%,transparent);
}
.section--alt::before{ top:0; }
.section--alt::after{ bottom:0; }

.shead{ max-width:640px; margin-bottom:clamp(30px,3.6vw,48px); }
.shead--center{ margin-inline:auto; text-align:center; }
.shead--center .shead__sub{ margin-inline:auto; }
.shead--center .shead__eyebrow::before{ display:none; }
.shead__eyebrow{
  display:inline-block; margin-bottom:16px;
  font-size:.78rem; font-weight:600;
  letter-spacing:.16em; text-transform:uppercase;
  color:var(--brand-text);
}
.shead__eyebrow::before{
  content:''; display:inline-block;
  width:26px; height:1px; margin-right:12px; vertical-align:middle;
  background:var(--brand-text); opacity:.6;
}
.shead__title{
  font-size:clamp(2.05rem,1.4rem + 2.6vw,3.3rem);
  margin-bottom:18px;
}
.shead__sub{ color:var(--ink-2); font-size:clamp(1rem,.97rem + .3vw,1.14rem); }


/* ==========================================================================
   08 · ABOUT
   ========================================================================== */
.about__grid{
  display:grid; gap:clamp(30px,4vw,56px);
  grid-template-columns:1fr;
}
.about__col{
  position:relative;
  padding-left:26px;
}
.about__col::before{                          /* thin gradient rule per column */
  content:''; position:absolute; left:0; top:6px; bottom:6px; width:2px;
  border-radius:2px;
  background:linear-gradient(180deg,var(--brand),transparent);
}
.about__h{ font-size:clamp(1.2rem,1.1rem + .5vw,1.45rem); margin-bottom:14px; }
.about__col p{ color:var(--ink-2); }
.about__col p + p{ margin-top:16px; }


/* ==========================================================================
   09 · SERVICE CARDS
   --------------------------------------------------------------------------
   The two cards are intentionally NOT identical. Each sets its own --accent
   and every coloured part of the card reads from it, so changing one line
   re-themes the whole card.
        .card--web      blue   · square icon · ticked checklist
        .card--graphic  blue   · round icon  · tag chips
   ========================================================================== */
.cards{ display:grid; gap:clamp(20px,2.6vw,30px); grid-template-columns:1fr; }

.card{
  /* default accent = the site blue; --accent-rgb is the same colour in
     r,g,b form so it can be used inside rgba() for tints */
  --accent:var(--brand-text);
  --accent-rgb:var(--brand-rgb);

  position:relative;
  padding:clamp(28px,3.4vw,44px);
  border:1px solid var(--line);
  border-radius:var(--radius);
  box-shadow:var(--shadow);
  overflow:hidden;
  transition:border-color var(--mid) var(--ease),
             box-shadow var(--mid) var(--ease);
}
/* top hairline highlight — the thing that stops cards looking flat */
.card::before{
  content:''; position:absolute; inset:0 0 auto 0; height:1px;
  background:linear-gradient(90deg,transparent,rgba(var(--accent-rgb),.55) 30%,rgba(var(--accent-rgb),.55) 70%,transparent);
}
/* glow that follows the cursor */
.card::after{
  content:''; position:absolute; inset:-1px; pointer-events:none;
  background:radial-gradient(320px circle at var(--mx,50%) var(--my,0%), rgba(var(--accent-rgb),.16), transparent 62%);
  opacity:0; transition:opacity var(--mid) var(--ease);
}
.card:hover{ border-color:rgba(var(--accent-rgb),.34); box-shadow:var(--shadow-lg); }
.card:hover::after{ opacity:1; }

/* --- Card 1: blue, light pooling from the top-left ----------------------- */
.card--web{
  --accent:var(--brand-text);
  --accent-rgb:var(--brand-rgb);
  background:
    radial-gradient(120% 100% at 0% 0%, rgba(61,155,240,.10), transparent 58%),
    linear-gradient(165deg,var(--card-2),var(--card));
}

/* --- Card 2: same blue as card 1, but the light pools from the opposite
       corner so the pair still reads as two different things -------------- */
.card--graphic{
  background:
    radial-gradient(120% 100% at 100% 0%, rgba(61,155,240,.10), transparent 58%),
    linear-gradient(165deg,var(--card-2),var(--card));
}

/* big ghosted numeral, top-right */
.card__index{
  position:absolute; top:14px; right:24px;
  font-size:clamp(3.6rem,3rem + 2.6vw,5.4rem);
  font-weight:600; line-height:1; letter-spacing:-.05em;
  font-variant-numeric:tabular-nums;
  color:transparent;
  -webkit-text-stroke:1px rgba(var(--accent-rgb),.26);
  pointer-events:none; user-select:none;
}

.card__icon{
  position:relative; z-index:1;
  width:58px; height:58px;
  display:grid; place-items:center;
  margin-bottom:20px;
  border:1px solid rgba(var(--accent-rgb),.32);
  background:linear-gradient(150deg,rgba(var(--accent-rgb),.22),rgba(var(--accent-rgb),.05));
  box-shadow:0 8px 24px -12px rgba(var(--accent-rgb),.9);
}
.card--web     .card__icon{ border-radius:16px; }   /* square-ish */
.card--graphic .card__icon{ border-radius:50%; }    /* round      */

.card__icon svg{
  width:27px; height:27px;
  fill:none; stroke:var(--accent); stroke-width:1.5;
  stroke-linecap:round; stroke-linejoin:round;
}

.card__kicker{
  font-size:.74rem; font-weight:600;
  letter-spacing:.16em; text-transform:uppercase;
  color:var(--accent);
  margin-bottom:8px;
}
.card__title{ font-size:clamp(1.35rem,1.2rem + .7vw,1.7rem); margin-bottom:14px; }
.card__text{ color:var(--ink-2); margin-bottom:26px; }

/* --- Checklist (card 1) -------------------------------------------------- */
.card__list{ display:grid; gap:11px; margin-bottom:30px; }
.card__list li{
  position:relative; padding-left:28px;
  color:var(--ink-2); font-size:.97rem; line-height:1.55;
}
.card__list li::before{                         /* SVG tick, not an emoji */
  content:''; position:absolute; left:0; top:.42em;
  width:16px; height:16px;
  background:var(--accent);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 13 4 4 10-10'/%3E%3C/svg%3E") center/contain no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 13 4 4 10-10'/%3E%3C/svg%3E") center/contain no-repeat;
}

/* --- Chips (card 2) — a completely different texture to the checklist ---- */
.card__chips{
  display:flex; flex-wrap:wrap; gap:8px;
  margin-bottom:30px;
}
.card__chips li{
  padding:7px 15px;
  border:1px solid rgba(var(--accent-rgb),.3);
  border-radius:999px;
  background:rgba(var(--accent-rgb),.07);
  color:var(--ink-2);
  font-size:.88rem; line-height:1.4;
  transition:border-color var(--fast) var(--ease),
             background var(--fast) var(--ease),
             color var(--fast) var(--ease);
}
.card--graphic:hover .card__chips li{
  border-color:rgba(var(--accent-rgb),.45);
  background:rgba(var(--accent-rgb),.12);
  color:var(--ink);
}

.card__link{
  display:inline-flex; align-items:center; gap:9px;
  min-height:44px;
  font-weight:600; color:var(--accent);
}
.card__link span{ transition:transform var(--mid) var(--ease); }
.card__link:hover span{ transform:translateX(6px); }


/* ==========================================================================
   10 · PACKAGE CARD  (Web Design and Graphic Design use the same component)
   --------------------------------------------------------------------------
   One card, a photograph behind everything, text sitting straight on it.
   The scrim is uniform rather than a gradient on purpose: a gradient left the
   right-hand column sitting over the bright part of the photo, where the list
   text fell to about 1.3:1. A flat scrim keeps the picture visible AND keeps
   every word readable wherever it lands.
   ========================================================================== */
.pcard{
  position:relative;
  display:grid; grid-template-columns:1fr;
  gap:clamp(20px,2.4vw,34px);
  padding:clamp(22px,2.6vw,38px);
  border:1px solid rgba(61,155,240,.3);
  border-radius:var(--radius);
  box-shadow:var(--shadow-lg);
  overflow:hidden;
  isolation:isolate;
}
.pcard__bg{
  position:absolute; inset:0; z-index:-2;
  width:100%; height:100%;
  object-fit:cover;
  filter:saturate(1.25) contrast(1.05) brightness(1.3);
}
.pcard::after{
  content:''; position:absolute; inset:0; z-index:-1;
  background:
    linear-gradient(180deg, rgba(6,9,15,.84), rgba(8,12,20,.80)),
    radial-gradient(80% 120% at 100% 0%, rgba(30,110,194,.24), transparent 60%);
}
.pcard::before{
  content:''; position:absolute; inset:0 0 auto 0; height:1px; z-index:1;
  background:linear-gradient(90deg,transparent,rgba(61,155,240,.65) 50%,transparent);
}

.pcard__lead{ align-self:center; }
.pcard__kicker{
  font-size:.74rem; font-weight:600;
  letter-spacing:.16em; text-transform:uppercase;
  color:var(--brand-text); margin-bottom:10px;
}
.pcard__kicker::before{
  content:''; display:inline-block;
  width:24px; height:1px; margin-right:11px; vertical-align:middle;
  background:var(--brand-text); opacity:.6;
}
.pcard__title{
  font-size:clamp(1.7rem,1.3rem + 1.7vw,2.5rem);
  margin-bottom:16px;
}
.pcard__text{
  color:var(--ink-2); font-size:.95rem; line-height:1.55;
  max-width:40ch; margin-bottom:22px;
}

.pcard__label{
  font-size:.72rem; font-weight:600;
  letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-2);
  padding-bottom:11px; margin-bottom:14px;
  border-bottom:1px solid rgba(61,155,240,.22);
}
.pcard__list{
  display:grid; grid-template-columns:1fr;
  gap:7px 18px;
  margin-bottom:14px;
}
.pcard__list li{
  position:relative; padding-left:19px;
  color:var(--ink-2); font-size:.9rem; line-height:1.45;
}
.pcard__list li::before{
  content:''; position:absolute; left:1px; top:.5em;
  width:7px; height:7px; border-radius:2px;
  background:var(--brand-text); opacity:.9;
  transform:rotate(45deg);
}
.pcard__foot{
  font-size:.86rem; color:var(--ink-2);
  padding-top:13px;
  border-top:1px solid var(--line);
}


/* ==========================================================================
   11 · PORTFOLIO
   One tile, which opens the gallery. The cue is a magnifier that is always
   there — quiet, but never hover-only, because on a phone there is no hover
   and a cue that needs one is a cue nobody ever sees.
   ========================================================================== */
.gallery, .gallery[hidden]{ display:none; }

.showcase-wrap{ max-width:900px; margin-inline:auto; }

.showcase{
  position:relative; display:block; width:100%;
  border-radius:var(--radius-sm); overflow:hidden;
  border:1px solid var(--line);
  background:var(--card);
  box-shadow:var(--shadow);
  cursor:pointer;
  transition:border-color var(--mid) var(--ease),
             box-shadow var(--mid) var(--ease),
             transform var(--mid) var(--ease);
}
/* These photographs are dark to begin with — around 20% average brightness.
   An earlier version dimmed them further and laid a scrim over the whole tile,
   which took the picture down to roughly 6% and it read as an empty black box.
   So: no dimming at all, and the scrim only where the button actually sits. */
.showcase img{
  display:block; width:100%;
  aspect-ratio:16/10; object-fit:cover;
  filter:saturate(1.05);
  transition:transform 1s var(--ease), filter var(--mid) var(--ease);
}
/* The photographs are dark to begin with — around 20% average brightness.
   An earlier version dimmed them and laid a scrim over the whole tile, which
   took the picture down to roughly 6% and it read as an empty black box. So:
   no dimming, and only enough shading in the corner to hold the magnifier. */
.showcase::after{
  content:''; position:absolute; inset:0;
  background:radial-gradient(120% 90% at 100% 100%, rgba(6,9,15,.62), transparent 58%);
}
.showcase:hover{
  border-color:rgba(61,155,240,.45);
  box-shadow:var(--shadow-lg);
  transform:translateY(-3px);
}
.showcase:hover img{ transform:scale(1.04); filter:saturate(1.15) brightness(1.06); }
.showcase:active{ transform:translateY(-1px); }
.showcase:focus-visible{ outline:2px solid var(--brand-text); outline-offset:3px; }

/* The magnifier. The whole tile is the button, so this only has to be seen,
   not hit — but it is still 46px, because on a phone it reads as the thing
   you press and it should not look smaller than a thumb. */
.showcase__cue{
  position:absolute; z-index:2;
  right:clamp(12px,1.6vw,18px); bottom:clamp(12px,1.6vw,18px);
  display:grid; place-items:center;
  width:46px; height:46px; border-radius:50%;
  border:1px solid rgba(255,255,255,.3);
  background:rgba(8,11,18,.55);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  color:#fff;
  transition:background var(--mid) var(--ease),
             border-color var(--mid) var(--ease),
             transform var(--mid) var(--ease);
}
.showcase__cue svg{
  width:19px; height:19px;
  fill:none; stroke:currentColor; stroke-width:1.75;
  stroke-linecap:round; stroke-linejoin:round;
}
.showcase:hover .showcase__cue{
  background:rgba(30,110,194,.85);
  border-color:rgba(255,255,255,.5);
  transform:scale(1.07);
}

@media (min-width:700px){
  .showcase img{ aspect-ratio:16/9; }
}


/* ==========================================================================
   12 · TESTIMONIALS
   One quote at a time, with dots underneath and a pair of arrows.

   The cards are stacked in a single grid cell and crossfaded, rather than
   slid along a track. That means no measuring, so nothing can drift out of
   step the way a measured track does when a font or an image loads late.
   The stage takes the height of the TALLEST quote and keeps it, so the page
   below does not jump about as you move between them.
   ========================================================================== */
.says{ max-width:760px; margin-inline:auto; }

.says__track{ display:grid; }

/* Every card occupies the same cell. `visibility` rides along with the fade
   so a card that has faded out cannot still be clicked or tabbed into. */
.say{
  grid-area:1 / 1;
  opacity:0; visibility:hidden;
  transition:opacity .45s var(--ease), visibility .45s;
}
.say.is-on{ opacity:1; visibility:visible; }

.say{
  display:flex; flex-direction:column; gap:clamp(16px,2vw,22px);
  padding:clamp(22px,2.6vw,32px);
  border:1px solid var(--line);
  border-radius:var(--radius-sm);
  background:var(--card);
  box-shadow:var(--shadow);
}

/* The stage is as tall as the LONGEST quote, so a short one would otherwise
   leave a hole above the name. Centring it in the space keeps every slide
   looking composed, and the attribution line stays put as you move between
   them rather than hopping up and down. */
.say__quote{ flex:1; display:flex; align-items:center; }
.say__quote p{
  position:relative;
  font-size:clamp(1rem,.96rem + .2vw,1.1rem);
  line-height:1.6;
  color:var(--ink-2);
}
/* The opening mark sits in the margin so the first line of the quote still
   starts flush with everything else in the card. */
.say__quote p::before{
  content:'"';
  position:absolute; left:-.42em; top:-.12em;
  font-size:2.4em; line-height:1;
  color:var(--brand-text); opacity:.32;
}

.say__who{
  display:flex; align-items:center; gap:14px;
  padding-top:clamp(14px,1.8vw,18px);
  border-top:1px solid var(--line);
}

/* A fixed plate with the logo fitted inside it. The size is in PIXELS on
   purpose — a percentage has nothing to resolve against here, and a wide
   logo then overflowed the plate. `contain` fits any shape, square or wide,
   without distorting it: Keep Cool is 5.5:1 and still sits inside neatly. */
.say__logo{
  flex:none;
  box-sizing:border-box;
  width:56px; height:56px;
  padding:9px;
  border-radius:12px;
  border:1px solid var(--line-2);
  background:rgba(255,255,255,.055);
  object-fit:contain;
}

.say__who figcaption{ display:grid; gap:2px; min-width:0; }
.say__name{ font-weight:600; font-size:.98rem; color:var(--ink); }
.say__org{
  font-size:.74rem; font-weight:600;
  letter-spacing:.14em; text-transform:uppercase;
  color:var(--ink-3);
}

/* A reminder you cannot miss while the words are still the stand-in ones.
   Delete data-placeholder in index.html and this disappears. */
.say[data-placeholder]{
  border-color:rgba(220,150,40,.5);
  background:
    linear-gradient(0deg, rgba(220,150,40,.05), rgba(220,150,40,.05)),
    var(--card);
}
.say[data-placeholder] .say__quote p{ color:var(--ink-3); font-style:italic; }

/* --- controls -------------------------------------------------------------
   Deliberately quiet. The arrows carry no border or background until you
   reach for them, and the dots are 7px of colour inside a 44px target — so
   they stay easy to hit on a phone without looking like it.
   -------------------------------------------------------------------------- */
.says__nav{
  display:flex; align-items:center; justify-content:center;
  gap:6px;
  margin-top:clamp(14px,1.8vw,20px);
}
.says__nav[hidden]{ display:none; }

.says__arrow{
  display:grid; place-items:center;
  width:44px; height:44px; border-radius:50%;
  background:transparent; border:1px solid transparent;
  color:var(--ink-3); cursor:pointer;
  transition:color var(--fast) var(--ease),
             background var(--fast) var(--ease),
             border-color var(--fast) var(--ease);
}
.says__arrow:hover,
.says__arrow:focus-visible{
  color:var(--ink);
  background:rgba(255,255,255,.05);
  border-color:var(--line-2);
}
.says__arrow:active{ transform:scale(.92); }
.says__arrow svg{
  width:18px; height:18px;
  fill:none; stroke:currentColor; stroke-width:1.9;
  stroke-linecap:round; stroke-linejoin:round;
}

.says__dots{ display:flex; align-items:center; }
/* The gap between dots is INSIDE each button, not between them, so the
   targets touch and there is no dead strip to miss between two dots. */
.sdot{
  display:grid; place-items:center;
  width:38px; height:44px;
  background:none; border:0; cursor:pointer;
}
.sdot::before{
  content:''; display:block;
  width:7px; height:7px; border-radius:50%;
  background:var(--ink-3); opacity:.45;
  transition:opacity var(--fast) var(--ease),
             background var(--fast) var(--ease),
             transform var(--fast) var(--ease);
}
.sdot:hover::before{ opacity:.8; }
.sdot[aria-current="true"]::before{
  background:var(--brand-text); opacity:1;
  transform:scale(1.35);
}
.sdot:focus-visible{ outline:2px solid var(--brand-text); outline-offset:-6px; border-radius:8px; }


/* ==========================================================================
   13 · FAQ ACCORDION
   Open/close height is animated by js/site.js so it glides on every browser.
   ========================================================================== */
.faq{ display:grid; gap:7px; }

.faq__item{
  position:relative;
  border:1px solid var(--line);
  border-radius:var(--radius-sm);
  background:linear-gradient(170deg,var(--card-2),var(--card));
  box-shadow:var(--shadow);
  overflow:hidden;
  transition:border-color var(--mid) var(--ease), box-shadow var(--mid) var(--ease);
}
/* Blue edge down the left of every question. Thin when closed, full strength
   and slightly wider once open, so the open row is obvious at a glance. */
.faq__item::before{
  content:''; position:absolute; z-index:2;
  left:0; top:0; bottom:0; width:3px;
  background:var(--brand);
  opacity:.55;
  transition:opacity var(--mid) var(--ease), width var(--mid) var(--ease);
}
.faq__item:hover::before{ opacity:.8; }
.faq__item.is-open::before{ opacity:1; width:4px; }
.faq__item:hover{ border-color:var(--line-2); }
.faq__item.is-open{
  border-color:rgba(61,155,240,.4);
  box-shadow:var(--shadow-lg);
}

.faq__h{ margin:0; font-size:inherit; font-weight:inherit; letter-spacing:normal; }

.faq__q{
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  width:100%; min-height:50px;
  padding:13px clamp(16px,1.9vw,22px) 13px calc(clamp(16px,1.9vw,22px) + 8px);
  text-align:left;
  font-size:clamp(.95rem,.93rem + .18vw,1.02rem);
  font-weight:600; letter-spacing:-.01em; line-height:1.4;
  color:var(--ink);
  transition:color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.faq__q:hover{ background:rgba(255,255,255,.03); }
.faq__item.is-open .faq__q{ color:var(--brand-text); }

/* the +/- mark, drawn with two bars so it can rotate into a cross */
.faq__icon{
  position:relative; flex:none;
  width:17px; height:17px;
  transition:transform var(--mid) var(--ease);
}
.faq__icon::before,
.faq__icon::after{
  content:''; position:absolute; left:50%; top:50%;
  width:13px; height:1.5px; border-radius:2px;
  background:currentColor;
  transform:translate(-50%,-50%);
  transition:transform var(--mid) var(--ease), opacity var(--mid) var(--ease);
}
.faq__icon::after{ transform:translate(-50%,-50%) rotate(90deg); }
.faq__item.is-open .faq__icon{ transform:rotate(180deg); }
.faq__item.is-open .faq__icon::after{ opacity:0; transform:translate(-50%,-50%) rotate(0deg); }

/* height is set inline by the script; this rule owns the easing */
.faq__a{
  height:0;
  overflow:hidden;
  transition:height .42s var(--ease);
}
.faq__inner{
  padding:0 clamp(16px,1.9vw,22px) 17px calc(clamp(16px,1.9vw,22px) + 8px);
  color:var(--ink-2);
  font-size:.94rem;
}
.faq__inner p{ max-width:62ch; }






/* ==========================================================================
   14 · CONTACT & FORM
   ========================================================================== */
.contact{ display:grid; gap:clamp(28px,3.6vw,48px); grid-template-columns:1fr; }

.contact__aside{ display:grid; gap:14px; align-content:start; }
.contact__row{
  display:flex; align-items:flex-start; gap:15px;
  min-height:44px;
  padding:19px 22px;
  border:1px solid var(--line); border-radius:var(--radius-sm);
  background:linear-gradient(160deg,var(--card-2),var(--card));
  color:var(--ink);
  transition:border-color var(--fast) var(--ease), transform var(--fast) var(--ease);
}
a.contact__row:hover{ border-color:rgba(61,155,240,.42); transform:translateY(-2px); }
.contact__row svg{
  flex:none; width:21px; height:21px; margin-top:3px;
  fill:none; stroke:var(--brand-text); stroke-width:1.5;
  stroke-linecap:round; stroke-linejoin:round;
}
.contact__row span{ display:grid; gap:2px; line-height:1.45; font-size:.98rem; color:var(--ink-2); }
.contact__row strong{
  font-size:.73rem; font-weight:600; letter-spacing:.14em;
  text-transform:uppercase; color:var(--ink-3);
}

.form{
  display:grid; gap:20px;
  padding:clamp(24px,3.2vw,40px);
  border:1px solid var(--line); border-radius:var(--radius);
  background:linear-gradient(165deg,var(--card-2),var(--card));
  box-shadow:var(--shadow);
}
.form__row{ display:grid; gap:20px; grid-template-columns:1fr; }

.field{ display:grid; gap:8px; }
.field label{
  font-size:.83rem; font-weight:600;
  letter-spacing:.09em; text-transform:uppercase; color:var(--ink-3);
}
.field label span{ color:var(--brand-text); }

.field input,
.field textarea{
  width:100%;
  min-height:52px;
  padding:14px 18px;
  font-size:16px;                          /* 16px stops iOS zooming on focus */
  line-height:1.55;
  color:var(--ink);
  background:rgba(255,255,255,.035);
  border:1px solid var(--line-2);
  border-radius:var(--radius-sm);
  transition:border-color var(--fast) var(--ease),
             background var(--fast) var(--ease),
             box-shadow var(--fast) var(--ease);
}
.field textarea{ resize:vertical; min-height:140px; }
.field input::placeholder,
.field textarea::placeholder{ color:#5C6980; }
.field input:focus,
.field textarea:focus{
  outline:none;
  border-color:var(--brand);
  background:rgba(61,155,240,.06);
  box-shadow:0 0 0 4px rgba(61,155,240,.14);
}
.field.is-bad input,
.field.is-bad textarea{ border-color:#FF7B7B; background:rgba(255,123,123,.06); }

.field__hint{ font-size:.86rem; color:var(--ink-3); }
.field__opt{
  font-weight:400; letter-spacing:.04em; text-transform:none;
  color:var(--ink-3); opacity:.85;
}

/* Consent line. Deliberately plain and quiet — it is a reassurance, not a
   legal wall, and it sits directly above the send button where it belongs. */
.form__consent{
  font-size:.84rem; line-height:1.55;
  color:var(--ink-3);
  padding:12px 14px;
  border-left:2px solid rgba(61,155,240,.35);
  background:rgba(61,155,240,.05);
  border-radius:0 var(--radius-sm) var(--radius-sm) 0;
}
.field__err{ display:none; font-size:.87rem; color:#FF9C9C; }
.field__err::before{ content:'! '; font-weight:700; }
.field.is-bad .field__err{ display:block; }

/* honeypot — visually gone, still reachable by bots */
.hp{ position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }

.form__foot{
  display:flex; flex-wrap:wrap; gap:16px;
  align-items:center; justify-content:space-between;
  margin-top:4px;
}
.form__tip{ font-size:.86rem; color:var(--ink-3); }
.form__tip span{ color:var(--brand-text); }

.form__result{
  display:none;
  padding:15px 20px; border-radius:var(--radius-sm);
  font-size:.96rem; line-height:1.5;
}
.form__result.is-ok{
  display:block; color:#A8F0C6;
  border:1px solid rgba(64,220,140,.36); background:rgba(64,220,140,.1);
}
.form__result.is-bad{
  display:block; color:#FFB9B9;
  border:1px solid rgba(255,123,123,.36); background:rgba(255,123,123,.09);
}


/* ==========================================================================
   15 · FOOTER
   ========================================================================== */
.foot{
  position:relative;
  padding-block:clamp(44px,5vw,64px);
  padding-bottom:calc(clamp(50px,6vw,74px) + env(safe-area-inset-bottom));
  border-top:1px solid var(--line);
  background:linear-gradient(180deg,transparent,rgba(61,155,240,.045));
}
.foot__inner{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:6px 22px; text-align:center;
}
.foot__logo{ display:flex; align-items:center; min-height:46px; }
.foot__logo img{ width:140px; opacity:.75; transition:opacity var(--fast); }
.foot__logo:hover img{ opacity:1; }
.foot__links{ display:flex; flex-wrap:wrap; justify-content:center; gap:4px 6px; }
.foot__links a{
  min-height:44px; display:inline-flex; align-items:center;
  padding:8px 14px; border-radius:999px;
  color:var(--ink-2); font-size:.93rem;
  transition:color var(--fast), background var(--fast);
}
.foot__links a:hover{ color:var(--ink); background:rgba(255,255,255,.05); }
.foot__estab{
  font-size:.78rem; font-weight:600;
  letter-spacing:.15em; text-transform:uppercase;
  color:var(--ink-2);
  margin-bottom:-14px;          /* pulls it close to the copyright line */
}
.foot__copy{ font-size:.87rem; color:var(--ink-3); }

.totop{
  position:fixed; z-index:800;
  right:clamp(16px,3vw,28px);
  bottom:calc(clamp(16px,3vw,28px) + env(safe-area-inset-bottom));
  display:grid; place-items:center;
  width:50px; height:50px; border-radius:50%;
  border:1px solid var(--line-2);
  background:rgba(12,17,26,.82);
  backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px);
  color:var(--ink-2);
  opacity:0; visibility:hidden; transform:translateY(14px);
  transition:opacity var(--mid) var(--ease), transform var(--mid) var(--ease), visibility var(--mid),
             color var(--fast), border-color var(--fast);
}
.totop.is-on{ opacity:1; visibility:visible; transform:none; }
.totop:hover{ color:#fff; border-color:var(--brand); }
.totop svg{ width:20px; height:20px; fill:none; stroke:currentColor; stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round; }


/* ==========================================================================
   16 · LIGHTBOX
   ========================================================================== */
.lightbox{
  position:fixed; inset:0; z-index:9500;
  display:grid; place-items:center;
  padding:clamp(16px,4vw,54px);
  background:rgba(4,7,12,.9);
  backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
  opacity:0; transition:opacity var(--mid) var(--ease);
}
.lightbox[hidden]{ display:none; }
.lightbox.is-open{ opacity:1; }
.lightbox__fig{
  position:relative;
  display:grid; gap:16px; justify-items:center;
  max-width:100%; max-height:100%;
  transform:scale(.94); opacity:0;
  transition:transform .45s var(--ease), opacity .45s var(--ease);
}
.lightbox.is-open .lightbox__fig{ transform:none; opacity:1; }
.lightbox__fig img{
  max-width:100%; max-height:78vh;
  border-radius:var(--radius); box-shadow:var(--shadow-lg);
  object-fit:contain;
}
.lightbox__fig figcaption{
  font-size:.78rem; font-weight:600; letter-spacing:.14em;
  text-transform:uppercase; color:var(--ink-3);
}
.lightbox__close{
  position:absolute; top:clamp(12px,2.4vw,24px); right:clamp(12px,2.4vw,24px);
  display:grid; place-items:center;
  width:48px; height:48px; border-radius:50%;
  border:1px solid var(--line-2); background:rgba(255,255,255,.05);
  color:var(--ink);
  transition:background var(--fast), border-color var(--fast), transform var(--fast);
}
.lightbox__close:hover{ background:rgba(255,255,255,.12); border-color:var(--brand); }
.lightbox__close:active{ transform:scale(.93); }
.lightbox__close svg{ width:22px; height:22px; fill:none; stroke:currentColor; stroke-width:1.8; stroke-linecap:round; }

/* The picture itself is the "next" button, so it says so. */
.lightbox__fig img{ cursor:pointer; }


/* --- gallery controls ---------------------------------------------------
   Phone: one row along the bottom, inside thumb reach and clear of the
   picture. Wider than 760px: the bar unwraps and the arrows go to the
   edges, where a mouse expects them.
   ------------------------------------------------------------------------ */
.lightbox__bar{
  position:absolute; left:0; right:0; bottom:clamp(12px,2.4vw,20px);
  display:flex; align-items:center; justify-content:center; gap:16px;
}
.lightbox__nav{
  display:grid; place-items:center;
  width:48px; height:48px; border-radius:50%;
  border:1px solid var(--line-2); background:rgba(255,255,255,.06);
  color:var(--ink); cursor:pointer;
  transition:background var(--fast), border-color var(--fast), transform var(--fast);
}
.lightbox__nav:hover{ background:rgba(255,255,255,.14); border-color:var(--brand); }
.lightbox__nav:active{ transform:scale(.93); }
.lightbox__nav[hidden]{ display:none; }
.lightbox__nav svg{ width:22px; height:22px; fill:none; stroke:currentColor; stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round; }

.lightbox__count{
  min-width:56px; text-align:center;
  font-size:.8rem; font-weight:600; letter-spacing:.1em;
  color:var(--ink-2); font-variant-numeric:tabular-nums;
}
.lightbox__count[hidden]{ display:none; }

@media (min-width:760px){
  /* room down each side so the edge arrows never sit on top of the picture —
     at 768px the image is otherwise the full width and they overlap it */
  .lightbox{ padding-inline:clamp(88px,7vw,120px); }
  .lightbox__bar{ display:contents; }
  .lightbox__nav{
    position:absolute; top:50%; transform:translateY(-50%);
    width:54px; height:54px;
    background:rgba(8,11,18,.6);
    backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  }
  .lightbox__nav--prev{ left:clamp(12px,2.4vw,28px); }
  .lightbox__nav--next{ right:clamp(12px,2.4vw,28px); }
  .lightbox__nav:active{ transform:translateY(-50%) scale(.93); }
  .lightbox__count{
    position:absolute; left:0; right:0; bottom:clamp(12px,2.4vw,22px);
  }
}

/* room for the bottom row on a phone */
@media (max-width:759px){
  .lightbox{ padding-bottom:82px; }
  .lightbox__fig img{ max-height:66vh; }
}


/* ==========================================================================
   17 · REVEAL ANIMATIONS
   Anything with data-reveal fades up as it enters the viewport.
   data-reveal-delay="1..4" staggers it by 80ms steps.
   ========================================================================== */
[data-reveal]{
  opacity:0; transform:translate3d(0,26px,0);
  transition:opacity .78s var(--ease), transform .78s var(--ease);
  will-change:opacity,transform;
}
[data-reveal].is-in{ opacity:1; transform:none; will-change:auto; }
[data-reveal-delay="1"]{ transition-delay:.08s; }
[data-reveal-delay="2"]{ transition-delay:.16s; }
[data-reveal-delay="3"]{ transition-delay:.24s; }
[data-reveal-delay="4"]{ transition-delay:.32s; }


/* ==========================================================================
   BREAKPOINTS  ·  600 / 768 / 1024 / 1200
   ========================================================================== */

/* --- 600px and up ------------------------------------------------------- */
@media (min-width:600px){
  .pcard__list{ grid-template-columns:1fr 1fr; }
  .form__row{ grid-template-columns:1fr 1fr; }
}

/* --- 768px and up ------------------------------------------------------- */
@media (min-width:768px){
  .strip__grid{ grid-template-columns:repeat(4,1fr); }
  .about__grid{ grid-template-columns:1fr 1fr; }
  .cards{ grid-template-columns:1fr 1fr; }
}

/* --- 1024px and up ------------------------------------------------------ */
@media (min-width:1024px){
  .pcard{ grid-template-columns:.9fr 1.1fr; gap:clamp(30px,3.5vw,56px); }
  :root{ --nav-h:84px; }
  .contact{ grid-template-columns:1.6fr minmax(260px,.8fr); }
  .lead{ max-width:16ch; }
}

/* --- 1200px and up ------------------------------------------------------ */
@media (min-width:1200px){
  .about__grid{ grid-template-columns:1fr 1fr; gap:clamp(40px,4vw,70px); }
}


/* ==========================================================================
   MOBILE NAVIGATION  (below 1024px)
   ========================================================================== */
@media (max-width:1023px){

  .burger{ display:grid; }

  .nav__links{
    position:fixed; inset:0;
    flex-direction:column; justify-content:center;
    gap:0;
    padding:calc(var(--nav-h) + env(safe-area-inset-top) + 20px) var(--gutter)
            calc(40px + env(safe-area-inset-bottom));
    background:rgba(8,11,18,.94);
    backdrop-filter:blur(22px) saturate(160%);
    -webkit-backdrop-filter:blur(22px) saturate(160%);
    opacity:0; visibility:hidden;
    transition:opacity var(--mid) var(--ease), visibility var(--mid);
    overflow-y:auto;
  }
  .nav__links.is-open{ opacity:1; visibility:visible; }

  /* A photograph behind the mobile menu, kept very faint and blurred so it
     reads as texture rather than a picture. Swap the image here. */
  .nav__links::before{
    content:''; position:absolute; inset:0; z-index:-1;
    background-image:url('../images/portfolio-graphic.jpg');
    background-size:cover; background-position:center;
    opacity:.16;
    filter:blur(2px) saturate(1.1);
  }
  /* and a wash over it so the links never fight the photograph */
  .nav__links::after{
    content:''; position:absolute; inset:0; z-index:-1;
    background:linear-gradient(180deg, rgba(8,11,18,.72), rgba(8,11,18,.92));
  }

  .nav__home{ display:block; }      /* mobile only — the logo covers it on desktop */

  .nav__links a{
    font-size:1.15rem; font-weight:600; letter-spacing:-.01em;
    padding:11px 18px;
    text-align:center;
    opacity:0; transform:translateY(18px);
    transition:opacity .4s var(--ease), transform .4s var(--ease), color var(--fast);
  }
  .nav__links a::after{ display:none; }
  .nav__links.is-open a{ opacity:1; transform:none; }
  .nav__links.is-open a:nth-child(1){ transition-delay:.06s; }
  .nav__links.is-open a:nth-child(2){ transition-delay:.11s; }
  .nav__links.is-open a:nth-child(3){ transition-delay:.16s; }
  .nav__links.is-open a:nth-child(4){ transition-delay:.21s; }
  .nav__links.is-open a:nth-child(5){ transition-delay:.26s; }
  .nav__links.is-open a:nth-child(6){ transition-delay:.31s; }

  /* Specificity has to match the desktop rule (.nav__links a.nav__cta),
     or its margin-left:10px wins and shunts the button off centre. */
  .nav__links a.nav__cta{
    margin:14px auto 0;
    width:min(300px,100%);
    font-size:.98rem!important;
    padding:13px 26px!important;
  }
}

/* --- Phones: lighten the expensive effects ------------------------------- */
@media (max-width:767px){
  /* a 90px blur on two large elements is heavy work for budget Androids */
  .hero__glow i{ filter:blur(58px); opacity:.34; }

  /* A larger foot pushes the centred copy UP the screen, which is what takes
     the big empty gap out from above the first line. */
  .hero{ --hero-foot:196px; }
  .hero__bottom{ bottom:calc(16px + env(safe-area-inset-bottom)); }

  /* Breathing room between the three lines — they were sitting on top of
     each other on a phone. */
  .hero__eyebrow{ margin-bottom:30px; }
  .hero__title  { line-height:1.16; }
}

/* --- Small phones -------------------------------------------------------- */
@media (max-width:479px){
  /* the scroll cue now stays on phones — with the buttons gone there's room */

  .form__foot{ flex-direction:column-reverse; align-items:stretch; }
  .form__foot .btn{ width:100%; }
  .form__tip{ text-align:center; }
}

/* --- Short viewports: tighten the hero so nothing collides ---------------- */
/* Most phones land in here once the browser's own toolbars are counted, so
   these values are what a real handset actually gets. They used to squeeze the
   three lines to 14/15px apart — hence the "all squashed together" look. */
@media (max-height:720px){
  .hero{ --hero-foot:186px; }
  .hero__eyebrow{ margin-bottom:26px; padding:7px 15px; font-size:.74rem; }
  .hero__title{ font-size:clamp(1.9rem,1.1rem + 3.4vw,2.9rem); }
}
@media (max-height:620px){
  .hero{ --hero-foot:132px; }
  .hero__eyebrow{ margin-bottom:20px; }
  .hero__title{ font-size:clamp(1.6rem,1rem + 2.8vw,2.2rem); }
}

/* --- Short / landscape phones -------------------------------------------- */
@media (max-height:620px) and (orientation:landscape){
  /* Not enough height to float the scroll cue — drop it and let the content
     set the hero's height. The photographs stay absolutely positioned and
     still cover the whole section. */
  .hero{
    min-height:auto; --hero-foot:0px;
    padding:calc(var(--nav-h) + 30px) var(--gutter) 26px;
  }
  .hero__bottom{ display:none; }
}

/* --- Pointer-less devices: drop hover-only flourishes -------------------- */
@media (hover:none){
  .card:hover{ transform:none; }
  .showcase:hover{ transform:none; }
  .showcase:hover img{ transform:none; }
}


/* ==========================================================================
   18 · REDUCED MOTION  &  PRINT
   ========================================================================== */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms!important;
    animation-iteration-count:1!important;
    transition-duration:.01ms!important;
    scroll-behavior:auto!important;
  }
  html{ scroll-behavior:auto; }
  [data-reveal]{ opacity:1; transform:none; }
  .hero__img{ transform:scale(1.06); }
  .hero__scroll span{ animation:none; opacity:.5; }
  .hero__glow i{ animation:none; }
}

@media print{
  .nav,.hero__glow,.hero__scroll,.totop,.loader,.lightbox,.burger{ display:none!important; }
  body{ background:#fff; color:#000; }
  .section,.section--alt{ background:#fff; padding-block:24px; }
  .hero{ min-height:auto; }
  [data-reveal]{ opacity:1; transform:none; }
}
