/* ==========================================================================
   czako.net — Strategy & design
   Implemented from Figma: home - desktop (node 281:471)
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Design tokens
   -------------------------------------------------------------------------- */
:root {
  color-scheme: light;

  /* --- Fixed brand values: identical in both themes ---------------------- */
  --c-hero-bg:      #0d0f28;  /* hero + contact ground — 801:2625 */
  --c-hero-ink:     #fafafa;  /* copy on that ground */
  --c-accent:       #e5fe4a;  /* hero heading, hero square, scroll cue */
  --c-purple:       #36189e;  /* mosaic tiles */
  --c-cyan:         #6fccdc;
  --c-deep:         #0a292c;  /* Highlights heading + two tiles — 807:2864 */
  --c-on-accent:      #352e71; /* text sitting on an acid gradient */
  --c-on-accent-soft: #525151;

  --g-tag:      linear-gradient(270deg, #dbf891 0%, #fdfd8a 100%);
  --g-tag-alt:  linear-gradient(270deg, #ccfe8a 0%, #fdfd8a 100%);
  --g-cta:      linear-gradient(270deg, #ccfe8a 0%, #fdfd8a 100%);

  /* --- Themed values: the light set is the Figma design ------------------ */
  --c-surface:      #ffffff;  /* Highlights + Projects bands */
  --c-surface-alt:  #f7f2ef;  /* Industry experience band — 805:2819 */
  --c-ink:          #352e71;  /* headings and pill labels */
  --c-body:         #525151;  /* body copy */
  --c-badge:        #332e5e;  /* Highlights year badge */

  --logo-filter:        grayscale(1);
  --logo-filter-hover:  grayscale(0);
  --logo-opacity:       0.75;

  /* Type scale — fluid between 360px and 1440px viewports */
  --fs-display:   clamp(2.375rem, 1.10rem + 4.17vw, 3.75rem);   /* 38 → 60 */
  --fs-hero:      clamp(2.5rem, 0.6rem + 6.6vw, 5rem);          /* 40 → 80 */
  --fs-statement: clamp(1.375rem, 0.62rem + 2.65vw, 2.5rem);    /* 22 → 40 */

  /* Headline offsets from the content column, as drawn: the block sits 103px
     in, the arrow 73px further, and "decisions" clears the arrow by 64px. */
  --hl-indent:    clamp(0px, 7.15vw, 103px);
  --hl-arrow:     clamp(0px, 5.07vw, 73px);
  --hl-step:      calc(var(--hl-arrow) + 64px);
  --fs-mega:      clamp(3rem, -0.55rem + 11.67vw, 7.5rem);      /* 48 → 120 */
  --fs-h3:        clamp(1.5rem, 1.13rem + 0.74vw, 2rem);        /* 24 → 32 */
  --fs-lead:      clamp(1.125rem, 0.90rem + 0.56vw, 1.5rem);    /* 18 → 24 */
  --fs-body:      clamp(1rem, 0.86rem + 0.37vw, 1.25rem);       /* 16 → 20 */
  --fs-item:      clamp(1rem, 0.94rem + 0.19vw, 1.125rem);      /* 16 → 18 */
  --fs-tag:       0.75rem;

  /* Layout */
  --content-max:  1060px;
  --gutter:       clamp(1.25rem, 0.83rem + 1.85vw, 2.5rem);     /* 20 → 40 */
  --col-gap:      clamp(2rem, 0.86rem + 3.7vw, 3rem);           /* 32 → 48 */

  /* Rhythm */
  --band-pad-y:   clamp(3.5rem, 0.5rem + 6.67vw, 6rem);         /* 56 → 96 */
  --radius-pill:  60px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* --- Dark theme — DORMANT -------------------------------------------------
   Nothing stamps data-theme any more: the theme picker has been removed and
   the page is the light look the Figma frames specify. The block is kept
   because it costs nothing and it is the whole of the dark palette. To bring
   it back, restore the .themepick markup and its initPicker call in main.js —
   or, for a system-following page with no control at all, wrap these
   declarations in @media (prefers-color-scheme: dark) too. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --c-surface:      #0e0d16;
  --c-surface-alt:  #16151f;
  --c-ink:          #ece9ff;
  --c-body:         #a5a1bd;
  --c-badge:        #6f63d6;
  --logo-filter:        grayscale(1) brightness(0) invert(1);
  --logo-filter-hover:  grayscale(1) brightness(0) invert(1);
  --logo-opacity:       0.6;
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--c-hero-bg);
  color: var(--c-hero-ink);
  font-family: "Outfit", "Helvetica Neue", Arial, system-ui, sans-serif;
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

h1, h2, h3, p, ul, figure { margin: 0; }
ul { padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; }

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

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

.skip-link {
  position: absolute;
  top: -100px;
  left: var(--gutter);
  z-index: 100;
  padding: 0.75rem 1.25rem;
  background: var(--c-accent);
  color: var(--c-on-accent);
  font-weight: 600;
  border-radius: var(--radius-pill);
  transition: top 0.2s var(--ease);
}
.skip-link:focus { top: 1rem; }

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */
.band {
  position: relative;
  padding-inline: var(--gutter);
}

.band__inner {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
}

/* Band colours, matching the stacked rectangles in the Figma frame */
.band--dark   { background: var(--c-hero-bg);     color: var(--c-hero-ink); }
.band--light  { background: var(--c-surface);     color: var(--c-body); }
.band--grey   { background: var(--c-surface-alt); color: var(--c-body); }

.cols {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--col-gap);
}

/* --------------------------------------------------------------------------
   4. Typography helpers
   -------------------------------------------------------------------------- */
.h-display {
  font-size: var(--fs-display);
  font-weight: 600;
  line-height: 1.1;
  color: var(--c-ink);
}

/* Hungarian compounds are long and unbreakable; at the narrowest widths a
   display line can be wider than the column. Hyphenation handles it where the
   browser has a dictionary for the document's language, and the break-word
   fallback catches the rest — neither fires while the word still fits. */
.h-display,
.hl,
.contact__title,
.accordion__label,
.engagement__name {
  overflow-wrap: break-word;
  hyphens: auto;
}

.highlights .h-display { color: var(--c-deep); }

.lead {
  font-size: var(--fs-lead);
  line-height: 1.5;
}

/* --------------------------------------------------------------------------
   5. Header
   -------------------------------------------------------------------------- */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  height: 100px;
  display: flex;
  align-items: center;
  padding-inline: var(--gutter);
  transition: transform 0.35s var(--ease), opacity 0.3s var(--ease);
}

/* The bar belongs to the hero. Once the next band reaches it, it retires
   rather than float over the rest of the page. */
.site-header.is-gone {
  transform: translateY(-100%);
  opacity: 0;
  pointer-events: none;
}

/* The bar has no ground of its own, so it sits straight on whatever band is
   passing under it. JS measures that band's background and reports it as
   data-ground; on a light one the glass and the icons flip to dark, which is
   the only reason they stay readable over the white Highlights band. */
.site-header[data-ground="light"] .pick {
  --tp-track: rgba(0, 0, 0, 0.06);
  --tp-thumb: rgba(0, 0, 0, 0.09);
  --tp-fg: var(--c-ink);
  --tp-rim-paint: linear-gradient(
    145deg,
    rgba(255, 255, 255, 0.9) 0%,
    rgba(255, 255, 255, 0.35) 34%,
    rgba(0, 0, 0, 0.06) 62%,
    rgba(0, 0, 0, 0.12) 100%
  );
  --tp-track-rim-paint: linear-gradient(
    145deg,
    rgba(255, 255, 255, 0.6) 0%,
    rgba(255, 255, 255, 0.15) 40%,
    rgba(0, 0, 0, 0.04) 66%,
    rgba(0, 0, 0, 0.07) 100%
  );
}

.site-header[data-ground="light"] .site-header__cta,
.site-header[data-ground="light"] .site-header__status {
  color: var(--c-ink);
}

.site-header__inner {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.site-header__brand {
  display: block;
  flex: 0 0 auto;
  line-height: 0;
}

.site-header__brand img {
  width: 57px;
  height: 50px;
}

.site-header__right {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 0.3rem + 2.2vw, 2rem);
}

/* The call to action sits above the availability line, both right aligned so
   they read as one block against the pickers. */
/* The call to action shares the picker's axis, so it is the only thing that
   sets this block's height: the availability line hangs below it, out of flow,
   rather than pushing the link off centre. */
.site-header__contact {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  min-width: 0;
}

.site-header__cta {
  font-size: var(--fs-lead);
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--c-hero-ink);
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.25s var(--ease);
}

