/* =========================================================
   ajak.Web — Portfolio Stylesheet
   A modern independent web design studio site.
   Design tokens live at the top — change colors, fonts and
   spacing here and the whole site updates.
   ========================================================= */

/* Self-hosted rather than pulled from Google Fonts: this is the one
   display face used only by the homepage hero headline, so shipping
   it as a local asset removes any dependency on a third-party font
   CDN being reachable for that one element. */
@font-face {
  font-family: "Bebas Neue";
  src: url("../fonts/bebas-neue.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
/* Replaces Bebas Neue as the hero headline face (redesign round 7):
   a heavier, more idiosyncratic condensed display face reads as
   art-directed rather than a stock template choice. */
@font-face {
  font-family: "Big Shoulders Display";
  src: url("../fonts/big-shoulders-800.ttf") format("truetype");
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}

/* ---------- Design Tokens ---------- */
:root {
  /* Color */
  --ink: #131316;
  --ink-soft: #2b2b33;
  --paper: #faf9f5;
  --paper-alt: #f1efe8;
  --surface: #ffffff;
  --accent: #3b46f0;
  --accent-dark: #2a32c4;
  --accent-tint: #eaebff;
  /* Hero-only accent (Phase 23B): a vivid neon lime, reserved for small
     marks placed on an ink-black surface -- on the warm paper/paper-alt
     backgrounds it measures ~1:1 contrast (functionally invisible), so
     it is never used as running text color here, only as a fill behind
     off-white/ink content. Kept as a token (not hardcoded) so it stays
     available if a future phase wants it elsewhere, but nothing outside
     the hero references it yet. Recalibrated to the reference's own
     measured lime (~#E1E778-#E7FF4D, warmer/yellower than the previous
     value) per the Phase 23 color-calibration pass. */
  --lime: #e7ff4d;
  --muted: #6b6b74;
  --muted-2: #96959e;
  --border: #e5e2da;
  --border-on-dark: rgba(250, 249, 245, 0.14);

  /* Type */
  --font-display: "Bricolage Grotesque", "Segoe UI", sans-serif;
  --font-body: "Inter", "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", "Courier New", monospace;

  --fs-hero: clamp(2.4rem, 4.5vw + 1rem, 4.35rem);
  --fs-h1: clamp(2rem, 2.6vw + 1rem, 2.9rem);
  --fs-h2: clamp(1.5rem, 1.6vw + 1rem, 2.1rem);
  --fs-h3: clamp(1.15rem, 0.6vw + 1rem, 1.35rem);
  --fs-lead: clamp(1.05rem, 0.5vw + 0.9rem, 1.2rem);
  --fs-body: 1rem;
  --fs-small: 0.875rem;
  --fs-eyebrow: 0.76rem;

  /* Space */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4.5rem;
  --space-9: 6.5rem;

  /* Shape */
  --radius-sm: 8px;
  --radius-md: 14px;
  --radius-lg: 22px;
  --radius-full: 999px;

  --shadow-sm: 0 1px 2px rgba(19, 19, 22, 0.06);
  --shadow-md: 0 12px 32px rgba(19, 19, 22, 0.08);
  --shadow-lg: 0 24px 60px rgba(19, 19, 22, 0.14);

  --container: 1180px;
  --speed: 0.35s;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

img, picture, svg { display: block; max-width: 100%; }

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

button, input, select, textarea {
  font: inherit;
  color: inherit;
}

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

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.01em;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

:focus-visible {
  outline: 2.5px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Layout helpers ---------- */
.wrap {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--space-5);
}

.section {
  padding-block: var(--space-8);
}

.section--tight { padding-block: var(--space-7); }
.section--alt { background: var(--paper-alt); }
.section--ink {
  background: var(--ink);
  color: var(--paper);
}

/* Same warm charcoal as the approved hero (a literal value, not a
   shared token -- the hero's CSS is a frozen baseline and isn't
   touched to extract one). Used only by the Introduction section
   directly below the hero, so the dark opening reads as two
   deliberate beats before the page returns to paper for Services. */
.section--charcoal { background: #17140f; }
.section--charcoal .eyebrow { color: var(--lime); }
.section--charcoal .eyebrow::before { background: var(--lime); }

.grid {
  display: grid;
  gap: var(--space-6);
}

.stack { display: flex; flex-direction: column; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

.eyebrow::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}

.section--ink .eyebrow { color: #9aa3ff; }
.section--ink .eyebrow::before { background: #9aa3ff; }

/* Global color-system alignment: inner-page eyebrows (page-header,
   founder title) sit on paper, where lime text measures near-invisible
   -- text stays neutral, only the dot picks up the brand accent. Scoped
   to body.is-inner (about/services/work/contact only) so this cannot
   reach the homepage's own eyebrows, several of which are still on the
   pre-lime system and out of scope for this phase. */
body.is-inner .eyebrow { color: var(--muted-2); }
body.is-inner .eyebrow::before { background: var(--lime); }

/* The dark CTA band (About/Services/Work) is the one place an inner
   page's eyebrow sits on ink instead of paper -- lime text is safe
   there, same as the approved Introduction's own eyebrow treatment. */
.cta-band.section--ink .eyebrow { color: var(--lime); }
.cta-band.section--ink .eyebrow::before { background: var(--lime); }

/* Selected Work (homepage) art-direction pass: this eyebrow sits on
   paper and was still on the legacy blue -- the one piece of Selected
   Work the color-system phase deliberately left alone. Same treatment
   as the inner pages: neutral text for legibility, lime only on the
   dot. Scoped to #selected-work specifically, not the shared .eyebrow
   base rule, so the rest of the homepage (out of scope for this
   phase) is untouched. */
#selected-work .eyebrow { color: var(--muted-2); }
#selected-work .eyebrow::before { background: var(--lime); }

/* Selected Work is the site's flagship section -- the "second act"
   right after the hero's own poster moment -- so its own heading
   carries more scale and confidence than the shared .section-head h2
   every other section uses. Scoped to #selected-work only, same
   pattern as the eyebrow override above, so About/Services/Why Ajak
   and every other section keep their existing heading size. */
#selected-work .section-head { max-width: 42rem; }
#selected-work .section-head h2 {
  font-size: clamp(2.4rem, 1.6vw + 1.9rem, 3.6rem);
  line-height: 1.04;
  max-width: 15ch;
}

.section-head {
  max-width: 640px;
  margin-bottom: var(--space-7);
}

.section-head h2 { margin-top: var(--space-3); }
.section-head p {
  margin-top: var(--space-4);
  color: var(--muted);
  font-size: var(--fs-lead);
}

.section--ink .section-head p { color: rgba(250, 249, 245, 0.72); }

.center { text-align: center; margin-inline: auto; }

/* ---------- Buttons ----------
   Small rectangular radius rather than a full pill, and hover feedback
   carried entirely by colour + the arrow glyph (no lift) -- the pill
   shape and hover "bounce" are the two most SaaS-coded button tells,
   so removing them is enough to place the button inside the studio's
   own visual language rather than a generic landing-page kit. */
.btn {
  --btn-fg: var(--paper);
  --btn-bg: var(--ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  padding: 0.85em 1.5em;
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 0.95rem;
  border: 1.5px solid transparent;
  background: var(--btn-bg);
  color: var(--btn-fg);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--speed) var(--ease), border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

/* Brand accent button (Global color-system alignment): lime fill with
   dark ink text at rest -- a large solid fill reads fine in lime
   (unlike small text on paper, which measures near-invisible), so
   this is safe as the primary "Start a Project"/"Send Enquiry" style
   sitewide. Hover inverts to ink-fill/lime-text, reusing the same
   pattern already approved on the hero's own nav CTA hover state. */
.btn--accent { --btn-bg: var(--lime); --btn-fg: var(--ink); }
.btn--accent:hover { --btn-bg: var(--ink); --btn-fg: var(--lime); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  border-color: var(--border);
}
.btn--ghost:hover { border-color: var(--ink); }

.section--ink .btn--ghost {
  --btn-fg: var(--paper);
  border-color: var(--border-on-dark);
}
.section--ink .btn--ghost:hover { border-color: var(--paper); }

.btn--sm { padding: 0.6em 1.1em; font-size: 0.85rem; }
.btn--block { width: 100%; }

.btn svg { width: 1.05em; height: 1.05em; flex: none; }

/* ---------- Header / Nav ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(250, 249, 245, 0);
  border-bottom: 1px solid transparent;
  transition: background var(--speed) var(--ease), border-color var(--speed) var(--ease), box-shadow var(--speed) var(--ease), backdrop-filter var(--speed) var(--ease);
}

.site-header.is-scrolled {
  background: rgba(250, 249, 245, 0.92);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-color: var(--border);
  box-shadow: var(--shadow-sm);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-4);
  transition: padding-block var(--speed) var(--ease);
}

.site-header.is-scrolled .nav { padding-block: 0.75rem; }

.brand {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.2rem;
  letter-spacing: -0.01em;
  color: var(--ink);
  transition: opacity var(--speed) var(--ease);
}

.brand:hover { opacity: 0.8; }

.brand__dot { color: var(--lime); }

.nav__links {
  display: none;
  align-items: center;
  gap: var(--space-6);
  font-size: 0.94rem;
  font-weight: 500;
}

.nav__links a {
  position: relative;
  padding-block: 4px;
  color: var(--ink-soft);
  transition: color var(--speed) var(--ease);
}

.nav__links a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -3px;
  width: 100%;
  height: 2px;
  background: var(--lime);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--speed) var(--ease);
}

.nav__links a:hover { color: var(--ink); }
.nav__links a:hover::after,
.nav__links a[aria-current="page"]::after { transform: scaleX(1); }
.nav__links a[aria-current="page"] { color: var(--ink); }

.nav__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.nav__cta { display: none; }

.btn__arrow {
  display: inline-block;
  margin-left: 0.5em;
  transition: transform var(--speed) var(--ease);
}

.btn:hover .btn__arrow { transform: translateX(3px); }

.nav__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--border);
  background: var(--surface);
  cursor: pointer;
}

.nav__toggle svg { width: 20px; height: 20px; }
.nav__toggle .icon-close { display: none; }
.nav__toggle[aria-expanded="true"] .icon-open { display: none; }
.nav__toggle[aria-expanded="true"] .icon-close { display: block; }

@media (min-width: 900px) {
  .nav__links { display: flex; }
  .nav__cta { display: inline-flex; }
  .nav__toggle { display: none; }
}

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: var(--paper);
  padding: calc(var(--space-9) + var(--space-4)) var(--space-5) var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  transform: translateY(-8px);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--speed) var(--ease), transform var(--speed) var(--ease);
}

.mobile-menu.is-open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.mobile-menu__links {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 600;
}

/* Text stays ink (the mobile menu sits on paper, where lime text
   would be hard to read at this size) -- the current page is marked
   with a lime underline instead. */
.mobile-menu__links a[aria-current="page"] {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--lime);
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}

.mobile-menu__links a {
  display: inline-block;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}

.mobile-menu.is-open .mobile-menu__links a {
  opacity: 1;
  transform: translateY(0);
}

.mobile-menu__links a:nth-child(1) { transition-delay: 0.04s; }
.mobile-menu__links a:nth-child(2) { transition-delay: 0.08s; }
.mobile-menu__links a:nth-child(3) { transition-delay: 0.12s; }
.mobile-menu__links a:nth-child(4) { transition-delay: 0.16s; }
.mobile-menu__links a:nth-child(5) { transition-delay: 0.2s; }

.mobile-menu__foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding-top: var(--space-6);
  border-top: 1px solid var(--border);
  opacity: 0;
  transition: opacity 0.3s var(--ease);
  transition-delay: 0.2s;
}

.mobile-menu.is-open .mobile-menu__foot { opacity: 1; }

.mobile-menu__foot a:not(.btn) { color: var(--muted); font-size: 0.95rem; }

@media (min-width: 900px) {
  .mobile-menu { display: none; }
}

/* ---------- Hero ----------
   Redesign (Phase 24): new positioning, new composition. The previous
   version's core problem was structural, not cosmetic -- headline and
   supporting copy sat directly on a full-bleed photograph, so text and
   image permanently competed for the same visual value range no
   matter how the mask/scrim curves were tuned. Replaced the layered
   atmosphere/mid/subject crossfade with a plain asymmetric split: the
   message lives on a flat ink field (guaranteed maximum, unconditional
   contrast), the portrait lives in its own contained panel and is
   toned to sit inside the same ink/cream/lime palette rather than
   competing with it in full saturation. The portrait is demoted from
   "the composition" to "supporting character" -- present, valuable,
   but no longer the dominant visual value on the page; the headline
   is. */
.hero--full {
  position: relative;
  margin-top: -73px;
  min-height: 100vh;
  overflow: hidden;
  /* Warm charcoal, not the sitewide --ink (#131316, slightly blue) --
     kept from the previous hero: it's already warm/distinctive and
     avoids the generic "flat black tech-agency" background the brief
     explicitly warned against. */
  background: #17140f;
}

.hero__grid {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* Portrait panel: a contained block, not an atmospheric full-bleed
   background -- this alone is most of the fix, since the headline no
   longer has photo content anywhere behind it. Tonal grade (desaturated,
   contrast lifted, brightness pulled down slightly) so the photo reads
   as part of the same restrained ink/cream/lime palette as the rest of
   the hero instead of a raw full-color photo dropped beside it. */
.hero__portrait {
  position: relative;
  order: -1;
  height: 44vh;
  min-height: 260px;
  overflow: hidden;
  /* Explicit fill so the mask fade below (which makes the image's own
     bottom edge transparent) reveals this exact color, not whatever
     happens to sit behind it -- guarantees a seamless dissolve rather
     than depending on ancestor backgrounds lining up by coincidence. */
  background: #17140f;
}

.hero__portrait picture,
.hero__portrait img {
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Bottom-edge dissolve, v2. The first pass (pure alpha mask, fading
   only the last ~20% of the image to transparent) turned out to be
   imperceptible -- pixel-sampled the render and found the crop's own
   content in that zone is *already* near-black (close to #17140f)
   before the mask does anything, since object-position 62%/10% puts
   floor-level shadow there at every breakpoint. Fading transparency
   alone can't make a visible dissolve when the source pixels already
   match the destination color -- there's nothing to visibly recede.
   Two changes fix this: the mask now starts higher up, in the zone
   that still has real brightness/color (the subject's shirt, lit
   floor) so there's an actual visible journey; and a second layer
   (::after, painted in the exact background color, increasing in
   opacity toward the bottom) forces convergence to the destination
   color regardless of what the photo's own tone happens to be at any
   given point -- the mechanism the alpha-only version was missing.
   Both curves are eased (multiple stops, not one linear ramp) so the
   photo holds its full strength through the top of the zone and only
   visibly gives way in the second half, matching "strong until the
   fade begins, then genuinely dissolving" rather than a uniform ramp
   the whole way down. */
/* Right-to-left dissolve (added on top of the bottom one above), v2.
   The first version held the right 38% opaque and faded the remaining
   62% -- overlaid on a grid at 10% increments, the subject's own body
   in this crop actually runs from ~21% to ~62% of the panel's width
   (measured directly on the render, not assumed), so that fade was
   cutting straight across his head and torso. Re-measured against the
   real render at every breakpoint: his head is the leftmost point that
   matters, landing at roughly 92% from the right edge on mobile/
   tablet's crop and 84% on desktop's. Hold zones below are set a few
   points past those measured edges (safety margin, not the character's
   literal edge) so the fade is now confined to the empty margin past
   him -- only the last 6-8% (mobile/tablet) or ~14% (desktop, more
   headroom before hitting him) actually dissolves. Same for the
   vertical mask below: his feet extend to ~90% of the panel's height
   at every breakpoint, so that hold zone moved from 58%/76% up to 90%
   for the same reason -- protect the whole figure, fade only the
   margin past his feet. */
.hero__portrait img {
  object-fit: cover;
  object-position: 62% 10%;
  filter: grayscale(0.32) saturate(0.82) contrast(1.1) brightness(0.9);
  -webkit-mask-image:
    linear-gradient(to bottom, #000 0%, #000 90%, rgba(0, 0, 0, 0.7) 95%, transparent 100%),
    linear-gradient(to left, #000 0%, #000 94%, rgba(0, 0, 0, 0.6) 97%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to bottom, #000 0%, #000 90%, rgba(0, 0, 0, 0.7) 95%, transparent 100%),
    linear-gradient(to left, #000 0%, #000 94%, rgba(0, 0, 0, 0.6) 97%, transparent 100%);
  mask-composite: intersect;
}

.hero__portrait::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(to top, #17140f 0%, rgba(23, 20, 15, 0.85) 4%, transparent 10%),
    linear-gradient(to right, #17140f 0%, rgba(23, 20, 15, 0.8) 3%, transparent 6%);
}

/* Top scrim: the transparent sticky nav sits directly over this panel
   at every breakpoint (mobile stacked-on-top and desktop full-height
   alike), so its own legibility can't depend on where the photo's
   tones happen to land -- this guarantees a dark band under the header
   regardless. Unrelated to the bottom-edge dissolve above (top vs.
   bottom of the same panel), left as its own overlay since it only
   ever needs to darken, never fully reveal the background beneath. */
.hero__portrait::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(23, 20, 15, 0.68) 0%, rgba(23, 20, 15, 0) 32%);
}

.hero__overlay {
  position: relative;
  z-index: 2;
  padding: var(--space-6) var(--space-5) var(--space-7);
}

/* Small kicker label: ties the hero into the same eyebrow-plus-lime-dot
   language every other section on the site already uses (see .eyebrow)
   -- the previous hero never referenced that pattern at all, so it
   read as a different design system grafted onto the same page. */
.hero__kicker {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(243, 241, 236, 0.55);
}

.hero__kicker-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--lime); flex: none; }

/* Two co-equal lines forming one statement -- not a tiered hierarchy
   like the previous headline, since "Your Business." and "Online,
   Properly." are one connected thought, not an eyebrow/bridge/
   punchline structure. Sitting on the flat ink background (not a
   photograph), so full-weight color and a light shadow are enough for
   guaranteed contrast at any breakpoint. */
.hero__headline {
  margin-top: var(--space-4);
  font-family: "Big Shoulders Display", var(--font-display), sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  line-height: 0.92;
  letter-spacing: 0.005em;
  font-size: clamp(2.6rem, 1.6rem + 8.6vw, 4.4rem);
  color: #f3f1ec;
}

.hero__headline-line { display: block; }

/* The one deliberate use of lime inside the headline itself: the word
   that carries the actual promise ("Properly"), not a stray mark --
   ties the accent color directly to meaning instead of decoration. */
.hero__headline-mark { color: var(--lime); }

.hero__sub {
  margin-top: var(--space-4);
  font-size: 1rem;
  color: rgba(243, 241, 236, 0.72);
  max-width: 34ch;
}

.hero__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  margin-top: var(--space-5);
  padding: 0.85em 1.6em;
  border: 1.5px solid rgba(243, 241, 236, 0.55);
  font-weight: 600;
  font-size: 0.85rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #f3f1ec;
  transition: border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}

.hero__cta:hover { border-color: var(--lime); color: var(--lime); }

.hero__cta-arrow { display: inline-block; transition: transform var(--speed) var(--ease); }
.hero__cta:hover .hero__cta-arrow { transform: translateX(3px); }

.hero__foot { margin-top: var(--space-6); }

.hero__foot-rule { display: block; height: 1px; background: rgba(243, 241, 236, 0.3); margin-bottom: var(--space-3); }

.hero__foot-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin-bottom: var(--space-3);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(243, 241, 236, 0.7);
}

.hero__foot-tag {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.02em;
  color: rgba(243, 241, 236, 0.5);
}

.hero__barcode {
  display: inline-block;
  flex: none;
  width: 46px;
  height: 12px;
  background-image: repeating-linear-gradient(to right, rgba(243, 241, 236, 0.8) 0 1px, transparent 1px 3px);
}

/* ---------- Featured project ----------
   Anchored to the portrait panel itself now (its own containing
   block), bottom-left, overlapping the photo's own lower corner --
   still no card/border/shadow, a printed-photo-credit treatment like
   before.

   Width below 1024px is deliberately narrower than the desktop rule --
   the same bottom-left corner sits over empty background at the
   1024px+ crop, but object-fit:cover reframes the same source image
   very differently at the mobile/tablet stacked crop, where the
   subject's own body runs much closer to that corner. Measured
   directly on the render (not assumed): at the base (<480px) crop his
   sleeve/arm falls at roughly 35% from the left, so the card is sized
   to end well inside that; at the 480-1023px crop the nearest figure
   (a background subject, not him) sits further out, so the card can
   stay a little wider there. Position (left/bottom) is unchanged --
   only width shrinks, at both tiers, to open real breathing room
   instead of the card's edge landing flush against a person. */
.hero__featured {
  display: block;
  position: absolute;
  left: var(--space-5);
  bottom: var(--space-5);
  z-index: 2;
  width: 5.5rem;
}

.hero__featured-frame { display: block; aspect-ratio: 1440 / 820; overflow: hidden; }

/* position:static explicitly undoes .hero__portrait picture, .hero__portrait
   img's position:absolute;inset:0 (added in 7dd4e70 for the main portrait's
   own height-circularity fix) -- that's a descendant selector, so it was
   also matching this thumbnail img three levels deep inside .hero__portrait,
   sizing it against .hero__featured (its nearest positioned ancestor once
   absolute) instead of this frame, letting it escape the frame's
   aspect-ratio/overflow:hidden box and bleed over the caption below. Back
   to static, width/height:100% resolves normally against the frame's own
   aspect-ratio-derived height instead. */
.hero__featured-frame img {
  display: block;
  position: static;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
  transition: transform 0.5s var(--ease);
}

.hero__featured:hover .hero__featured-frame img { transform: scale(1.05); }

.hero__featured-caption {
  display: block;
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--lime);
}

.hero__featured-title {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.78rem;
  color: #f3f1ec;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85), 0 2px 10px rgba(0, 0, 0, 0.6);
}

.hero__featured-meta {
  display: block;
  margin-top: 0.2em;
  font-family: var(--font-mono);
  font-size: 0.56rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: rgba(243, 241, 236, 0.75);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85), 0 2px 10px rgba(0, 0, 0, 0.6);
}

@media (min-width: 480px) {
  .hero__featured { width: 8rem; }
}

@media (min-width: 640px) {
  .hero__overlay { padding-inline: var(--space-6); }
  .hero__portrait { height: 50vh; }
}

/* 1024px+: the stacked panel becomes a true side-by-side split --
   text column vertically centered on a flat ink field, portrait column
   filling the full hero height flush to the right edge. This is the
   core structural change from the previous full-bleed-photo hero. */
@media (min-width: 1024px) {
  /* min-height (not height) + flex, not height:100% on the grid below:
     a fixed height + overflow:hidden clipped the foot-tag row whenever
     a real browser window was shorter than ~730px (verified -- common
     laptop window heights, not an edge case).

     Three things had to be true together, not one swap:
     1. .hero--full needs min-height (grow if content needs it) instead
        of a hard height, so overflow:hidden never truncates content.
     2. .hero__grid needs a *definite* height to hand down to its own
        height:100% descendants -- flex (flex:1) with min-height:0 on
        the grid item gives it that, since flex resolves an item's used
        size independently of its content, unlike a plain block whose
        auto height would stay circular against this min-height-only
        parent.
     3. Even with both of those, .hero__portrait img's OWN height:100%
        was still falling back to its intrinsic aspect ratio (measured:
        833px / 1111px exactly matches column-width / 0.7513, the
        source image's own ratio) as long as the img itself sized via
        width/height percentages -- an ordinary in-flow replaced
        element still consults its own intrinsic ratio the moment any
        ancestor in the chain resolves as indefinite during layout.
        Making the picture/img absolutely positioned (inset:0 within
        .hero__portrait, already position:relative) removes it from
        that flow-sizing algorithm entirely: it just fills whatever box
        .hero__portrait ends up with, however that box's size was
        determined, with nothing left to fall back on. */
  .hero--full { display: flex; flex-direction: column; min-height: calc(100vh - 73px); }

  .hero__grid {
    display: grid;
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    min-height: 0;
    flex: 1;
  }

  .hero__overlay {
    order: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: var(--space-8) clamp(var(--space-6), 5vw, 5rem);
    max-width: 42rem;
  }

  .hero__headline { font-size: clamp(4.2rem, 2.2rem + 3.6vw, 7.2rem); }

  .hero__portrait { order: 1; height: 100%; }

  /* Same character-safety re-measurement as the base rule above, using
     this breakpoint's own object-position (58%/6%, slightly different
     crop than mobile/tablet's 62%/10%): his head lands at ~84% from
     the right edge and his feet at ~90% of the panel's height here,
     so the hold zones are set a few points past those, not the 38%/76%
     the previous pass used. Desktop keeps a bit more fade room than
     mobile/tablet (there's more empty margin past him at this crop)
     but the principle is identical -- fade the margin, not him. */
  .hero__portrait img {
    object-position: 58% 6%;
    -webkit-mask-image:
      linear-gradient(to bottom, #000 0%, #000 90%, rgba(0, 0, 0, 0.7) 95%, transparent 100%),
      linear-gradient(to left, #000 0%, #000 86%, rgba(0, 0, 0, 0.6) 93%, transparent 100%);
    -webkit-mask-composite: source-in;
    mask-image:
      linear-gradient(to bottom, #000 0%, #000 90%, rgba(0, 0, 0, 0.7) 95%, transparent 100%),
      linear-gradient(to left, #000 0%, #000 86%, rgba(0, 0, 0, 0.6) 93%, transparent 100%);
    mask-composite: intersect;
  }

  .hero__portrait::after {
    background:
      linear-gradient(to top, #17140f 0%, rgba(23, 20, 15, 0.85) 4%, transparent 10%),
      linear-gradient(to right, #17140f 0%, rgba(23, 20, 15, 0.8) 6%, transparent 14%);
  }

  .hero__featured {
    left: auto;
    right: var(--space-6);
    bottom: var(--space-6);
    width: min(60%, 12.5rem);
  }
}

/* The header itself is untouched -- see the Header/Nav rules above --
   but its brand/link text color (var(--ink), near-black) assumes the
   light backgrounds every other page has behind it. On the homepage,
   before any scroll, the header sits transparent over the new dark
   hero photo instead, which would make that text unreadable (near-
   black on a near-black photo). This override only fires in that one
   state -- body.is-home (index.html only) AND :not(.is-scrolled) --
   and reverts automatically once .is-scrolled gives the header its
   normal opaque light background back, at which point the original
   dark text is correct again. */
body.is-home .site-header:not(.is-scrolled) .brand,
body.is-home .site-header:not(.is-scrolled) .nav__links a {
  color: #f3f1ec;
}

body.is-home .site-header:not(.is-scrolled) .brand__dot { color: var(--lime); }

body.is-home .site-header:not(.is-scrolled) .nav__links a::after { background: var(--lime); }

/* Opaque ink fill, not a transparent outline: the header now often
   sits over the bright/busy photo column (not a uniformly dark
   surface), where a transparent button becomes illegible. An opaque
   background keeps it readable regardless of what's behind it. */
body.is-home .site-header:not(.is-scrolled) .nav__cta {
  background: var(--ink);
  border-color: var(--ink);
  color: #f3f1ec;
}

body.is-home .site-header:not(.is-scrolled) .nav__cta:hover {
  background: var(--ink);
  border-color: var(--lime);
  color: var(--lime);
}

/* ---------- Trust strip (home page, directly under the hero) ----------
   A quiet typographic bridge between the hero and Introduction, not a
   feature grid: a hairline seam under the hero, four short facts led by
   a small mono label (echoing .eyebrow) rather than a bold SaaS-style
   icon strip, tighter padding than .section, muted rather than
   accent-coloured icons so it never competes with the hero above it. */
.trust-strip {
  border-top: 1px solid var(--border);
  padding-block: var(--space-5);
}

.trust-strip__list {
  display: grid;
  gap: var(--space-5) var(--space-6);
  grid-template-columns: 1fr;
}

@media (min-width: 620px) {
  .trust-strip__list { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 980px) {
  .trust-strip__list {
    grid-template-columns: repeat(4, 1fr);
    gap: 0;
  }

  .trust-strip__item {
    padding-inline: var(--space-5);
    border-left: 1px solid var(--border);
  }

  .trust-strip__item:first-child { padding-left: 0; border-left: none; }
  .trust-strip__item:last-child { padding-right: 0; }
}

.trust-strip__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.trust-strip__index {
  flex: none;
  padding-top: 1px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--muted-2);
}

.trust-strip__item span {
  display: block;
  min-width: 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--muted);
}

.trust-strip__item strong {
  display: block;
  margin-bottom: 2px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  font-weight: 500;
}

/* Charcoal variant: required for the hero -> Introduction transition
   (the homepage Introduction below is now dark too) -- left on its
   light background, this strip would sit as a jarring pale band
   between two dark sections. Colors only; layout is untouched. Same
   warm charcoal literal as .section--charcoal and the hero for
   visual continuity. */
.trust-strip--charcoal {
  background: #17140f;
  border-top-color: rgba(243, 241, 236, 0.14);
}

.trust-strip--charcoal .trust-strip__item { border-left-color: rgba(243, 241, 236, 0.14); }
.trust-strip--charcoal .trust-strip__index { color: rgba(243, 241, 236, 0.45); }
.trust-strip--charcoal .trust-strip__item span { color: #a39d90; }
.trust-strip--charcoal .trust-strip__item strong { color: #f3f1ec; }

/* ---------- Manifesto (Introduction) ----------
   An editorial opening statement rather than a centered "about" blurb:
   the eyebrow numbering sits in its own narrow margin column (like a
   running head/folio in a magazine spread) beside a large display
   statement, with a smaller supporting paragraph underneath -- the
   asymmetry itself is the section's whole visual idea, so it needs no
   further decoration. */
.manifesto__grid {
  display: grid;
  gap: var(--space-4);
}

@media (min-width: 860px) {
  .manifesto__grid {
    grid-template-columns: 180px 1fr;
    gap: var(--space-8);
  }

  .manifesto__index { padding-top: 0.5em; }
}

.manifesto__statement {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
  font-size: clamp(2rem, 1.1rem + 3.6vw, 3.8rem);
  max-width: 15ch;
  color: var(--ink);
}

.manifesto__support {
  margin-top: var(--space-5);
  font-size: var(--fs-lead);
  color: var(--muted);
  max-width: 56ch;
}

/* Dark-charcoal context (.section--charcoal, homepage Introduction
   only): off-white statement and a warm-toned muted gray for the
   support line, rather than this pair's light-background colors. */
.section--charcoal .manifesto__statement { color: #f3f1ec; }
.section--charcoal .manifesto__support { color: #a39d90; }

/* ---------- Cards ---------- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  transition: transform var(--speed) var(--ease), box-shadow var(--speed) var(--ease), border-color var(--speed) var(--ease);
}

a.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-md);
  border-color: var(--border);
}

.card h3 { margin-bottom: var(--space-2); }
.card p { color: var(--muted); font-size: var(--fs-small); }

/* ---------- Services (Phase: 02 -- What I Build) ----------
   The site's deliberate dark-to-light hinge: Hero and Introduction are
   dark editorial, Selected Work onward is paper again, and this
   section is where that switch happens. Kept on the standard light
   .section background (no --alt needed), but rebuilt so it reads as
   the same design system as the approved dark sections -- an
   editorial numbered sequence (echoing Trust Strip's 01-04 and
   Introduction's own "01 --" folio mark) rather than a SaaS feature
   grid. The previous version wrapped the lead item in the sitewide
   .card component (white surface, border, radius, shadow) -- that's
   removed entirely; hierarchy here comes from type scale, spacing and
   a hairline column rule, not a UI container. Scoped under
   .services-preview throughout so none of this reaches .section-head,
   .eyebrow or .card as used on other pages. */
.services-preview__heading {
  margin-top: var(--space-3);
  font-size: clamp(1.8rem, 1.3rem + 2vw, 2.6rem);
}

/* Small, restrained lime mark -- lime reads as near-invisible running
   text on this light background (measured elsewhere in this system),
   so it's used here only as a small decorative dot, not as text
   color, mirroring how sparingly the hero itself uses solid lime
   fills against its own bright zones. */
.services-preview .eyebrow::before { background: var(--lime); }

.services {
  display: grid;
  gap: var(--space-7);
}

@media (min-width: 860px) {
  .services {
    grid-template-columns: 1.05fr 1fr;
    align-items: start;
    gap: var(--space-9);
  }

  .services__list { border-left: 1px solid var(--border); padding-left: var(--space-8); }
}

.services__lead {
  padding-top: var(--space-5);
  border-top: 1px solid var(--ink);
}

.services__lead h3 {
  margin-top: var(--space-4);
  font-size: clamp(2rem, 1.5rem + 2.2vw, 3rem);
}

.services__lead p {
  margin-top: var(--space-3);
  color: var(--muted);
  max-width: 42ch;
}

/* Editorial index numbering instead of icons -- reads as a
   contents-page list (01/WEB DESIGN, 02/...) rather than a feature
   grid. The lead's own number is sized up to carry real weight
   without becoming a graphic element; list rows stay small. */
.services__index {
  display: block;
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  color: var(--muted-2);
  transition: color var(--speed) var(--ease);
}

.services__lead .services__index { font-size: 1rem; }

.services__cta {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  margin-top: var(--space-6);
  padding-bottom: 0.2em;
  border-bottom: 1.5px solid var(--ink);
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink);
  transition: border-color var(--speed) var(--ease);
}

.services__cta-arrow { display: inline-block; transition: transform var(--speed) var(--ease); }
.services__cta:hover { border-color: var(--lime); }
.services__cta:hover .services__cta-arrow { transform: translateX(3px); }

.services__list {
  display: flex;
  flex-direction: column;
}

.services__row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding-block: var(--space-5);
  border-top: 1px solid var(--border);
  border-left: 2px solid transparent;
  padding-left: var(--space-3);
  margin-left: calc(-1 * var(--space-3));
  transition: border-color var(--speed) var(--ease);
}

.services__row:first-child { border-top: none; padding-top: 0; }
.services__row:last-child { padding-bottom: 0; }

.services__row .services__index { font-size: 0.85rem; flex: none; width: 2ch; padding-top: 0.2em; }
.services__row h3 { margin-bottom: var(--space-1); font-size: 1.15rem; }
.services__row p { color: var(--muted); font-size: var(--fs-small); margin: 0; }

/* Restrained hover: a lime rule grows in on the left rather than the
   row shifting position or picking up the old blue accent color --
   color-only elsewhere, no movement, no shadow. */
.services__row:hover { border-left-color: var(--lime); }

/* Standalone text-link style (e.g. "Explore My Services", "View All
   Work") -- shared across pages, so kept even though the card
   component it originally lived alongside (image + tag + body) was
   retired in the Selected Work redesign in favour of .work-spread. */
.work-card__link {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink);
}

.work-card__link svg { width: 16px; height: 16px; transition: transform var(--speed) var(--ease); }
.work-card__link:hover svg { transform: translateX(3px); }

/* ---------- Selected Work (editorial project spreads) ----------
   Real case-study entries, not a card grid: each project is a "spread"
   with its own oversized number, metadata line, title and short
   description, hairline-ruled from the next rather than boxed. Four
   layout variants (side, side-reverse, compact, stacked) give the
   sequence real editorial variety while sharing one visual language,
   per the redesign brief -- deliberately not all identical, but built
   from the same handful of parts so the sequence still reads as one
   coherent system. */
/* Selected Work is the main feature of the homepage, so it gets more
   room to breathe than the sections either side of it -- deliberate
   rhythm rather than the uniform padding every other section shares. */
#selected-work { padding-block: var(--space-9); }

.work-spreads { margin-top: var(--space-8); }

.work-spread {
  padding-block: var(--space-9);
  border-top: 1px solid var(--border);
}

.work-spread:first-child { border-top: none; padding-top: 0; }

.work-spread__visual {
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  transition: transform 0.4s var(--ease);
}

.work-spread__visual:hover { transform: translateY(-4px); }

.work-spread__visual img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
  transition: transform 0.6s var(--ease);
}

.work-spread__visual:hover img { transform: scale(1.03); }

.work-spread__number {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(3rem, 1.8rem + 4vw, 5.6rem);
  line-height: 1;
  color: var(--border);
}

/* Safwa opens the sequence right after the hero, so its number carries
   a quiet accent tint -- the one deliberate, restrained use of colour
   in the section, marking it as the lead case study rather than just
   "spread one of four". Was a leftover legacy-blue tint. Raw lime is
   too close in lightness to the warm paper behind it to read as a
   ghost numeral at any opacity (unlike a solid button fill, this is a
   huge translucent glyph, so luminance -- not hue -- is what makes it
   visible), so this uses a deepened, muted lime instead of var(--lime)
   directly, tuned to sit at roughly the same quiet visual weight the
   blue tint had. */
.work-spreads > .work-spread:first-child .work-spread__number {
  color: #c8d24a;
}

.work-spread__meta {
  margin-top: var(--space-2);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

.work-spread__title { margin-top: var(--space-3); font-size: var(--fs-h2); }
.work-spread__desc { margin-top: var(--space-4); color: var(--muted); max-width: 48ch; }

.work-spread__link {
  margin-top: var(--space-5);
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-weight: 600;
  color: var(--ink);
  position: relative;
  padding-block: 0.3em;
}

.work-spread__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--speed) var(--ease);
}

.work-spread__link:hover::after { transform: scaleX(1); }
.work-spread__link svg { width: 16px; height: 16px; transition: transform var(--speed) var(--ease); }
.work-spread__link:hover svg { transform: translateX(3px); }

/* Layout A -- "side": visual left, body right. The default, most
   editorial two-column spread (large image / small metadata / large
   title / short description). */
.work-spread--side { display: grid; gap: var(--space-6); }
.work-spread--side .work-spread__visual { aspect-ratio: 1440 / 820; }

@media (min-width: 900px) {
  .work-spread--side { grid-template-columns: 1.5fr 1fr; align-items: center; gap: var(--space-8); }
}

/* Safwa is the opening case study right after the hero, so its image
   runs a touch taller than the other spreads' native screenshot ratio
   -- more presence for the first thing seen after the cover. */
.work-spreads > .work-spread:first-child .work-spread__visual { aspect-ratio: 1440 / 900; }

/* Layout B -- "side-reverse": visual right, body left, and the title
   pulls up over the tail of the oversized number (negative margin
   only -- no absolute positioning) so the numeral and title visually
   cross, per the brief's "project title crossing the visual
   hierarchy". */
.work-spread--side-reverse { display: grid; gap: var(--space-6); }
.work-spread--side-reverse .work-spread__visual { aspect-ratio: 1440 / 820; }

@media (min-width: 900px) {
  .work-spread--side-reverse {
    grid-template-columns: 1fr 1.5fr;
    align-items: center;
    gap: var(--space-8);
  }
  .work-spread--side-reverse .work-spread__visual { order: 2; }
  .work-spread--side-reverse .work-spread__body { order: 1; }
  .work-spread--side-reverse .work-spread__title { margin-top: calc(var(--space-2) * -1); }
}

/* Layout C -- "compact": a constrained (not full-column-width) image
   with real surrounding whitespace, per the brief's "different image
   scale, strong whitespace, small technical metadata" -- but still
   substantial enough to feel confident rather than like an
   afterthought, since Madani is a flagship-tier project. */
.work-spread--compact { display: grid; gap: var(--space-6); }
.work-spread--compact .work-spread__visual { aspect-ratio: 3 / 2; max-width: 460px; }
.work-spread--compact .work-spread__visual img { object-position: left top; }

@media (min-width: 900px) {
  .work-spread--compact { grid-template-columns: 1fr 1.1fr; align-items: center; gap: var(--space-8); }
  .work-spread--compact .work-spread__visual { order: 2; margin-left: auto; }
  .work-spread--compact .work-spread__body { order: 1; }
}

/* Layout D -- "stacked": full-width image on top, number/meta and
   title/description running as a two-column foot beneath it -- a
   structural variant (not just a mirrored side-by-side) that closes
   the sequence. */
.work-spread--stacked .work-spread__visual { aspect-ratio: 1440 / 620; }

.work-spread--stacked .work-spread__foot {
  margin-top: var(--space-6);
  display: grid;
  gap: var(--space-4);
}

/* ---------- Selected Work -- per-project image art direction ----------
   Each source screenshot has its own focal point; "cover + top" is
   only correct where the strongest visual information genuinely sits
   at the top of the frame. Decided per project, not inherited as one
   sitewide default. */

/* Safwa: nav, eyebrow, headline and both CTAs all sit in the upper
   two-thirds of the frame; the only things near the left/right edges
   are the logo and the WhatsApp pill, which can afford the small
   horizontal trim this aspect-ratio change already produces. Center
   top keeps the headline block centered under that trim either way. */
.work-spread--safwa .work-spread__visual img { object-position: center top; }

/* NOVAÉ: the original homepage screenshot (novae-home.jpg) was mostly
   empty gradient with its headline sitting at the very bottom edge and
   its subhead cut off -- a bad source crop, not something object-fit
   could fix. Swapped to the New Arrivals screenshot (novae-products.jpg),
   whose headline and product grid sit at the top of the frame like
   every other spread in this section. */
.work-spread--novae .work-spread__visual img { object-position: center top; }

/* Klinik Ceria: cropping to this spread's wide aspect ratio trims
   roughly the bottom quarter of the source. That's the "Need to visit
   us?" info strip, not the hero -- headline, CTAs and the clinic
   illustration all sit above it and survive fully intact. */
.work-spread--klinik .work-spread__visual img { object-position: center top; }

/* Below the two-column breakpoint every spread becomes a single
   full-width column, which is where side and side-reverse start to
   look identical. A slight right-inset on the reversed spread's image
   echoes its "flipped" desktop identity without a second grid column. */
@media (max-width: 899px) {
  .work-spread--side-reverse .work-spread__visual {
    width: 92%;
    margin-left: auto;
  }
}

@media (min-width: 720px) {
  .work-spread--stacked .work-spread__foot { grid-template-columns: 200px 1fr; gap: var(--space-6); }
}

/* ---------- Selected Work -- compact index of remaining projects ----------
   The rest of the studio's real work, listed the way a magazine's
   contents page lists shorter items after the featured spreads --
   deliberately not thumbnails: only one of the three (Royale
   Chesterfield) has real project photography in the repo, so adding
   an image to that row alone would look more unfinished than none at
   all, not less. The distinction from the four featured spreads above
   is made with typography and rhythm instead -- a smaller but still
   lime-numbered index, a real display-face name, and a labelled
   "More Selected Work" divider so the tier change reads as
   intentional archive, not an afterthought. */
.work-index__label {
  margin-top: var(--space-8);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.work-index { margin-top: var(--space-3); border-bottom: 1px solid var(--border); }

.work-index__row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas: "index name link" "index category link";
  align-items: center;
  row-gap: 0.3em;
  column-gap: var(--space-5);
  padding-block: var(--space-5);
  border-top: 1px solid var(--border);
  transition: border-color var(--speed) var(--ease);
}

.work-index__row:hover { border-top-color: var(--lime); }

.work-index__index {
  grid-area: index;
  align-self: start;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: clamp(1.6rem, 1vw + 1.3rem, 2.2rem);
  color: var(--lime);
  width: 2ch;
}

.work-index__name {
  grid-area: name;
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.15rem, 0.5vw + 1.02rem, 1.4rem);
  color: var(--ink);
}

.work-index__category {
  grid-area: category;
  display: block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

.work-index__link {
  grid-area: link;
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding-block: 0.3em;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
}

.work-index__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--speed) var(--ease);
}

.work-index__row:hover .work-index__link::after { transform: scaleX(1); }
.work-index__link svg { width: 15px; height: 15px; transition: transform var(--speed) var(--ease); }
.work-index__row:hover .work-index__link svg { transform: translateX(3px); }

@media (max-width: 639px) {
  .work-index__row {
    grid-template-columns: auto 1fr;
    grid-template-areas: "index name" "index category" "link link";
    row-gap: 0.4em;
  }
  .work-index__link { justify-self: start; margin-top: var(--space-2); }
}

/* ---------- Why Ajak -- founder line ---------- */
/* Founder line: a first-person statement inside the "Why Ajak" section
   head, sitting between the h2 and the checklist. Deliberately not the
   shared .section-head p (muted, same weight as every other section's
   generic lead-in) -- darker and a touch heavier so it reads as Ajak
   speaking, while staying well short of the h2's display-type weight.
   Selector is ".section-head p.founder-line" (rather than bare
   ".founder-line") so it outranks the generic ".section-head p" rule,
   which otherwise wins on specificity and silently mutes it back down. */
.section-head p.founder-line {
  margin-top: var(--space-4);
  font-size: 1.05rem;
  font-weight: 500;
  color: var(--ink-soft);
}

/* ---------- Why Ajak (editorial statement, not a benefits grid) ----------
   Asymmetric two-column layout echoing the Introduction manifesto:
   the statement + founder line sit in one column, the reasons run as a
   plain ruled list (numbered, no icons) in the other -- a confident
   editorial statement rather than a checklist of feature badges. */
.why-ajak__grid { display: grid; gap: var(--space-6); }

@media (min-width: 860px) {
  .why-ajak__grid { grid-template-columns: 1.1fr 0.9fr; gap: var(--space-8); align-items: start; }
}

/* This section's heading previously had no font-size rule of its own
   and was silently falling back to the browser's default <h2> size
   (a flat 24px at every viewport) -- the same gap Services and
   Introduction each avoided by giving their own heading a dedicated
   class. Scale follows that precedent: a bit more assertive than
   Services' clamp(1.8rem, 1.3rem + 2vw, 2.6rem) since this is framed
   as a standalone statement (like the Introduction manifesto) rather
   than a preview heading, but capped well short of Introduction's own
   scale so it doesn't compete with it. font-family/weight/line-height
   still come from the shared h1,h2,h3,h4 rule -- only font-size is set
   here. */
.why-ajak__statement {
  font-size: clamp(1.9rem, 1.3rem + 2.4vw, 2.9rem);
}

/* Eyebrow dot only: Why Ajak's own accent-system correction, scoped to
   this section so it can't reach the shared .eyebrow/.eyebrow::before
   rule used elsewhere. The eyebrow text already renders neutral here
   (the more-specific .section-head p rule already outranks the plain
   .eyebrow color), so only the dot needs to move off the legacy blue. */
.why-ajak__grid .eyebrow::before { background: var(--lime); }

.why-ajak__list { display: flex; flex-direction: column; }

.why-ajak__list li {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  padding-block: var(--space-4);
  border-top: 1px solid var(--border);
  font-size: 0.98rem;
}

.why-ajak__list li:first-child { border-top: none; padding-top: 0; }
.why-ajak__list li:last-child { padding-bottom: 0; }

.why-ajak__index {
  flex: none;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--muted-2);
}

/* ---------- Steps (numbered process — used where order is real) ---------- */
.steps {
  display: grid;
  gap: var(--space-6);
}

@media (min-width: 720px) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .steps--5 { grid-template-columns: repeat(5, 1fr); } }

.step__num {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--muted-2);
  margin-bottom: var(--space-3);
}

.step h3 { margin-bottom: var(--space-2); font-size: var(--fs-h3); }
.step p { color: var(--muted); font-size: var(--fs-small); }

/* ---------- Final CTA band ---------- */
.cta-band {
  border-radius: var(--radius-lg);
  padding: var(--space-8) var(--space-6);
  text-align: center;
}

/* Global color-system alignment: same warm charcoal as the approved
   Hero/Introduction/Services, not the cooler sitewide --ink. Scoped to
   the .cta-band + .section--ink combination specifically (the only
   place the two classes are ever paired) rather than changing bare
   .section--ink, which stays available at its original value for any
   other use. */
.cta-band.section--ink { background: #17140f; }

.cta-band .eyebrow { justify-content: center; margin-bottom: var(--space-4); }

.cta-band h2 { max-width: 20ch; margin-inline: auto; }

/* This heading had no font-size rule of its own and was falling back
   to the browser's default <h2> size (a flat 24px at every viewport),
   the same gap already found and fixed on Why Ajak -- here it also
   let the "WhatsApp Me" link's own responsive clamp grow past it from
   768px up, an inversion where the action reads louder than the
   statement above it. Reuses Why Ajak's exact scale rather than a new
   one, since both are the same "closing statement" weight in this
   system. Shared with .cta-band, so this corrects About/Services/
   Work's identical CTA bands at the same time. */
.cta-band__statement {
  font-size: clamp(1.9rem, 1.3rem + 2.4vw, 2.9rem);
}

.cta-band p {
  margin-top: var(--space-4);
  color: rgba(250, 249, 245, 0.75);
  max-width: 46ch;
  margin-inline: auto;
}

/* Closing spread: one dominant typographic link (not a button, and not
   competing with a second equal-weight button) with a small, quieter
   secondary text link underneath for the alternate contact channel. */
.cta-band__actions { margin-top: var(--space-7); }

.cta-band__primary {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.3rem, 1rem + 1.2vw, 1.8rem);
  text-transform: uppercase;
  letter-spacing: 0.01em;
  color: var(--paper);
  position: relative;
  padding-block: 0.3em;
}

.cta-band__primary::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--speed) var(--ease);
}