.site-header__cta:hover { color: var(--c-accent); }

.site-header__status {
  position: absolute;
  top: calc(100% + 7px);
  right: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 10px;
  font-weight: 600;
  color: var(--c-hero-ink);
  opacity: 0.5;
  white-space: nowrap;
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}

/* The dot is the live part of the line, so it breathes: the disc itself swells
   and brightens, and a ring travels out from under it. The ring alone was too
   quiet to read at 5px against the hero. */
.site-header__dot,
.contact__dot {
  position: relative;
  width: 6px;
  height: 6px;
  flex: 0 0 6px;
  border-radius: 50%;
  background: var(--c-accent);
}

.site-header__dot::after,
.contact__dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--c-accent);
}

@media (prefers-reduced-motion: no-preference) {
  .site-header__dot,
  .contact__dot        { animation: pulse-dot 2.2s var(--ease) infinite; }
  .site-header__dot::after,
  .contact__dot::after { animation: pulse-ring 2.2s var(--ease) infinite; }
}

@keyframes pulse-dot {
  0%, 100% { transform: scale(1);    opacity: 0.75; }
  45%      { transform: scale(1.35); opacity: 1; }
}

/* The ring is a second disc that grows out and fades, so the pulse has a
   travelling edge rather than only a change of size. */
@keyframes pulse-ring {
  0%   { transform: scale(1);   opacity: 0.5; }
  70%  { transform: scale(3.2); opacity: 0; }
  100% { transform: scale(3.2); opacity: 0; }
}

/* The availability line is a first-screen detail; it steps aside on scroll. */
.site-header.is-stuck .site-header__status {
  opacity: 0;
  transform: translateY(-4px);
  pointer-events: none;
}

.toggle-group {
  display: flex;
  align-items: center;
  gap: 16px;
}

/* --- Pickers (Figma 507:435 theme, 512:669 language) -----------------------
   One glass skin, two controls. Each is a row of 48px slots: closed it shows a
   single slot, and hover, keyboard focus or a tap opens the track to reveal the
   rest. The track and thumb are translucent fills over backdrop-filter, with a
   hairline gradient rim drawn as a 1px padded border whose middle is cut out
   with mask-composite.

   The header is right aligned, so the flex row pins each control's right edge:
   opening grows it leftwards and nothing around it moves. The surface stays
   white-tinted in both site themes, because the ground behind it — the hero —
   is black either way. */
.pick {
  --tp-slot: 48px;                            /* one slot / the thumb diameter */
  --tp-track: rgba(255, 255, 255, 0.1);       /* 508:618 */
  --tp-thumb: rgba(255, 255, 255, 0.12);      /* 507:448 */
  --tp-fg: #ffffff;
  --tp-idle: 0.4;                             /* inactive option — 508:635 */
  --tp-ease: cubic-bezier(0.32, 0.72, 0.2, 1);

  --tp-blur: 16px;
  --tp-rim: 1px;
  --tp-rim-paint: linear-gradient(
    145deg,
    rgba(255, 255, 255, 0.55) 0%,
    rgba(255, 255, 255, 0.14) 34%,
    rgba(255, 255, 255, 0) 55%,
    rgba(255, 255, 255, 0.22) 100%
  );
  --tp-track-rim-paint: linear-gradient(
    145deg,
    rgba(255, 255, 255, 0.28) 0%,
    rgba(255, 255, 255, 0.06) 40%,
    rgba(255, 255, 255, 0) 62%,
    rgba(255, 255, 255, 0.12) 100%
  );

  position: relative;
  flex: 0 0 auto;
  width: var(--tp-slot);
  height: var(--tp-slot);
  transition: width 0.3s var(--tp-ease);
}

.pick[data-open="true"] {
  width: calc(var(--tp-slot) * 2);
}

/* The track grows out from under the thumb. */
.pick__track {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--tp-slot);
  border-radius: 100px;
  background: var(--tp-track);
  backdrop-filter: blur(var(--tp-blur));
  -webkit-backdrop-filter: blur(var(--tp-blur));
  opacity: 0;
  pointer-events: none;
  transition: width 0.3s var(--tp-ease), opacity 0.24s var(--tp-ease);
}

/* Hairline gradient rim: a 1px border painted with a gradient, its middle cut
   out by mask-composite. */
.pick__track::after,
.pick__thumb::after {
  content: "";
  position: absolute;
  inset: 0;
  box-sizing: border-box;
  border-radius: inherit;
  padding: var(--tp-rim);
  background: var(--tp-rim-paint);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  pointer-events: none;
}

.pick__track::after {
  background: var(--tp-track-rim-paint);
}

.pick[data-open="true"] .pick__track {
  width: calc(var(--tp-slot) * 2);
  opacity: 1;
}

/* The thumb rides on the active slot; closed it always sits on slot 0. */
.pick__thumb {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--tp-slot);
  height: var(--tp-slot);
  border-radius: 100px;
  background: var(--tp-thumb);
  backdrop-filter: blur(var(--tp-blur));
  -webkit-backdrop-filter: blur(var(--tp-blur));
  pointer-events: none;
  transition:
    transform 0.3s var(--tp-ease),
    background-color 0.24s var(--tp-ease);
}

/* One option: a 48 x 48 slot holding a 24px icon or a label. */
.pick__option {
  position: absolute;
  top: 0;
  left: calc(var(--tp-index) * var(--tp-slot));
  width: var(--tp-slot);
  height: var(--tp-slot);
  margin: 0;
  padding: 0;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 100px;
  background: none;
  font: inherit;
  color: var(--tp-fg);
  cursor: pointer;
  opacity: var(--tp-idle);
  transition:
    opacity 0.24s var(--tp-ease),
    transform 0.3s var(--tp-ease),
    visibility 0s linear 0s;
  -webkit-tap-highlight-color: transparent;
}

.pick[data-open="false"] .pick__option {
  transition-delay: 0s, 0s, 0.24s;
}

.pick__option[aria-checked="true"] {
  opacity: 1;
}

@media (hover: hover) {
  .pick__option:hover { opacity: 1; }
}

.pick__option:focus-visible,
.pick__trigger:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.pick__icon {
  display: block;
  width: 24px;
  height: 24px;
}

@media (prefers-reduced-motion: reduce) {
  .pick,
  .pick__track,
  .pick__thumb,
  .pick__option,
  .pick__trigger {
    transition-duration: 0.01ms;
  }
}

/* Without backdrop-filter the fills need a little more body so the surface
   does not disappear into the background. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .pick {
    --tp-track: rgba(255, 255, 255, 0.14);
    --tp-thumb: rgba(255, 255, 255, 0.18);
  }
}

/* --- Language picker (820:3042, revising 512:669) --------------------------
   Closed it shows a globe instead of the active language, so neither label is
   on screen until it opens. That globe is also the control that opens it —
   on touch there is no hover to do the job.

   The revision is the open state: the thumb is no longer a pane of glass but
   the brand acid, and the language standing on it flips to black. Three frames
   define it — closed (820:3045, glass + globe), open with EN active
   (820:3046), open with HU active (820:3047) — and in each the other language
   stays white at half strength. */
.langpick {
  --tp-idle: 0.5;                             /* 820:3052 — the other language */
  --tp-thumb-on: var(--c-accent);             /* 820:3046 — #e5fe4a */
  --tp-on-thumb: #000000;                     /* 820:3051 — label on the acid */
}

.langpick .pick__option {
  font-size: 16px;
  font-weight: 600;
  line-height: 1;
  /* The label flips to black as the thumb slides under it, not after. */
  transition:
    opacity 0.24s var(--tp-ease),
    color 0.24s var(--tp-ease),
    transform 0.3s var(--tp-ease),
    visibility 0s linear 0s;
}

.langpick[data-open="false"] .pick__option {
  transition-delay: 0s, 0s, 0s, 0.24s;
}

/* Open, the thumb is a solid acid disc: no glass left to blur through, and the
   colour is the point, so the fill carries it rather than a tint over blur. */
.langpick[data-open="true"] .pick__thumb {
  background: var(--tp-thumb-on);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Its rim turns to the light-ground paint — a white hairline would vanish into
   the acid, where a soft dark edge still reads as a lit surface. */
.langpick[data-open="true"] .pick__thumb::after {
  background: linear-gradient(
    145deg,
    rgba(255, 255, 255, 0.55) 0%,
    rgba(255, 255, 255, 0.15) 32%,
    rgba(0, 0, 0, 0.06) 62%,
    rgba(0, 0, 0, 0.14) 100%
  );
}

.langpick .pick__option[aria-checked="true"] {
  color: var(--tp-on-thumb);
}

/* The other language does not brighten under the pointer — at 820:3063 it
   keeps its half strength and takes a faint ring instead, so the hover reads
   as "this slot is live" without competing with the active one. */
.langpick .pick__option::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: var(--tp-rim);
  background: var(--tp-rim-paint);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.24s var(--tp-ease);
}

@media (hover: hover) {
  .langpick[data-open="true"] .pick__option:not([aria-checked="true"]):hover {
    opacity: var(--tp-idle);
  }
  .langpick[data-open="true"] .pick__option:not([aria-checked="true"]):hover::after {
    opacity: 0.4;                             /* 820:3063 */
  }
}

.langpick[data-open="true"][data-lang="hu"] .pick__thumb {
  transform: translateX(var(--tp-slot));
}

/* Both labels are hidden and parked on slot 0: out of the accessibility tree,
   and inside the collapsed box so they cannot widen the document. */
.langpick[data-open="false"] .pick__option {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateX(calc(-1 * var(--tp-index) * var(--tp-slot)));
}

.pick__trigger {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--tp-slot);
  height: var(--tp-slot);
  margin: 0;
  padding: 0;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 100px;
  background: none;
  font: inherit;
  color: var(--tp-fg);
  cursor: pointer;
  transition: opacity 0.24s var(--tp-ease);
  -webkit-tap-highlight-color: transparent;
}

.langpick[data-open="true"] .pick__trigger {
  opacity: 0;
  pointer-events: none;
}
}

.band--light,
.band--grey,
.bar__track,
.bar__badge {
  transition: background-color 0.35s var(--ease), color 0.35s var(--ease);
}

/* --------------------------------------------------------------------------
   6. Stage — the pinned opening sequence (hero: Figma 801:2625)
   -------------------------------------------------------------------------- */

/* The scroll driver. Its height is what the sequence has to spend; the pin
   inside stays put for that distance. JS reads the progress of one against the
   other and writes it to --p, plus a per-act opacity and offset. Without JS, or
   under reduced motion, the pin is not sticky and the acts lay out as ordinary
   stacked blocks. */
.stage {
  --a1: 1;    /* act one   — opacity */
  --t1: 0px;  /*            — offset */
  --a2: 0;    /* act two   */
  --t2: 90px;
  --a3: 0;    /* act three */
  --t3: 90px;
  --pl: 0;    /* progress line fill */
  --plv: 0;   /* progress line presence */
  --mx: 0;    /* damped pointer, -1 → 1 */

  position: relative;
  z-index: 2;
  background: var(--c-hero-bg);
  color: var(--c-hero-ink);
}