.cta-band__primary:hover::after { transform: scaleX(1); }
.cta-band__primary span[aria-hidden] { display: inline-block; transition: transform var(--speed) var(--ease); }
.cta-band__primary:hover span[aria-hidden] { transform: translateX(4px); }

.cta-band__secondary {
  margin-top: var(--space-4);
  font-size: 0.9rem;
  color: rgba(250, 249, 245, 0.6);
}

.cta-band__secondary a { color: rgba(250, 249, 245, 0.88); text-decoration: underline; text-underline-offset: 3px; }
.cta-band__secondary a:hover { color: var(--paper); }

/* ---------- Footer ---------- */
.site-footer {
  /* Warm charcoal, not the sitewide --ink (#131316, slightly cool) --
     matches the CTA band directly above it (same literal value as
     .section--charcoal, the hero and .trust-strip--charcoal) instead
     of ending the page on a different, cooler dark tone. */
  background: #17140f;
  color: rgba(250, 249, 245, 0.82);
  padding-block: var(--space-8) var(--space-6);
}

.footer__top {
  display: grid;
  gap: var(--space-7);
  padding-bottom: var(--space-7);
  border-bottom: 1px solid var(--border-on-dark);
}

@media (min-width: 720px) {
  .footer__top { grid-template-columns: 1.2fr 0.9fr 0.9fr 0.9fr; }
}