.stage__pin {
  position: relative;
  min-height: 100vh;
  padding-block: 150px 48px;
  padding-inline: var(--gutter);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.stage__inner {
  position: relative;
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
}

/* --- Act one -------------------------------------------------------------- */
.stage__acts {
  position: relative;
  z-index: 1;
  transform: translate3d(calc(var(--mx) * 6px), var(--t1), 0);
  opacity: var(--a1);
}

/* --- Headline -------------------------------------------------------------
   Three lines at 80px / 100px with -0.04em tracking, indented 103px from the
   content column as drawn. Each line masks its own content so the load
   sequence can wipe them up one after another; the horizontal padding keeps
   the pill's rounded overhang inside that mask. */
.hl {
  margin-left: var(--hl-indent);
  font-size: var(--fs-hero);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: -0.04em;
  color: var(--c-hero-ink);
}

.hl__line {
  display: block;
  overflow: hidden;
  padding: 0 14px 0.06em;
  margin-inline: -14px;
}

.hl__line--indent {
  margin-left: calc(var(--hl-arrow) - 14px);
}

.hl__mask {
  display: block;
}

/* "for" is punched out of an acid pill; the negative margin puts the word,
   not the pill's cap, on the column edge. */
.hl__pill {
  display: inline-block;
  margin-left: -11px;
  padding-inline: 19px;
  border-radius: 120px;
  background: var(--c-accent);
  color: var(--c-hero-bg);
  font-family: "Baskervville", Georgia, "Times New Roman", serif;
  font-style: italic;
  font-weight: 600;
  line-height: 1.15;
}

.hl__accent { color: var(--c-accent); }

.hl__serif {
  font-family: "Baskervville", Georgia, "Times New Roman", serif;
  font-style: italic;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.hl__arrow {
  display: inline-block;
  width: 28px;
  margin-right: 36px;
  color: var(--c-accent);
  font-size: 0.45em;
  font-weight: 400;
  line-height: 1;
  vertical-align: 0.35em;
  letter-spacing: 0;
}

.stage__intro {
  margin-top: 22px;
  margin-left: calc(var(--hl-indent) + var(--hl-step));
  font-size: var(--fs-lead);
  letter-spacing: -0.04em;
  line-height: 1.25;
  color: var(--c-hero-ink);
}

/* --- Scroll cue ----------------------------------------------------------- */
.scroll-cue {
  display: block;
  margin-top: 78px;
  margin-left: calc(var(--hl-indent) + var(--hl-step));
  padding: 0;
  border: 0;
  background: transparent;
  color: rgba(250, 250, 250, 0.5);
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.25s var(--ease);
}

.scroll-cue:hover { color: var(--c-accent); }

/* --- Client strip in the hero --------------------------------------------- */
.stage__clients {
  margin-top: 74px;
}

/* Every mark reads as one ink on the hero, whatever colour it was drawn in:
   brightness(0) flattens it to black and invert(1) lifts that to pure white,
   so the strip carries no competing brand colours. It sits at a quarter
   strength by default and comes up under the pointer. */
.stage__clients .clients__item {
  --reveal-opacity: 0.25;
  filter: grayscale(1) brightness(0) invert(1);
}

.stage__clients .clients__item:hover {
  --reveal-opacity: 0.9;
  filter: grayscale(1) brightness(0) invert(1);
}

/* --- Acts two and three ---------------------------------------------------
   They sit over act one's space, so the three exchange places rather than
   stack. Each carries its own opacity and offset, so one can be leaving while
   the next arrives. */
.stage__line {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  align-content: center;
  gap: 28px;
  margin: 0;
  margin-left: var(--hl-indent);
  /* One measure for both paragraphs — an absolute value, because `ch` here
     would resolve against the container's inherited size, not the display
     size the paragraphs are actually set in. */
  max-width: min(100%, 820px);
  pointer-events: none;
}

.stage__statement {
  font-size: var(--fs-statement);
  font-weight: 500;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--c-hero-ink);
  text-wrap: balance;
}

/* The closing act sets both of its paragraphs at the statement size, so the
   fold reads as one voice rather than as a caption above a headline. What
   separates them is weight and brightness, not scale: this one is the
   reasoning, the one under it is the point. */
.stage__lead {
  font-size: var(--fs-statement);
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: rgba(250, 250, 250, 0.68);
}

/* One lime phrase per act — the payoff of each statement, not decoration. */
.stage__hi {
  color: var(--c-accent);
  text-shadow: 0 0 26px rgba(229, 254, 74, 0.35);
}

.stage__line--two {
  opacity: var(--a2);
  transform: translate3d(0, var(--t2), 0);
}

.stage__line--three {
  opacity: var(--a3);
  transform: translate3d(0, var(--t3), 0);
}

/* --- Progress line -------------------------------------------------------- */
.stage__progress {
  position: absolute;
  left: var(--hl-indent);
  bottom: -56px;
  width: min(420px, 50%);
  height: 1px;
  background: rgba(229, 254, 74, 0.18);
  opacity: var(--plv);
  /* Past the last act it does not merely fade — it slips downward out of the
     frame, so the sequence closes rather than dissolving in place. */
  transform: translateY(calc(var(--pld, 0) * 26px));
  z-index: 1;
}

.stage__progress > span {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--c-accent);
  box-shadow: 0 0 12px rgba(229, 254, 74, 0.7);
  transform-origin: left center;
  transform: scaleX(var(--pl));
}

/* --- Cinema mode ---------------------------------------------------------- */

/* Only here does the pin actually pin. JS treats this computed value as the
   switch: no sticky, no scroll driver. */
@media (prefers-reduced-motion: no-preference) {
  .js .stage { height: 280vh; }

  .js .stage__pin {
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100svh;
    min-height: 0;
    padding-block: 0;
    overflow: hidden;
  }
}

/* --- Load sequence -------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .js .hl__mask {
    transform: translateY(115%);
    transition: transform 0.9s var(--ease) var(--hl-d, 0ms);
  }
  .js .hl__line:nth-child(1) { --hl-d: 120ms; }
  .js .hl__line:nth-child(2) { --hl-d: 240ms; }
  .js .hl__line:nth-child(3) { --hl-d: 360ms; }

  .js .stage__intro,
  .js .scroll-cue,
  .js .stage__clients {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
  }
  .js .stage__intro   { transition-delay: 0.62s; }
  .js .scroll-cue     { transition-delay: 0.74s; }
  .js .stage__clients { transition-delay: 0.86s; }

  .js .stage.is-loaded .hl__mask { transform: none; }

  .js .stage.is-loaded .stage__intro,
  .js .stage.is-loaded .scroll-cue,
  .js .stage.is-loaded .stage__clients {
    opacity: 1;
    transform: none;
  }
}

/* Reduced motion, or no JS: the three acts read as plain stacked blocks. */
@media (prefers-reduced-motion: reduce) {
  .stage__acts     { opacity: 1; transform: none; }
  .stage__line     { position: static; opacity: 1; transform: none;
                     max-width: none; margin-top: 56px; }
  .stage__progress { position: static; margin-top: 28px; opacity: 1; }
  .stage__progress > span { transform: scaleX(1); }
}

html:not(.js) .stage__line { position: static; opacity: 1; transform: none;
                             max-width: none; margin-top: 56px; }
html:not(.js) .stage__progress { position: static; margin-top: 28px; opacity: 1; }

/* --------------------------------------------------------------------------
   8. Highlights
   -------------------------------------------------------------------------- */
.highlights { padding-block: var(--band-pad-y); }

.highlights__head { margin-bottom: 62px; }

.highlights__meta {
  margin-top: 22px;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--c-body);
}

.competencies__title {
  font-size: var(--fs-lead);
  font-weight: 700;
  text-transform: uppercase;
  color: var(--c-deep);
  margin-bottom: 30px;
}

.competencies__list {
  list-style: disc;
  padding-left: 30px;
  color: var(--c-body);
  display: grid;
  gap: 12px;
}
.competencies__list li { line-height: 1.35; }

/* --- Tile mosaic (805:2819) ------------------------------------------------
   Three columns that butt together, five tiles, each column offset and sized as
   drawn. Everything is a share of the block, so the arrangement holds at any
   width; container units carry the type down with it. Each tile keeps its
   bottom-left corner square — that asymmetry is the shape's signature. */
.mosaic {
  container-type: inline-size;
  position: relative;
  width: min(100%, 378px);
  aspect-ratio: 377.7 / 409;
  margin-left: auto;
  /* The tiles fill the block exactly, so clipping shows nothing — it just keeps
     their scroll areas from widening the document. */
  overflow: hidden;
}

/* Each tile is its own container, so the label, the figure and the insets scale
   off the tile rather than off the block — that is what lets the two mosaics
   share one component despite sitting in blocks of different widths. Note that
   an element never resolves cqw against itself, so the insets live on the
   children, not on the tile's own padding. */
.mosaic__tile {
  container-type: inline-size;
  position: absolute;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* A length, not cqw: an element never resolves container units against
     itself, so 23cqw here would size off the block and blow the corners out. */
  border-radius: clamp(16px, 2.03vw, 29.28px) clamp(16px, 2.03vw, 29.28px)
                 clamp(16px, 2.03vw, 29.28px) 0;
}

.mosaic__label {
  margin: 22cqw 3cqw 0 19cqw;
  /* A hair under the drawn 18.3px: Outfit fits "Leadership" on one line at that
     size, a wider fallback face does not, and a broken word looks like a bug. */
  font-size: clamp(0.625rem, 13.6cqw, 1.09rem);
  font-weight: 600;
  line-height: 1.15;
  overflow-wrap: break-word;
}

.mosaic__value {
  margin: 0 3cqw 0 19cqw;
  font-size: clamp(1.25rem, 35.5cqw, 2.875rem);
  font-weight: 500;
  line-height: 1.15;
}

/* --- Highlights mosaic (807:2864): four columns in a 513 x 513 block ------ */
.mosaic--skills {
  width: min(100%, 513px);
  aspect-ratio: 1 / 1;
  margin-left: 0;
}

.mosaic__tile--strategy   { left: 0;      top: 28.29%; width: 25.10%; height: 51.79%; }
.mosaic__tile--strategic  { left: 25.10%; top: 14.74%; width: 25.10%; height: 51.79%; }
.mosaic__tile--leadership { left: 50.20%; top: 0;      width: 24.97%; height: 31.35%; }
.mosaic__tile--interface  { left: 50.00%; top: 31.28%; width: 25.10%; height: 68.72%; }
.mosaic__tile--experience { left: 75.10%; top: 13.15%; width: 24.90%; height: 59.76%; }

.mosaic__tile--strategy,
.mosaic__tile--experience {
  background: var(--c-deep);
  color: var(--c-accent);
}

.mosaic__tile--strategic {
  background: var(--c-accent);
  color: var(--c-deep);
}

.mosaic__tile--leadership {
  background: var(--c-cyan);
  color: #ffffff;
}

.mosaic__tile--interface {
  background: var(--c-purple);
  color: #ffffff;
}

/* --- Industry mosaic (827:3195, revising 805:2819) -------------------------
   Three columns in a 377.73 x 409 block, each tile a share of it. The revision
   drops the middle and right columns: Telco no longer starts level with
   Finance, Media is shorter and sits lower, and Startups falls further, so the
   three columns read as a descending stagger rather than a grid. */
/* left column — the only one anchored top and bottom */
.mosaic__tile--finance  { left: 0;      top: 0;      width: 33.33%; height: 68.21%; }
.mosaic__tile--banking  { left: 0;      top: 68.01%; width: 33.33%; height: 31.99%; }
/* middle column, dropped 53px of 409 */
.mosaic__tile--telco    { left: 33.43%; top: 12.96%; width: 33.19%; height: 37.81%; }
.mosaic__tile--media    { left: 33.43%; top: 50.12%; width: 33.19%; height: 31.99%; }
/* right column, dropped further still */
.mosaic__tile--startups { left: 66.67%; top: 32.27%; width: 33.33%; height: 35.61%; }

.mosaic__tile--finance,
.mosaic__tile--startups {
  background: var(--c-purple);
  color: #ffffff;
}

.mosaic__tile--banking { background: var(--c-accent); }
.mosaic__tile--telco   { background: var(--c-accent); }
.mosaic__tile--media   { background: var(--c-cyan); }

/* On the three light tiles both the name and the figure are now the saturated
   purple — the muted ink and the split between label and value are gone. */
.mosaic__tile--banking .mosaic__label,
.mosaic__tile--telco .mosaic__label,
.mosaic__tile--media .mosaic__label,
.mosaic__tile--banking .mosaic__value,
.mosaic__tile--telco .mosaic__value,
.mosaic__tile--media .mosaic__value { color: var(--c-purple); }

/* The band breathes at least as much as Highlights above it, so the two read
   as the same rhythm rather than one crowding the other. */
.industry { padding-block: var(--band-pad-y); }

.industry__lead {
  max-width: 517px;
  margin-top: 32px;
  font-size: var(--fs-lead);
  line-height: 1.35;
  color: var(--c-ink);
}

/* The client strip runs as a marquee: one track duplicated, the pair sliding a
   half-width and looping. The copy is aria-hidden, so it reads once. */