.footer__brand .brand { color: var(--paper); margin-bottom: var(--space-3); }
.footer__brand p { color: rgba(250, 249, 245, 0.6); max-width: 34ch; font-size: var(--fs-small); }

/* Colophon-style production line: mono, quiet, under the tagline --
   the same small technical-metadata treatment used everywhere else on
   the site, so the footer reads as the publication's closing page. */
.footer__reg {
  margin-top: var(--space-3);
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  /* 0.4 measured ~3.7:1 against --ink, under the 4.5:1 WCAG AA
     minimum for this text size -- 0.5 clears it (~5.1:1). */
  color: rgba(250, 249, 245, 0.5);
}

.footer__heading {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* 0.45 measured ~4.3:1 against --ink, just under the 4.5:1 WCAG AA
     minimum for this text size -- 0.5 clears it (~5.1:1). */
  color: rgba(250, 249, 245, 0.5);
  margin-bottom: var(--space-4);
}

.footer__list { display: flex; flex-direction: column; gap: var(--space-3); font-size: 0.94rem; }
.footer__list a:hover { color: var(--paper); }

.footer__bottom {
  padding-top: var(--space-5);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  /* 0.45 measured ~4.4:1 against --ink, just under the 4.5:1 WCAG AA
     minimum for this text size -- 0.5 clears it (~5.1:1). */
  color: rgba(250, 249, 245, 0.5);
}

/* ---------- Entrance animation ----------
   Plays once automatically shortly after each section paints —
   it is NOT tied to scrolling into view. That's deliberate: a
   scroll-triggered version can leave long sections sitting at
   opacity:0 (invisible) until the visitor scrolls to the exact
   right spot, which on some sections/screens never quite happens.
   This way every section becomes fully visible within a second of
   the page loading, scroll or no scroll, with just a soft lift-in
   for polish. */
.reveal {
  animation: reveal-in 0.7s var(--ease) both;
  animation-delay: 0.05s;
}

@keyframes reveal-in {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .reveal { animation: none; opacity: 1; transform: none; }
}

/* ---------- Hero entrance sequence ---------- */
.hero__overlay.reveal { animation-delay: 0.15s; }
.hero__featured.reveal { animation-delay: 0.35s; }

/* ---------- Work page entrance sequence ---------- */
.work-toc.reveal { animation-delay: 0.32s; }

.work-feature__head.reveal { animation-delay: 0.05s; }
.work-feature__visual.reveal { animation-delay: 0.14s; }
.work-feature__meta.reveal { animation-delay: 0.05s; }

.numbered-list li.reveal:nth-child(1) { animation-delay: 0.05s; }
.numbered-list li.reveal:nth-child(2) { animation-delay: 0.1s; }
.numbered-list li.reveal:nth-child(3) { animation-delay: 0.15s; }
.numbered-list li.reveal:nth-child(4) { animation-delay: 0.2s; }
.numbered-list li.reveal:nth-child(5) { animation-delay: 0.25s; }