.clients {
  position: relative;
  overflow: hidden;
  /* Fade both ends so the loop has no visible seam. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

.clients__rail {
  display: flex;
  width: max-content;
}

@media (prefers-reduced-motion: no-preference) {
  .clients__rail { animation: clients-run 38s linear infinite; }
  .clients:hover .clients__rail { animation-play-state: paused; }
}

@keyframes clients-run {
  to { transform: translateX(-50%); }
}

.clients__track {
  display: flex;
  align-items: center;
  gap: clamp(2.5rem, 1.4rem + 4.4vw, 4.5rem);
  padding-right: clamp(2.5rem, 1.4rem + 4.4vw, 4.5rem);
  flex: 0 0 auto;
}

.clients__item {
  flex: 0 0 auto;
  --reveal-opacity: var(--logo-opacity);
  filter: var(--logo-filter);
  opacity: var(--reveal-opacity);
  transition: filter 0.3s var(--ease), opacity 0.3s var(--ease);
}

.clients__item:hover {
  --reveal-opacity: 1;
  filter: var(--logo-filter-hover);
}

/* Each logo keeps its own designed box — no shared height is imposed, which
   would distort them relative to one another. */
.clients__item img { height: auto; }

/* --------------------------------------------------------------------------
   10. Projects
   -------------------------------------------------------------------------- */
.projects { padding-block: var(--band-pad-y); }

.projects__head { margin-bottom: 48px; }

.projects__lead {
  max-width: 660px;
  margin-top: 24px;
  font-size: var(--fs-lead);
  line-height: 1.4;
  color: var(--c-body);
}

.project-list { display: grid; gap: 24px; }

/* --- Accordion -------------------------------------------------------------
   A stack of rows divided by hairlines: the row is the category, the panel
   under it the work. One stands open at a time, so the list stays the length
   of the page rather than the length of the archive.

   The panel opens by animating a grid track from 0fr to 1fr — the content
   keeps its natural height, so nothing has to be measured in script, and the
   row reflows correctly when the text rewraps at another width. */
.accordion {
  --acc-rule: rgba(53, 46, 113, 0.16);
  --acc-rule-soft: rgba(53, 46, 113, 0.09);
  border-top: 1px solid var(--acc-rule);
}

.accordion__row { border-bottom: 1px solid var(--acc-rule); }

.accordion__head { margin: 0; }

.accordion__toggle {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin: 0;
  padding: clamp(1.1rem, 0.75rem + 1.1vw, 1.75rem) 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--c-ink);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.accordion__label {
  font-size: var(--fs-h3);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
  transition: opacity 0.25s var(--ease);
}

@media (hover: hover) {
  .accordion__toggle:hover .accordion__label { opacity: 0.62; }
}

/* The sign is two bars; opening collapses the upright one. */
.accordion__sign {
  position: relative;
  flex: 0 0 22px;
  width: 22px;
  height: 22px;
}

.accordion__sign::before,
.accordion__sign::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 1.5px;
  margin-top: -0.75px;
  background: currentColor;
  transition: transform 0.32s var(--ease);
}

.accordion__sign::after { transform: rotate(90deg); }

.accordion__toggle[aria-expanded="true"] .accordion__sign::after {
  transform: rotate(90deg) scaleX(0);
}

.accordion__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.38s var(--ease);
}

.accordion__inner {
  overflow: hidden;
  min-height: 0;
}

.accordion__row.is-open > .accordion__panel { grid-template-rows: 1fr; }

.accordion__inner > * { padding-bottom: clamp(1.5rem, 1rem + 1.5vw, 2.5rem); }

/* Inside an open panel the projects are ruled apart too, on a fainter line
   than the categories — near enough to read as the same system, far enough
   that a row never looks like a category of its own. */
.accordion .project-list { gap: 0; }

.accordion .project-list > li { padding-block: 18px; }

.accordion .project-list > li:first-child { padding-top: 2px; }

.accordion .project-list > li + li { border-top: 1px solid var(--acc-rule-soft); }

/* Unscripted, every panel is simply open and the signs mean nothing. */
html:not(.js) .accordion__panel { grid-template-rows: 1fr; }
html:not(.js) .accordion__sign { display: none; }

@media (prefers-reduced-motion: reduce) {
  .accordion__panel,
  .accordion__sign::before,
  .accordion__sign::after { transition-duration: 0.01ms; }
}

.tag {
  display: inline-flex;
  align-items: center;
  padding: 5px 10px;
  border-radius: var(--radius-pill);
  background: var(--g-tag);
  color: var(--c-on-accent);
  font-size: var(--fs-tag);
  font-weight: 400;
  line-height: 1.25;
  margin-bottom: 16px;
}
.tag--alt { background: var(--g-tag-alt); color: var(--c-on-accent-soft); }

.project__name {
  font-size: var(--fs-item);
  font-weight: 700;
  color: var(--c-ink);
  margin-bottom: 6px;
}

/* An aside on the name line — whose project it was, not what it is. */
.project__note {
  font-weight: 400;
  color: var(--c-body);
}

.project__desc {
  font-size: var(--fs-item);
  font-weight: 500;
  color: var(--c-body);
}

/* --------------------------------------------------------------------------
   11. Contact
   -------------------------------------------------------------------------- */
/* Two indents carry the whole block, as drawn: the mark hangs left of the
   column, the availability line and the headline share one step in, and the
   body copy sits a second step deeper. The pill is pulled back by its own
   padding so that its text — not its edge — lines up with that copy. */
.contact {
  --ct-lead: var(--hl-indent);              /* 103px at 1440 — the hero's step */
  --ct-body: clamp(0px, 15.14vw, 218px);

  padding-block: 108px 168px;
  overflow: hidden;
}

.contact__logo {
  width: 57px;
  height: 50px;
}

/* Only where there is room to spare does the mark step outside the column. */
@media (min-width: 1100px) {
  .contact__logo { margin-left: -29px; }
}

.contact__status {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: var(--ct-lead);
  margin-top: clamp(2rem, 0.9rem + 3.2vw, 4.625rem);   /* → 74px */
  font-size: 10px;
  font-weight: 600;
  color: var(--c-hero-ink);
  opacity: 0.5;
}

.contact__title {
  margin-left: var(--ct-lead);
  font-size: var(--fs-hero);               /* 40 → 80px, the hero's own scale */
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.02em;
  color: var(--c-hero-ink);
}

.contact__body {
  display: grid;
  /* The frame draws an empty line between the two sentences rather than a
     tighter paragraph space, so the gap is a full line. */
  gap: 1.25em;
  max-width: 539px;
  margin-left: var(--ct-body);
  margin-top: 16px;
  font-size: var(--fs-lead);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: -0.04em;
  color: var(--c-hero-ink);
}

.contact__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 13px;
  margin-left: max(0px, calc(var(--ct-body) - 24px));
  margin-top: 22px;
}

/* Phone and mail are two separate targets, so each gets its own pill: one
   thing to tap, one thing to read, and the row still sits on the drawn
   48px line. */
/* --- Contact pills (979:4577) ----------------------------------------------
   Two states. At rest the pill is the same pane of glass the language picker
   is made of — a translucent white fill over the hero, with a hairline
   gradient rim; under the pointer it fills with the brand acid and the label
   and glyph turn to the deep ink. The glyph is a mask rather than an image, so
   one asset serves both states and takes its colour from the text. */
.contact__reveal { display: contents; }

.contact__pill {
  display: inline-flex;
  align-items: center;
  gap: 10px;                               /* icon to label, as drawn */
  position: relative;
  min-height: 48px;
  margin: 0;
  padding: 10px 24px;
  border: 0;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.1);
  color: var(--c-hero-ink);
  font: inherit;
  font-size: var(--fs-item);               /* 18px at 1440 */
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition:
    background-color 0.25s var(--ease),
    color 0.25s var(--ease),
    transform 0.25s var(--ease),
    box-shadow 0.25s var(--ease);
}

.contact__pill[hidden] { display: none; }

/* The hairline rim: a 1px border painted with a gradient, its middle cut out
   by mask-composite — the same recipe the pickers use. */