.work-story-item.reveal:nth-child(1) { animation-delay: 0.05s; }
.work-story-item.reveal:nth-child(2) { animation-delay: 0.1s; }
.work-story-item.reveal:nth-child(3) { animation-delay: 0.15s; }
.work-story-item.reveal:nth-child(4) { animation-delay: 0.2s; }
.work-story-item.reveal:nth-child(5) { animation-delay: 0.25s; }
.work-story-item.reveal:nth-child(6) { animation-delay: 0.3s; }

/* ---------- Utility ---------- */
.mt-0 { margin-top: 0 !important; }
.text-muted { color: var(--muted); }

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -60px;
  background: var(--ink);
  color: var(--paper);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-sm);
  z-index: 200;
  transition: top var(--speed) var(--ease);
}

.skip-link:focus { top: var(--space-4); }

/* =========================================================
   Page-specific components
   ========================================================= */

/* ---------- Page header (inner-page opening spread) ----------
   The inner-page equivalent of the homepage's manifesto: a small
   numbered eyebrow in its own margin column beside an oversized
   statement, rather than a conventional centered page title. Shared
   by About, Services, Work and Contact so each page opens with the
   same editorial move -- distinct content, same system. Title-case
   (not the hero's uppercase treatment) so inner pages read as
   further spreads in the publication, not a second cover. */
.page-header {
  padding-top: var(--space-8);
  padding-bottom: var(--space-8);
}

.page-header__grid {
  display: grid;
  gap: var(--space-4);
}

@media (min-width: 860px) {
  .page-header__grid { grid-template-columns: 180px 1fr; gap: var(--space-8); }
  .page-header__index { padding-top: 0.5em; }
}

.page-header h1 {
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.01em;
  font-size: clamp(2.2rem, 1.2rem + 4vw, 4.2rem);
  max-width: 14ch;
  color: var(--ink);
}

.page-header p {
  margin-top: var(--space-5);
  color: var(--muted);
  font-size: var(--fs-lead);
  max-width: 56ch;
}

/* ---------- About / Founder ---------- */
.founder {
  display: grid;
  gap: var(--space-7);
  align-items: center;
}

@media (min-width: 860px) {
  .founder { grid-template-columns: 0.7fr 1.3fr; }
}

/* Same real photo as the homepage hero, reused with a different crop
   (bust-length, object-position:top on a 4:5 box vs the hero's tall
   near-full-body frame) -- a different composition from the same
   photograph, not a duplicate of the hero, and not a fabricated
   second portrait. Square (unrounded) edges to match the hero
   portrait's photographic, non-card treatment. */
.founder__photo {
  width: 100%;
  max-width: 320px;
  aspect-ratio: 4 / 5;
  margin-inline: auto;
  background: var(--paper-alt);
  overflow: hidden;
}

.founder__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

.founder__title { color: var(--muted-2); margin-bottom: var(--space-2); }
.founder h3.founder__name { font-size: var(--fs-h2); margin-bottom: var(--space-4); }
.founder p { color: var(--muted); }
.founder p + p { margin-top: var(--space-4); }

/* ---------- Approach / process steps with connector ---------- */
.approach {
  position: relative;
}