.contact__pill::after {
  content: "";
  position: absolute;
  inset: 0;
  box-sizing: border-box;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(
    145deg,
    rgba(255, 255, 255, 0.55) 0%,
    rgba(255, 255, 255, 0.14) 34%,
    rgba(255, 255, 255, 0) 55%,
    rgba(255, 255, 255, 0.22) 100%
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  opacity: 1;
  pointer-events: none;
  transition: opacity 0.25s var(--ease);
}

.contact__pill-icon {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'/%3E");
  flex: 0 0 24px;
  width: 24px;
  height: 24px;
  background: currentColor;
  -webkit-mask: var(--icon) center / 24px 24px no-repeat;
  mask: var(--icon) center / 24px 24px no-repeat;
}

/* The two glyphs — Communication/Phone (977:4487) and Communication/Mail
   (979:4496), 24 x 24 — are inlined here as data URIs rather than linked as
   files: the mask needs no extra request, works when the page is opened
   straight from disk, and takes its colour from the label, so one asset
   serves the white state and the deep-ink one alike. The source files are
   kept in assets/img/Communication/ for reference. */
.contact__pill-icon--phone { --icon: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath d='M9.50246 4.25722C9.19873 3.4979 8.46332 3 7.64551 3H4.89474C3.8483 3 3 3.8481 3 4.89453C3 13.7892 10.2108 21 19.1055 21C20.1519 21 21 20.1516 21 19.1052L21.0005 16.354C21.0005 15.5361 20.5027 14.8009 19.7434 14.4971L17.1069 13.4429C16.4249 13.1701 15.6483 13.2929 15.0839 13.7632L14.4035 14.3307C13.6089 14.9929 12.4396 14.9402 11.7082 14.2088L9.79222 12.2911C9.06079 11.5596 9.00673 10.3913 9.66895 9.59668L10.2363 8.9163C10.7066 8.35195 10.8305 7.57516 10.5577 6.89309L9.50246 4.25722Z' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E %3C/svg%3E"); }

.contact__pill-icon--mail { --icon: url("data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cpath d='M4 6L10.1076 10.6123L10.1097 10.614C10.7878 11.1113 11.1271 11.3601 11.4988 11.4562C11.8272 11.5412 12.1725 11.5412 12.501 11.4562C12.8729 11.36 13.2132 11.1105 13.8926 10.6123C13.8926 10.6123 17.8101 7.60594 20 6M3 15.8002V8.2002C3 7.08009 3 6.51962 3.21799 6.0918C3.40973 5.71547 3.71547 5.40973 4.0918 5.21799C4.51962 5 5.08009 5 6.2002 5H17.8002C18.9203 5 19.4796 5 19.9074 5.21799C20.2837 5.40973 20.5905 5.71547 20.7822 6.0918C21 6.5192 21 7.07899 21 8.19691V15.8036C21 16.9215 21 17.4805 20.7822 17.9079C20.5905 18.2842 20.2837 18.5905 19.9074 18.7822C19.48 19 18.921 19 17.8031 19H6.19691C5.07899 19 4.5192 19 4.0918 18.7822C3.71547 18.5905 3.40973 18.2842 3.21799 17.9079C3 17.4801 3 16.9203 3 15.8002Z' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E %3C/svg%3E"); }

/* Filled state: the acid ground leaves no glass to rim. */
@media (hover: hover) {
  .contact__pill:hover,
  .contact__pill:focus-visible {
    background: var(--c-accent);
    color: var(--c-on-accent);
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(229, 254, 74, 0.22);
  }
  .contact__pill:hover::after,
  .contact__pill:focus-visible::after { opacity: 0; }
}

/* Once the detail is showing, the pill stays filled — it is the answer now,
   not an invitation. */
.contact__pill[href] {
  background: var(--c-accent);
  color: var(--c-on-accent);
}
.contact__pill[href]::after { opacity: 0; }

.contact__social {
  display: block;
  flex: 0 0 48px;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  transition: transform 0.25s var(--ease);
}

.contact__social img {
  width: 48px;
  height: 48px;
}

@media (hover: hover) {
  .contact__social:hover { transform: translateY(-2px); }
}


/* --------------------------------------------------------------------------
   12. Typical engagements (824:3141)

   A grey band on the same ground as Industry experience: a two-line display
   heading, then four bold-and-body pairs in two columns. The drawn frame is
   1138 wide with a 104px gutter; here that gutter is kept as its share of the
   page's own 1060 column rather than as an absolute, so the pairs sit at the
   same relative distance at every width.
   -------------------------------------------------------------------------- */
.engagements { padding-block: var(--band-pad-y); }

.engagements__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(2rem, -0.2rem + 6.7vw, 6rem);
  margin-top: clamp(2.5rem, 0.5rem + 4.4vw, 6.5rem);   /* 40 → 104 */
}

.engagements__col {
  display: grid;
  align-content: start;
  gap: 32px;
}

.engagement__name {
  font-size: var(--fs-lead);
  font-weight: 700;
  line-height: 1.25;
  color: var(--c-ink);
}

.engagement__body {
  font-size: var(--fs-lead);
  font-weight: 400;
  line-height: 1.25;
  color: var(--c-ink);
}

@media (max-width: 700px) {
  .engagements__grid { grid-template-columns: minmax(0, 1fr); gap: 32px; }
}

/* --------------------------------------------------------------------------
   13. Footer

   The page is one scroll with a headline, not a set of pages, so this is where
   the plain-text version of it lives: what the work is called, which sectors it
   has been done in, and how to reach him. It sits on the same ground as the
   contact band above, separated by a hairline rather than a colour change.
   -------------------------------------------------------------------------- */
.site-footer {
  position: relative;
  padding-inline: var(--gutter);
  padding-block: clamp(2.5rem, 1.5rem + 3.3vw, 4.5rem) clamp(1.75rem, 1.2rem + 1.9vw, 2.5rem);
  background: var(--c-hero-bg);
  color: rgba(250, 250, 250, 0.62);
  font-size: 0.9375rem;
  line-height: 1.55;
}

.site-footer::before {
  content: "";
  position: absolute;
  inset: 0 var(--gutter) auto;
  height: 1px;
  background: linear-gradient(90deg,
    rgba(229, 254, 74, 0.35), rgba(250, 250, 250, 0.12) 40%, transparent);
}

/* The brand column carries the prose and takes twice the width of a list. */
.site-footer__top {
  display: grid;
  grid-template-columns: 1.9fr repeat(3, minmax(0, 1fr));
  gap: clamp(1.75rem, 0.5rem + 3.5vw, 3rem);
}

.site-footer__mark {
  width: 46px;
  height: 40px;
  margin-bottom: 18px;
}

.site-footer__name {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--c-hero-ink);
}

.site-footer__role {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--c-accent);
  margin-bottom: 14px;
}

.site-footer__pitch {
  max-width: 40ch;
  font-size: 0.9375rem;
}

/* The bar between the two halves of the line, dimmed so it separates without
   reading as punctuation. */
.site-footer__pitch span { opacity: 0.4; }

.site-footer__title {
  margin-bottom: 14px;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(250, 250, 250, 0.45);
}