.step {
  position: relative;
  padding-left: var(--space-1);
}

/* ---------- Services list ---------- */
.service-row {
  display: grid;
  gap: var(--space-5);
  padding-block: var(--space-7);
  border-bottom: 1px solid var(--border);
}

.service-row:first-of-type { padding-top: 0; }
.service-row:last-of-type { border-bottom: none; }

@media (min-width: 860px) {
  .service-row { grid-template-columns: 0.9fr 1.6fr; gap: var(--space-7); }
}

.service-row__head { display: flex; align-items: baseline; gap: var(--space-3); }

.service-row__index {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  /* --muted-2 measures ~2.6:1 on this background at this size, well
     under WCAG AA's 4.5:1 for text this small -- this index number is
     real visible content (not decorative/aria-hidden), so it uses
     --muted (~4.6-5:1) instead. */
  color: var(--muted);
}

/* Was a dead rule (targeted h3, but the markup uses h2 with a
   repeated inline font-size) -- fixed to actually apply, and sized up
   from the generic --fs-h2 so titles read as dominant editorial-index
   entries rather than a standard section heading. */
.service-row__head h2 { font-size: clamp(1.9rem, 1.3rem + 2.2vw, 2.7rem); }

.service-row__body p { color: var(--muted); margin-bottom: var(--space-4); max-width: 62ch; }

.tag-list { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.tag {
  font-size: 0.82rem;
  padding: 6px 13px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border);
  color: var(--ink-soft);
  background: var(--surface);
}

.feature-list { display: flex; flex-direction: column; gap: var(--space-2); }

.feature-list li {
  display: flex;
  align-items: flex-start;
  gap: 0.6em;
  font-size: 0.92rem;
  color: var(--ink-soft);
}

.feature-list svg { width: 16px; height: 16px; flex: none; margin-top: 4px; color: var(--lime); }

/* ---------- Portfolio project index (editorial anchor nav) ----------
   Replaces the old client-side filter: a magazine contents-page list
   of every project below, each entry a real #anchor link rather than
   a JS show/hide filter. Same plain-mono, underline-in visual language
   the old .filter-bar used. */
.work-toc-section { padding-bottom: var(--space-7); }
.work-selected-head { padding-top: var(--space-9); }

.work-toc {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-6);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--border);
}

.work-toc__item {
  display: inline-flex;
  align-items: baseline;
  gap: 0.6em;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--muted);
  position: relative;
  padding-block: 0.3em;
  transition: color var(--speed) var(--ease);
}

.work-toc__item::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: var(--lime);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--speed) var(--ease);
}

.work-toc__item:hover { color: var(--ink); }
.work-toc__item:hover::after { transform: scaleX(1); }

.work-toc__index {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--muted-2);
}

/* ---------- Portfolio visual gallery grid (reused by every case study's visual story) ---------- */
.project__gallery {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}

.project__gallery > * { min-width: 0; }

@media (min-width: 720px) {
  .project__gallery { grid-template-columns: repeat(2, 1fr); }
}

.project__gallery button.work-story-item__frame {
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  cursor: zoom-in;
  text-align: left;
  width: 100%;
  transition: box-shadow var(--speed) var(--ease), transform var(--speed) var(--ease);
}

.project__gallery button.work-story-item__frame:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.project__gallery button.work-story-item__frame img,
.project__gallery button.work-story-item__frame svg {
  display: block;
  width: 100%;
  height: auto;
  transition: transform 0.5s var(--ease);
}

.project__gallery button.work-story-item__frame:hover img { transform: scale(1.03); }

/* ---------- NOVAÉ / King's Hall galleries: mixed aspect-ratio screenshots,
   scoped so the default (matched-ratio) galleries elsewhere are unaffected ---------- */
#novae .project__gallery,
#kingshall .project__gallery {
  align-items: start;
}

@media (min-width: 720px) {
  #novae .project__gallery {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ---------- JOVI gallery: the six approved presentation captures vary
   hugely in native proportion (a full-length rail screenshot next to a
   phone frame), so the case study reads as a deliberate hierarchy --
   product system as a tall centred panel, Gift Finder/Personalisation
   paired, the lifestyle moment full-width, mobile a small closing
   frame -- rather than six equal thumbnails. Every image keeps its own
   intrinsic ratio (no cropping); span/max-width do the arranging. */
#jovi .project__gallery {
  align-items: start;
}

#jovi .work-story-item--product,
#jovi .work-story-item--lifestyle,
#jovi .work-story-item--mobile {
  grid-column: 1 / -1;
}

#jovi .work-story-item--product .work-story-item__frame {
  max-width: 520px;
  margin-inline: auto;
}

#jovi .work-story-item--mobile .work-story-item__frame {
  max-width: 280px;
  margin-inline: auto;
}

@media (min-width: 900px) {
  #jovi .project__gallery {
    grid-template-columns: repeat(6, 1fr);
  }

  #jovi .work-story-item--giftfinder,
  #jovi .work-story-item--personalise {
    grid-column: span 3;
  }
}

.work-story-item__label {
  display: block;
  margin-bottom: var(--space-3);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  /* real gallery caption text, not decorative -- --muted-2 fails WCAG
     AA (~2.6:1) at this size, --muted passes (~4.6-5:1). */
  color: var(--muted);
}

/* ---------- Work page — flagship case study (Madani) ---------- */
.work-feature {
  --navy: var(--ink); /* Global color-system alignment: unified with the warm ink family per direction; kept as --navy so its ~7 heading consumers below don't need individual edits. */
  padding-block: var(--space-9);
  border-bottom: 1px solid var(--border);
}

.work-feature__label {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin-bottom: var(--space-4);
}

.work-feature__head { max-width: 68ch; margin-bottom: var(--space-7); }
.work-feature__head h2 {
  font-size: clamp(2rem, 1.5rem + 1.8vw, 3rem);
  color: var(--navy);
  margin-bottom: var(--space-3);
}

.work-feature__category {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: var(--space-4);
}

.work-feature__tags {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  /* real discipline-tag text, not decorative -- --muted-2 fails WCAG AA
     at this size, --muted passes (matches .work-feature__meta-item dt
     and .work-story-item__label just above/below). */
  color: var(--muted);
  margin-bottom: var(--space-3);
}

.work-feature__intro { font-size: var(--fs-lead); color: var(--muted); max-width: 56ch; }

/* Mounted-print treatment: the hero screenshot sits inset on a card
   rather than bleeding edge-to-edge. Madani's own hero source is a
   short, wide banner crop (~3.2:1) that would otherwise read as a
   thin strip next to King's Hall's tall photograph -- padding gives
   both feature-tier heroes real presence without cropping or
   distorting either image. */
.work-feature__visual {
  margin-bottom: var(--space-7);
  padding: clamp(1.25rem, 3vw, 2.25rem);
  background: var(--surface);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
  transition: transform 0.5s var(--ease);
}

.work-feature__visual img,
.work-feature__visual svg { border-radius: var(--radius-sm); }

.work-feature__visual:hover { transform: translateY(-4px); }
.work-feature__visual img,
.work-feature__visual svg { display: block; width: 100%; height: auto; }
.work-feature__visual img { transition: transform 0.6s var(--ease); }
.work-feature__visual:hover img { transform: scale(1.02); }

/* King's Hall's own honest-defect disclosure -- required wherever the
   concept appears, so it can't be missed by scanning past the intro. */
.work-feature__disclosure {
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--paper-alt);
  font-size: 0.85rem;
  color: var(--muted);
  max-width: 56ch;
}

.work-feature__disclosure strong { color: var(--ink); }

.work-feature__meta {
  margin-bottom: var(--space-8);
  display: grid;
  gap: var(--space-4);
}

@media (min-width: 720px) {
  .work-feature__meta { grid-template-columns: repeat(3, 1fr); gap: var(--space-6); }
}

.work-feature__meta-item dt {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* real field label text ("Industry"/"Services"/"Technology"), not
     decorative -- --muted-2 fails WCAG AA (~2.6:1) at this size,
     --muted passes (~4.6-5:1). */
  color: var(--muted);
  margin-bottom: var(--space-2);
}

.work-feature__meta-item dd { font-weight: 600; color: var(--ink); }

.work-feature__grid {
  display: grid;
  gap: var(--space-6);
  margin-bottom: var(--space-8);
}

@media (min-width: 860px) {
  .work-feature__grid { grid-template-columns: repeat(2, 1fr); gap: var(--space-8); }
}

.work-feature__grid h3 { font-size: var(--fs-h3); margin-bottom: var(--space-3); color: var(--navy); }
.work-feature__grid p { color: var(--muted); }

.work-feature__features { margin-bottom: var(--space-9); }
.work-feature__features h3 { font-size: var(--fs-h3); margin-bottom: var(--space-5); color: var(--navy); }

.work-feature__story { margin-bottom: var(--space-9); }
.work-feature__story h3 { font-size: var(--fs-h3); margin-bottom: var(--space-5); color: var(--navy); }
.work-feature__story .project__gallery { gap: var(--space-6); }

/* Madani's 6-image gallery renders at generic 2-up scale otherwise --
   large enough to visually compete with the hero above it instead of
   supporting it. A tighter 3-up grid keeps every screenshot legible
   while clearly reading as secondary. Scoped to Madani only -- King's
   Hall's 2-image gallery is deliberately spacious. */
@media (min-width: 900px) {
  #oil-gas .project__gallery { grid-template-columns: repeat(3, 1fr); }
}

.work-feature__summary {
  margin-bottom: var(--space-9);
  border-top: 1px solid var(--border);
  display: grid;
  gap: var(--space-6);
}

@media (min-width: 720px) {
  .work-feature__summary { grid-template-columns: 1fr auto; align-items: end; }
}

.work-feature__summary h3 { font-size: var(--fs-h3); margin-bottom: var(--space-4); color: var(--navy); }

.work-feature__ctas { display: flex; flex-wrap: wrap; gap: var(--space-5); }

/* ---------- Numbered key-features list (shared: flagship + selected projects) ---------- */
.numbered-list {
  display: grid;
  gap: var(--space-5);
}

@media (min-width: 720px) {
  .numbered-list { grid-template-columns: repeat(2, 1fr); gap: var(--space-6); }
}

.numbered-list li {
  display: flex;
  gap: var(--space-4);
  padding-bottom: var(--space-5);
  border-bottom: 1px solid var(--border);
}

.numbered-list__index {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  color: var(--muted-2);
  flex: none;
}

.numbered-list__text { font-weight: 600; color: var(--ink); }

/* ---------- Work page — selected projects (alternating editorial layout) ---------- */
.work-project {
  --navy: var(--ink); /* Global color-system alignment: unified with the warm ink family per direction; kept as --navy so its ~7 heading consumers below don't need individual edits. */
  padding-block: var(--space-9);
  border-bottom: 1px solid var(--border);
}

.work-project:last-of-type { border-bottom: none; }

.work-project__grid {
  display: grid;
  gap: var(--space-7);
  align-items: center;
}

@media (min-width: 900px) {
  .work-project__grid { grid-template-columns: 1.1fr 0.9fr; gap: var(--space-8); }
  .work-project--reverse .work-project__grid { grid-template-columns: 0.9fr 1.1fr; }
  .work-project--reverse .work-project__visual { order: 2; }
  .work-project--reverse .work-project__body { order: 1; }

  /* Medium tier: Chicken Rice keeps the default ratio; Safwa and NOVAÉ
     each get a genuinely different image/text balance rather than
     just a mirrored copy of the same column split -- Safwa's own copy
     is deliberately restrained ("without leaning on heavy imagery"),
     NOVAÉ's is the most visual-forward of the three. */
  #safwa .work-project__grid { grid-template-columns: 1.2fr 0.8fr; }
  #novae .work-project__grid { grid-template-columns: 1.3fr 0.7fr; }
}

.work-project__visual {
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
  transition: transform 0.4s var(--ease);
}

.work-project__visual:hover { transform: translateY(-4px); }
.work-project__visual img,
.work-project__visual svg { display: block; width: 100%; height: auto; }
.work-project__visual img { transition: transform 0.6s var(--ease); }
.work-project__visual:hover img { transform: scale(1.03); }

.work-project__label {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
  margin-bottom: var(--space-4);
}

.work-project__labels { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }
.work-project__labels .work-project__label { margin-bottom: 0; }

.work-project__body h3 { font-size: var(--fs-h2); color: var(--navy); margin-bottom: var(--space-2); }

.work-project__category {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: var(--space-4);
}

.work-project__body > p.work-project__desc { color: var(--muted); margin-bottom: var(--space-5); }

.work-project__body h4 { font-size: 0.95rem; margin-bottom: var(--space-2); color: var(--navy); }
.work-project__body p { color: var(--muted); }
.work-project__body .work-project__block + .work-project__block { margin-top: var(--space-4); }

.work-project__features {
  margin-top: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.work-project__story { margin-top: var(--space-6); }
.work-project__story h4 { margin-bottom: var(--space-4); }

.work-project__cta {
  margin-top: var(--space-6);
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-weight: 600;
  color: var(--navy);
  position: relative;
  padding-block: 0.4em;
}

.work-project__cta::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--speed) var(--ease);
}

.work-project__cta:hover::after { transform: scaleX(1); }
.work-project__cta svg { width: 16px; height: 16px; transition: transform var(--speed) var(--ease); }
.work-project__cta:hover svg { transform: translateX(3px); }

.info-rows { display: flex; flex-direction: column; }

.info-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-3);
  border-bottom: 1px solid var(--border);
  font-size: 0.92rem;
}

.info-row:last-child { border-bottom: none; }
.info-row dt { color: var(--muted); }
.info-row dd { font-weight: 600; text-align: right; }

/* ---------- Work page — archive tier (lighter visual weight) ----------
   Klinik Ceria, Royale Chesterfield and Lumi\00e8re carry the same full
   case-study markup as the medium tier, but read as a lighter "more
   projects" pass: a smaller, constrained image and tighter spacing
   rather than a fourth full-width spread. */
.work-project--compact {
  padding-block: var(--space-7);
}

@media (min-width: 900px) {
  .work-project--compact .work-project__visual {
    max-width: 420px;
  }

  .work-project--compact .work-project__grid {
    grid-template-columns: 0.8fr 1.2fr;
  }

  .work-project--compact.work-project--reverse .work-project__grid {
    grid-template-columns: 1.2fr 0.8fr;
  }
}

.work-project--compact .work-project__story {
  margin-top: var(--space-5);
}

.work-project--compact .project__gallery {
  gap: var(--space-3);
}

@media (min-width: 900px) {
  .work-project--compact .project__gallery { max-width: 640px; }
  .work-project--compact.work-project--reverse .project__gallery { margin-left: auto; }
}

/* ---------- Lightbox ---------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
  background: rgba(19, 19, 22, 0.86);
}

.lightbox.is-open { display: flex; }

.lightbox__inner {
  position: relative;
  width: 100%;
  max-width: 980px;
}

.lightbox__inner img {
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 78vh;
  display: block;
  margin: 0 auto;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-on-dark);
}

.lightbox__caption {
  margin-top: var(--space-4);
  color: rgba(250, 249, 245, 0.72);
  font-size: var(--fs-small);
  text-align: center;
}

.lightbox__close {
  position: absolute;
  top: calc(var(--space-6) * -1);
  right: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--paper);
  border: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.lightbox__close svg { width: 18px; height: 18px; }

@media (max-width: 600px) {
  .lightbox__close { top: -52px; right: 0; }
}

/* ---------- Contact page ---------- */
.contact-layout {
  display: grid;
  gap: var(--space-7);
}

@media (min-width: 980px) {
  .contact-layout { grid-template-columns: 0.85fr 1.15fr; align-items: start; }
}

/* Plain ruled rows instead of icon-boxed cards, matching the trust
   strip / services / why-ajak precedent set on the homepage. */
.contact-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-block: var(--space-4);
  border-top: 1px solid var(--border);
}

.contact-card:first-child { border-top: none; padding-top: 0; }
.contact-card + .contact-card { margin-top: 0; }

/* One dominant WhatsApp link (per the redesign brief: keep WhatsApp
   as the primary action, avoid competing CTAs) sitting above the
   quieter reference info -- the same big-typographic-link move as the
   homepage's closing CTA, reused here in ink-on-paper rather than
   paper-on-ink since this page opens on a light background. */
.contact-primary {
  margin-bottom: var(--space-7);
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--border);
}

.contact-primary__link {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.6rem, 1rem + 2.4vw, 2.4rem);
  text-transform: uppercase;
  letter-spacing: 0.01em;
  color: var(--ink);
  position: relative;
  padding-block: 0.2em;
}

.contact-primary__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  background: var(--lime);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--speed) var(--ease);
}

.contact-primary__link:hover::after { transform: scaleX(1); }
.contact-primary__link span[aria-hidden] { display: inline-block; transition: transform var(--speed) var(--ease); }
.contact-primary__link:hover span[aria-hidden] { transform: translateX(4px); }
.contact-primary__note { margin-top: var(--space-3); color: var(--muted); font-size: 0.92rem; }
.contact-primary__note a { color: var(--ink-soft); text-decoration: underline; text-underline-offset: 3px; }

.contact-card__label {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* real field label text ("LinkedIn"/"Location"), not decorative --
     --muted-2 fails WCAG AA (~2.6:1) at this size, --muted passes
     (~4.6-5:1). */
  color: var(--muted);
  margin-bottom: 2px;
}

.contact-card__value { font-weight: 600; }
/* Text stays ink at this size (small label text); the lime accent
   shows as an underline on hover instead of a color swap. */
.contact-card__value a:hover {
  text-decoration: underline;
  text-decoration-color: var(--lime);
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

.form-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}

.form-row { display: grid; gap: var(--space-4); }

@media (min-width: 620px) {
  .form-row--2 { grid-template-columns: 1fr 1fr; }
}

.field { display: flex; flex-direction: column; gap: 0.5em; margin-bottom: var(--space-4); }

.field label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink-soft);
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 0.85em 1em;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--border);
  background: var(--paper);
  font-size: 0.95rem;
  transition: border-color var(--speed) var(--ease);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  border-color: var(--lime);
  outline: none;
}

.field textarea { resize: vertical; min-height: 120px; }

.form-note {
  display: flex;
  align-items: flex-start;
  gap: 0.6em;
  font-size: 0.82rem;
  color: var(--muted);
  background: var(--paper-alt);
  border-radius: var(--radius-sm);
  padding: var(--space-4);
  margin-bottom: var(--space-5);
}

.form-note svg { width: 17px; height: 17px; flex: none; margin-top: 1px; color: var(--lime); }

.form-status {
  margin-top: var(--space-4);
  font-size: 0.88rem;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  display: none;
}

.form-status.is-visible { display: block; }
.form-status.is-success { background: var(--accent-tint); color: var(--accent-dark); }
.form-status.is-error { background: #fdecec; color: #b3261e; }

.map-embed {
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  aspect-ratio: 16/10;
}

.map-embed iframe { width: 100%; height: 100%; border: 0; }