.site-footer__list {
  display: grid;
  gap: 8px;
}

.site-footer a {
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}

.site-footer a:hover {
  color: var(--c-accent);
  border-bottom-color: rgba(229, 254, 74, 0.5);
}

.site-footer__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 24px;
  margin-top: clamp(2rem, 1.2rem + 2.6vw, 3.25rem);
  padding-top: 22px;
  border-top: 1px solid rgba(250, 250, 250, 0.08);
  font-size: 0.8125rem;
  color: rgba(250, 250, 250, 0.42);
}

/* Back to top closes the page where a second copy of the address used to sit.
   The arrow lifts on hover, so the direction is legible before the label is
   read; the anchor itself is enough, since the document already scrolls
   smoothly. */
.site-footer__top-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px 7px 12px;
  border: 1px solid rgba(250, 250, 250, 0.14);
  border-radius: var(--radius-pill);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  transition:
    color 0.25s var(--ease),
    border-color 0.25s var(--ease),
    background-color 0.25s var(--ease);
}

.site-footer .site-footer__top-link:hover {
  color: var(--c-accent);
  border-color: rgba(229, 254, 74, 0.45);
  background: rgba(229, 254, 74, 0.07);
}

.site-footer__top-arrow {
  display: block;
  line-height: 1;
  transition: transform 0.25s var(--ease);
}

@media (prefers-reduced-motion: no-preference) {
  .site-footer__top-link:hover .site-footer__top-arrow {
    transform: translateY(-3px);
  }
}

@media (max-width: 860px) {
  .site-footer__top { grid-template-columns: 1fr 1fr; }
  .site-footer__brand { grid-column: 1 / -1; }
}

@media (max-width: 560px) {
  .site-footer__top { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  .site-footer__pitch { max-width: none; }
  .site-footer__bar { justify-content: flex-start; }
}

/* --------------------------------------------------------------------------
   14. Motion

   Everything here is gated three ways: the document must be scripted (.js), the
   visitor must not have asked for reduced motion, and the hero is deliberately
   left out so the first screen is complete the moment it loads.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {

  /* Text and blocks rise a short distance as they come into view. Children of a
     [data-stagger] group carry their own --d, set in JS, so a list arrives as a
     sequence rather than all at once. */
  .js .reveal,
  .js [data-stagger] > * {
    opacity: 0;
    transform: translateY(18px);
    transition:
      opacity 0.65s var(--ease) var(--d, 0ms),
      transform 0.65s var(--ease) var(--d, 0ms);
    will-change: opacity, transform;
  }

  /* The tiles do not fade in with everything else — they build up from their
     own base, column by column, which is how the mosaic reads in the first
     place. The clip sits on the tile rather than on a wrapper because nothing
     observes a tile: the block above it is what IntersectionObserver watches,
     so a clipped box here costs no intersection area. */
  .js .mosaic__tile {
    opacity: 1;
    clip-path: inset(100% 0 0 0);
    transform: translateY(8px);
    transition:
      clip-path 0.72s var(--ease) var(--d, 0ms),
      transform 0.72s var(--ease) var(--d, 0ms);
    will-change: clip-path, transform;
  }

  .js .mosaic__tile.is-visible {
    clip-path: inset(0);
    transform: none;
    will-change: auto;
  }

  .js .reveal.is-visible,
  .js [data-stagger] > .is-visible {
    opacity: var(--reveal-opacity, 1);
    transform: none;
    will-change: auto;
  }

  /* The display headings wipe up from their own baseline instead of fading.
     The clip sits on an inner span, never on the observed element: a clipped
     box has no intersection area, so IntersectionObserver would never see it.
     The padding/margin pair widens the clip box so descenders are not shaved —
     inset() rejects negative values, which would drop the rule entirely. */
  .js .reveal--mask {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .js .reveal--mask > span {
    display: block;
    padding-bottom: 0.16em;
    margin-bottom: -0.16em;
    clip-path: inset(0 0 100% 0);
    transform: translateY(10px);
    transition:
      clip-path 0.85s var(--ease) var(--d, 0ms),
      transform 0.85s var(--ease) var(--d, 0ms);
  }

  .js .reveal--mask.is-visible > span {
    clip-path: inset(0);
    transform: none;
  }

  /* Decorative shapes drift against the scroll. JS writes --py; the amplitude
     is small enough to read as depth rather than as an effect. */
  [data-parallax] {
    transform: translate3d(0, var(--py, 0px), 0);
    will-change: transform;
  }
}

/* Row-level micro-interactions — these are hover states, so they apply
   whatever the motion preference, minus the movement. */
.project-list > li {
  transition: transform 0.3s var(--ease);
}

@media (prefers-reduced-motion: no-preference) {
  .project-list > li:hover { transform: translateX(6px); }
}

.project-list > li:hover .project__name { color: var(--c-badge); }
.project__name { transition: color 0.3s var(--ease); }

/* --------------------------------------------------------------------------
   15. Responsive
   -------------------------------------------------------------------------- */

/* Tablet ------------------------------------------------------------------- */
@media (max-width: 1024px) {
  .stage__line { max-width: min(100%, 660px); }
  .stage__clients { margin-top: 56px; }
  .scroll-cue { margin-top: 60px; }

  .projects__head { margin-bottom: 72px; }
  .contact { padding-block: 88px 128px; }
}

/* Small tablet / large phone ---------------------------------------------- */
@media (max-width: 860px) {
  .cols {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(3rem, 8vw, 4.5rem);
  }

  /* The sequence still pins here; the headline just drops its indents. */
  .contact { --ct-body: var(--hl-indent); }

  .stage__line { max-width: none; gap: 20px; }
  .mosaic { margin-left: 0; }
  .stage__progress { bottom: -46px; width: min(300px, 66%); }

  .stage__clients { margin-top: 44px; }
  .scroll-cue { margin-top: 44px; }

  .hl__arrow { margin-right: 20px; }
  .stage { --hl-step: calc(var(--hl-arrow) + 48px); }


}

/* Phone -------------------------------------------------------------------- */
@media (max-width: 560px) {
  .site-header { height: 80px; }
  .toggle-group { gap: 10px; }

  .contact { --ct-lead: 0px; --ct-body: 0px; }
  .site-header { height: 84px; }
  .site-header__brand img { width: 44px; height: 39px; }
  .site-header__cta { font-size: 1rem; }

  .hl__pill { padding-inline: 14px; margin-left: -8px; }
  .hl__arrow { width: 20px; margin-right: 14px; }
  .stage { --hl-arrow: 0px; --hl-step: 34px; }
  .stage__clients { margin-top: 36px; }



  .clients__track { gap: 2.25rem; padding-right: 2.25rem; }

  .projects__head { margin-bottom: 48px; }
  .contact { padding-block: 72px 88px; }
  /* Narrow enough that the two pills stack; each keeps its own shape. */
  .contact__pill { padding-inline: 20px; }
}
