/* ==========================================================================
   Components, in the order they appear down the page.
   ========================================================================== */

/* ============================================================== 1. header = */
.hdr {
  position: sticky; top: 0; z-index: 50;
  border-bottom: 1px solid transparent;
  transition: background var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease);
}
/* Solid only once the page has moved — over the hero it should be invisible. */
.hdr.is-stuck {
  background: rgba(8, 11, 14, .82);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  border-bottom-color: var(--line);
}
.hdr__in {
  display: flex; align-items: center; gap: var(--s-5);
  height: 72px;
}

.brand { display: inline-flex; align-items: center; flex: 0 0 auto; }
/* The wordmark carries the identity, so it is the logo file itself rather than
   text plus a mark. Height is fixed and width follows, which keeps the mosaic
   from ever being squashed. */
.brand__logo { height: 22px; width: auto; }
@media (max-width: 480px) { .brand__logo { height: 19px; } }

.nav { display: flex; align-items: center; gap: var(--s-5); margin-left: auto; }
.nav__link {
  font-size: var(--fs-sm); color: var(--ink-2);
  transition: color var(--t-fast) var(--ease);
}
.nav__link:hover { color: var(--ink); }
/* The nav's CTA exists for the mobile panel only — on desktop the button in
   .hdr__tools is the one, and two identical buttons in one bar read as a bug. */
.nav > .btn { display: none; }

.hdr__tools { display: flex; align-items: center; gap: var(--s-3); flex: 0 0 auto; }

/* Language pill. Two states, both always visible — a flag or a single letter
   makes people guess what the other option is. */
.lang {
  display: inline-flex; padding: 3px; gap: 2px;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .04);
}
.lang button {
  appearance: none; border: 0; cursor: pointer;
  padding: 4px 10px; border-radius: var(--r-pill);
  background: transparent; color: var(--ink-3);
  font-size: var(--fs-2xs); font-weight: 620; letter-spacing: .06em;
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.lang button:hover { color: var(--ink); }
.lang button[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-hot); }

/* Mobile menu button — hidden on desktop, where the nav is inline. */
.burger {
  display: none; appearance: none; cursor: pointer;
  width: 40px; height: 40px; padding: 0;
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: rgba(255, 255, 255, .04);
}
.burger span {
  display: block; width: 16px; height: 1.5px; margin: 3px auto;
  background: var(--ink); border-radius: 2px;
  transition: transform var(--t-mid) var(--ease), opacity var(--t-fast) var(--ease);
}
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(4.5px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-4.5px) rotate(-45deg); }

/* ============================================================= 2. buttons = */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  padding: 12px 20px; border-radius: var(--r-pill);
  border: 1px solid transparent;
  font-size: var(--fs-sm); font-weight: 620; letter-spacing: -.005em;
  cursor: pointer; white-space: nowrap;
  transition: transform var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn--primary {
  background: var(--accent); color: var(--accent-ink);
  box-shadow: 0 10px 30px -14px rgba(255, 106, 77, .8);
}
.btn--primary:hover { background: var(--accent-hot); }
.btn--ghost { border-color: var(--line-strong); color: var(--ink); background: transparent; }
.btn--ghost:hover { border-color: var(--accent-line); background: var(--accent-soft); color: var(--accent-hot); }
.btn--lg { padding: 15px 26px; font-size: var(--fs-md); }
.btn[disabled] { opacity: .55; cursor: not-allowed; }
.btn svg { width: 16px; height: 16px; }

/* ================================================================ 3. hero = */
.hero {
  position: relative;
  padding-block: clamp(48px, 6vw, 92px) clamp(40px, 5vw, 72px);
  overflow: hidden;
  text-align: center;
}
.hero__bg { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.hero__in { position: relative; z-index: 1; max-width: 880px; }
/* A soft floor under the copy, so a bright pulse passing behind it can never
   take the contrast below readable. */
.hero__in::before {
  content: ""; position: absolute; inset: -6% -8%; z-index: -1;
  background: radial-gradient(ellipse 60% 58% at 50% 50%,
              rgba(6, 10, 20, .92) 0%, rgba(6, 10, 20, .72) 55%, transparent 78%);
}
.hero .eyebrow { justify-content: center; }
/* The wordmark sits where the reference puts the chip: the traces come out of
   it, so it has to be the optical centre of the field. */
.hero__logo {
  width: min(460px, 74vw); height: auto;
  margin: var(--s-5) auto var(--s-4);
}
.hero h1 { margin: 0; }
.hero h1 em {
  font-style: normal;
  background: var(--brand-ramp);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.hero__lede {
  margin: var(--s-4) auto 0;
  max-width: 58ch;
  font-size: var(--fs-lg);
  line-height: 1.5;
  color: var(--ink-2);
}
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-5); justify-content: center; }

/* Proof strip. Numbers, not adjectives. */
.stats {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s-4);
  margin-top: clamp(32px, 4vw, 52px);
  padding-top: var(--s-5);
  border-top: 1px solid var(--line);
  position: relative; z-index: 1;
}
.stats dt {
  font-size: clamp(22px, 2vw, 30px); font-weight: 680; letter-spacing: -.03em;
  background: var(--brand-ramp); -webkit-background-clip: text; background-clip: text;
  color: transparent;
}
.stats dd { margin: 4px 0 0; font-size: var(--fs-xs); color: var(--ink-3); line-height: 1.35; }
@media (max-width: 720px) { .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ============================================================ 4. services = */
.svc {
  position: relative;
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-5) var(--s-4) var(--s-4);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--surface), rgba(14, 22, 38, .5));
  overflow: hidden;
  transition: border-color var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
}
/* Each card takes one stop of the wordmark's ramp, in order, so the six
   services and the six colours of the logo are visibly the same set. */
.svc::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--c, var(--accent)); opacity: .8;
}
.grid > .svc:nth-child(1) { --c: var(--c-teal); }
.grid > .svc:nth-child(2) { --c: var(--c-cyan); }
.grid > .svc:nth-child(3) { --c: var(--c-blue); }
.grid > .svc:nth-child(4) { --c: var(--c-violet); }
.grid > .svc:nth-child(5) { --c: var(--c-mauve); }
.grid > .svc:nth-child(6) { --c: var(--c-coral); }
.svc:hover { border-color: var(--c, var(--accent-line)); transform: translateY(-2px); }
.svc__n {
  font-family: var(--font-mono); font-size: var(--fs-2xs);
  letter-spacing: .12em; color: var(--c, var(--accent));
}
.svc h3 { font-size: var(--fs-lg); }
.svc p { color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.55; }

/* ============================================================= 5. process = */
.step {
  position: relative;
  padding: var(--s-4) 0 0 var(--s-4);
  border-left: 1px solid var(--line);
}
.step::before {
  content: ""; position: absolute; left: -4px; top: var(--s-5);
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 4px rgba(246, 119, 108, .14);
}
.grid > .step:nth-child(1)::before { background: var(--c-teal);   box-shadow: 0 0 0 4px rgba(36,150,155,.16); }
.grid > .step:nth-child(2)::before { background: var(--c-blue);   box-shadow: 0 0 0 4px rgba(71,144,212,.16); }
.grid > .step:nth-child(3)::before { background: var(--c-violet); box-shadow: 0 0 0 4px rgba(132,128,212,.16); }
.grid > .step:nth-child(4)::before { background: var(--c-coral);  box-shadow: 0 0 0 4px rgba(246,119,108,.16); }
.step__k { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--ink-3); letter-spacing: .1em; }
.step h3 { margin-top: 2px; font-size: var(--fs-lg); }
.step p { margin-top: var(--s-2); color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.5; }
.step__when {
  display: inline-block; margin-top: var(--s-3);
  padding: 3px 9px; border-radius: var(--r-pill);
  background: var(--good-soft); color: var(--good);
  font-family: var(--font-mono); font-size: var(--fs-3xs);
}

/* The stack, as one strip rather than a section of its own. */
.stackbar {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-3) var(--s-4);
  margin-top: clamp(28px, 3vw, 44px); padding-top: var(--s-5);
  border-top: 1px solid var(--line);
}
.stackbar__h {
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-3);
  letter-spacing: .02em; flex: 0 0 auto;
}
.stackbar__chips { display: flex; flex-wrap: wrap; gap: 6px; }
.stackbar__chips li {
  padding: 4px 10px; border-radius: var(--r-pill);
  border: 1px solid var(--line); background: rgba(120, 170, 255, .05);
  font-size: var(--fs-2xs); color: var(--ink-2);
}

/* ============================================================== 6. work == */
/* Two bands of project tiles travelling in opposite directions over a lit
   board. The movement is the effect: it reads at any scroll position, it does
   not fight the scrollbar, and it is two CSS animations rather than a scroll
   handler. */
.section--work {
  position: relative; overflow: hidden;
  background:
    radial-gradient(ellipse 90% 120% at 50% 0%, rgba(71, 144, 212, .12), transparent 70%),
    var(--bg);
  border-block: 1px solid var(--line);
}
.board--work {
  color: #6FA8DC;
  mask-image: linear-gradient(180deg, transparent 0%, #000 22%, #000 88%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 22%, #000 88%, transparent 100%);
}
.section--work .shead {
  position: relative; z-index: 1;
  max-width: none;
  padding-inline: clamp(10px, 1.6vw, 22px);
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 46ch);
  align-items: end; gap: var(--s-5) var(--s-7);
  margin-bottom: var(--s-5);
}
.section--work .shead .eyebrow { grid-column: 1 / -1; margin-bottom: 0; }
.section--work .shead p { margin-top: 0; padding-bottom: 4px; }
@media (max-width: 860px) {
  .section--work .shead { grid-template-columns: minmax(0, 1fr); align-items: start; gap: var(--s-3); }
}

/* --- the two bands ------------------------------------------------------- */
.marq { position: relative; z-index: 1; display: grid; gap: 12px; }
.marq__row {
  overflow: hidden;
  /* the tiles dissolve at both edges rather than being sliced by the viewport */
  mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
/* Each track holds the five projects twice, so translating it by exactly half
   its width returns it to where it started — the loop has no seam. */
.marq__track {
  display: flex; gap: 12px; width: max-content;
  animation: marq-left 64s linear infinite;
  will-change: transform;
}
.marq__row--b .marq__track { animation-name: marq-right; }
@keyframes marq-left  { from { transform: translateX(0); }    to { transform: translateX(-50%); } }
@keyframes marq-right { from { transform: translateX(-50%); } to { transform: translateX(0); } }
/* Reading one of them is easier if it holds still while you point at it. */
.marq:hover .marq__track { animation-play-state: paused; }

.tile {
  position: relative;
  flex: 0 0 auto;
  width: clamp(290px, 25vw, 400px);
  min-height: 208px;
  display: flex; flex-direction: column; gap: 8px;
  padding: var(--s-5) var(--s-4);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: linear-gradient(160deg, var(--surface), rgba(10, 16, 32, .82));
  overflow: hidden;
  transition: border-color var(--t-mid) var(--ease), background var(--t-mid) var(--ease);
}
.tile::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--c, var(--accent)); opacity: .85;
}
.tile:hover { border-color: var(--c); background: linear-gradient(160deg, var(--surface-2), rgba(10, 16, 32, .9)); }

/* One stop of the wordmark's ramp per project, wherever it appears. */
.tile--coral  { --c: var(--c-coral); }
.tile--blue   { --c: var(--c-blue); }
.tile--violet { --c: var(--c-violet); }
.tile--mauve  { --c: var(--c-mauve); }
.tile--teal   { --c: var(--c-teal); }

.tile__tag {
  font-family: var(--font-mono); font-size: var(--fs-3xs);
  letter-spacing: .12em; text-transform: uppercase; color: var(--c);
}
.tile__h { font-size: clamp(19px, 1.5vw, 25px); line-height: 1.14; letter-spacing: -.02em; }
.tile p { color: var(--ink-2); font-size: var(--fs-xs); line-height: 1.5; }
.tile__foot {
  display: flex; flex-wrap: wrap; gap: var(--s-4);
  margin: auto 0 0; padding-top: var(--s-3);
  border-top: 1px solid var(--line);
}
.tile__foot dt {
  font-size: clamp(16px, 1.2vw, 21px); font-weight: 660; letter-spacing: -.02em;
  line-height: 1.15; font-variant-numeric: tabular-nums;
  background: linear-gradient(180deg, var(--ink), var(--c));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.tile__foot dd { margin: 2px 0 0; font-size: var(--fs-3xs); color: var(--ink-3); line-height: 1.35; }

@media (max-width: 560px) {
  .tile { width: 84vw; min-height: 190px; padding: var(--s-4); }
}
/* Without motion the bands would sit frozen and half the tiles would be
   unreachable, so they become two ordinary scrollable strips instead. */
@media (prefers-reduced-motion: reduce) {
  .marq__track { animation: none; }
  .marq__row { overflow-x: auto; }
}

/* ================================================================= 9. faq = */
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  padding: var(--s-4) 0; cursor: pointer; list-style: none;
  font-size: var(--fs-lg); font-weight: 600; letter-spacing: -.01em;
  transition: color var(--t-fast) var(--ease);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--accent-hot); }
.faq summary::after {
  content: ""; flex: 0 0 auto; width: 12px; height: 12px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--t-mid) var(--ease);
}
.faq details[open] summary::after { transform: rotate(-135deg) translate(-3px, -3px); }
.faq details p { padding-bottom: var(--s-4); color: var(--ink-2); max-width: var(--maxw-text); }

/* ============================================================= 10. contact = */
.contact__grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(24px, 4vw, 64px);
  align-items: start;
}
@media (max-width: 900px) { .contact__grid { grid-template-columns: minmax(0, 1fr); } }

.form { display: grid; gap: var(--s-4); }
.field { display: grid; gap: 6px; }
.field label { font-size: var(--fs-sm); color: var(--ink-2); }
.field label span { color: var(--accent); }
.field input, .field select, .field textarea {
  width: 100%; padding: 12px 14px;
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  background: rgba(255, 255, 255, .04); color: var(--ink);
  font-size: var(--fs-sm);
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.field textarea { min-height: 132px; resize: vertical; }
.field input::placeholder, .field textarea::placeholder { color: var(--ink-3); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--accent-line); background: rgba(255, 106, 77, .06);
}
.field select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%),
                    linear-gradient(135deg, var(--ink-3) 50%, transparent 50%);
  background-position: calc(100% - 20px) 50%, calc(100% - 14px) 50%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}
.field select option { background: var(--surface); color: var(--ink); }
/* Validation only speaks up once the field has been touched and left. */
.field.is-bad input, .field.is-bad textarea { border-color: #E4573D; }
.field__err { font-size: var(--fs-2xs); color: #FF8A72; display: none; }
.field.is-bad .field__err { display: block; }

/* The honeypot. Bots fill every field they find; people never see this one. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.form__note { font-size: var(--fs-2xs); color: var(--ink-3); }
.form__status {
  display: none; padding: var(--s-4);
  border-radius: var(--r-md); font-size: var(--fs-sm);
}
.form__status.is-on { display: block; }
.form__status--ok  { background: var(--good-soft); color: var(--good); border: 1px solid rgba(35,196,160,.3); }
.form__status--bad { background: rgba(228, 87, 61, .12); color: #FF8A72; border: 1px solid rgba(228,87,61,.35); }

.contact__aside { display: flex; flex-direction: column; gap: var(--s-5); }
.contact__card {
  padding: var(--s-5); border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--surface);
}
.contact__card h3 { font-size: var(--fs-lg); }
.contact__list { display: grid; gap: var(--s-3); margin-top: var(--s-4); }
.contact__list a {
  display: flex; align-items: center; gap: var(--s-3);
  text-decoration: none; color: var(--ink);
  padding: 12px 14px; border-radius: var(--r-md);
  border: 1px solid var(--line); background: rgba(255, 255, 255, .03);
  font-size: var(--fs-sm);
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.contact__list a:hover { border-color: var(--accent-line); background: var(--accent-soft); }
.contact__list svg { width: 18px; height: 18px; flex: 0 0 auto; color: var(--accent); }
.contact__list b { display: block; }
.contact__next {
  margin-top: var(--s-4); padding-top: var(--s-4); border-top: 1px solid var(--line);
  display: grid; gap: var(--s-2); counter-reset: n;
}
.contact__next li {
  display: flex; gap: var(--s-3); font-size: var(--fs-sm); color: var(--ink-2);
}
.contact__next li::before {
  counter-increment: n; content: counter(n);
  flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
  font-family: var(--font-mono); font-size: var(--fs-3xs);
}
.contact__list span { font-size: var(--fs-2xs); color: var(--ink-3); }

/* ============================================================== 11. footer = */
.ftr { border-top: 1px solid var(--line); padding-block: var(--s-7) var(--s-6); }
.ftr__top { display: flex; flex-wrap: wrap; gap: var(--s-6); justify-content: space-between; }
.ftr__nav { display: flex; flex-wrap: wrap; gap: var(--s-5); }
.ftr__nav a { font-size: var(--fs-sm); color: var(--ink-2); text-decoration: none; }
.ftr__nav a:hover { color: var(--accent-hot); }
.ftr__bottom {
  margin-top: var(--s-6); padding-top: var(--s-5); border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; gap: var(--s-4); justify-content: space-between;
  font-size: var(--fs-2xs); color: var(--ink-3);
}

/* ============================================================ 12. mobile == */
@media (max-width: 860px) {
  .burger { display: block; }
  .hdr__in { height: 64px; }
  /* The nav becomes a panel under the header; it is display:none when closed
     so it cannot be tabbed into while invisible. */
  .nav {
    position: fixed; inset: 64px 0 auto 0;
    display: none; flex-direction: column; align-items: stretch; gap: 0;
    margin: 0; padding: var(--s-4) var(--gutter) var(--s-6);
    background: rgba(8, 11, 14, .97);
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--line);
    max-height: calc(100dvh - 64px); overflow-y: auto;
  }
  .nav.is-open { display: flex; }
  .nav__link {
    padding: 14px 0; font-size: var(--fs-lg); color: var(--ink);
    border-bottom: 1px solid var(--line);
  }
  .nav > .btn { display: inline-flex; margin-top: var(--s-4); }
  .hdr__tools .btn--primary { display: none; }   /* it lives in the panel instead */
}

/* ---------------------------------------------------------------------------
   Classes that replaced inline style attributes. They are here rather than in
   the markup because the site sends a Content-Security-Policy without
   'unsafe-inline': a style="" attribute is simply dropped by the browser.
   --------------------------------------------------------------------------- */
.u-gap-4 { gap: var(--s-4); }
.ftr__blurb { margin-top: var(--s-3); max-width: 42ch; }
.form__submit { display: flex; flex-wrap: wrap; gap: var(--s-4); align-items: center; }

/* 404 */
.nf { min-height: 70dvh; display: grid; place-items: center; text-align: center; }
.nf__in { max-width: 56ch; }
.nf__eyebrow { justify-content: center; }
.nf__h { margin-top: var(--s-4); font-size: var(--fs-3xl); }
.nf__p { margin-top: var(--s-4); }
.nf__cta { margin-top: var(--s-6); }

/* ---------------------------------------------- a tile links to its case -- */
/* The whole tile is a link to that project in the cases section. It is an <a>
   stretched over the card rather than a wrapper, because a link may not contain
   a heading. */
.tile__hit {
  position: absolute; inset: 0; z-index: 2;
  border-radius: var(--r-lg);
}
.tile__hit:focus-visible { outline: 2px solid var(--c, var(--accent-hot)); outline-offset: -3px; }
.tile:has(.tile__hit:hover) { border-color: var(--c); }
/* The heading picks up the tile's colour on hover, so it reads as a link. */
.tile:has(.tile__hit:hover) .tile__h { color: var(--c); }
.tile__h { transition: color var(--t-fast) var(--ease); }

.shead__more {
  display: inline-block; margin-left: var(--s-2);
  color: var(--accent-hot); text-decoration: none; white-space: nowrap;
  border-bottom: 1px solid var(--accent-line);
}
.shead__more:hover { border-bottom-color: var(--accent-hot); }

/* ================================================ 7. the cases section == */
.chero { padding-bottom: 0; }
.chero h1 { margin-top: var(--s-4); font-size: clamp(30px, 3.4vw, 54px); }
.chero__lede {
  margin-top: var(--s-4); max-width: 62ch;
  font-size: var(--fs-lg); line-height: 1.5; color: var(--ink-2);
}

/* The index: one card per case, each a link to its own page. */
/* Three across, because no direction holds more than three cases: a fourth
   column would leave every group with a hole in it. Density comes from the
   cards being smaller, not from more of them per row. */
.ccards {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(8px, .8vw, 12px);
}
@media (max-width: 1000px) { .ccards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .ccards { grid-template-columns: minmax(0, 1fr); } }

.ccard {
  position: relative; display: flex; flex-direction: column; gap: 6px;
  padding: var(--s-4) var(--s-3) var(--s-3);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: linear-gradient(160deg, var(--surface), rgba(10, 16, 32, .82));
  overflow: hidden;
  transition: border-color var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
}
.ccard::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--c); opacity: .85;
}
.ccard:hover { border-color: var(--c); transform: translateY(-2px); }
.ccard--coral  { --c: var(--c-coral); }
.ccard--blue   { --c: var(--c-blue); }
.ccard--violet { --c: var(--c-violet); }
.ccard--mauve  { --c: var(--c-mauve); }
.ccard--teal   { --c: var(--c-teal); }
.ccard__tag {
  font-family: var(--font-mono); font-size: var(--fs-3xs);
  letter-spacing: .12em; text-transform: uppercase; color: var(--c);
}
.ccard__h { font-size: clamp(16px, 1.05vw, 19px); line-height: 1.18; letter-spacing: -.015em; }
/* The task is a taste of the case, not the case: three lines, then the card
   stops and the link takes over. Clamping also squares off the ragged card
   heights that long tasks used to produce. */
.ccard p {
  color: var(--ink-2); font-size: var(--fs-2xs); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.ccard__facts {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-3);
  margin: auto 0 0; padding-top: var(--s-2); border-top: 1px solid var(--line);
}
.ccard__facts dt {
  font-size: var(--fs-sm); font-weight: 660; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  background: linear-gradient(180deg, var(--ink), var(--c));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.ccard__facts dd { margin: 1px 0 0; font-size: var(--fs-3xs); line-height: 1.3; color: var(--ink-3); }
.ccard__go { margin-top: var(--s-2); font-size: var(--fs-3xs); color: var(--c); }

/* --- one case, on its own page -------------------------------------------- */
.cpage--coral  { --c: var(--c-coral); }
.cpage--blue   { --c: var(--c-blue); }
.cpage--violet { --c: var(--c-violet); }
.cpage--mauve  { --c: var(--c-mauve); }
.cpage--teal   { --c: var(--c-teal); }
.cpage .eyebrow { color: var(--c); }
.cpage .eyebrow::before { background: var(--c); }
.cpage__back {
  /* Block, not inline-block: beside an inline-flex eyebrow the two ran onto
     one line and read as a single broken sentence. */
  display: block; width: fit-content; margin-bottom: var(--s-5);
  font-size: var(--fs-sm); color: var(--ink-3);
}
.cpage__back:hover { color: var(--c); }
.cpage h1 { margin-top: var(--s-4); font-size: clamp(28px, 3.2vw, 50px); }
.cpage__lede {
  margin-top: var(--s-4); max-width: 66ch;
  font-size: var(--fs-lg); line-height: 1.5; color: var(--ink-2);
}

/* The numbers sit right under the title: they are the reason to read on. */
.case__facts {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-4); margin: var(--s-5) 0 0; padding: 0 0 var(--s-5);
  /* Bottom rule only: the heading above already draws one, and a border on both
     sides put two lines under «Результаты» with a gap between them. */
  border-bottom: 1px solid var(--line);
}
@media (max-width: 620px) { .case__facts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.case__facts dt {
  font-size: clamp(20px, 2vw, 32px); font-weight: 660; letter-spacing: -.025em;
  line-height: 1.15; font-variant-numeric: tabular-nums;
  background: linear-gradient(180deg, var(--ink), var(--c));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.case__facts dd { margin: 4px 0 0; font-size: var(--fs-2xs); color: var(--ink-3); line-height: 1.35; }

.case__cols {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-5) var(--s-7); margin-top: clamp(24px, 3vw, 40px);
}
@media (max-width: 860px) { .case__cols { grid-template-columns: minmax(0, 1fr); } }
.case__cols h2 {
  font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--c);
}
.case__cols h2 + p, .case__cols h2 + ul { margin-top: var(--s-3); }
.case__cols p { color: var(--ink-2); font-size: var(--fs-md); line-height: 1.65; max-width: 58ch; }
.case__list { display: grid; gap: 10px; }
.case__list li {
  position: relative; padding-left: 20px;
  font-size: var(--fs-sm); line-height: 1.55; color: var(--ink-2);
}
.case__list li::before {
  content: ""; position: absolute; left: 0; top: 8px;
  width: 6px; height: 6px; border-radius: 2px; background: var(--c);
}
.case__chips { display: flex; flex-wrap: wrap; gap: 6px; }
.case__chips li {
  padding: 6px 12px; border-radius: var(--r-pill);
  border: 1px solid var(--line); background: rgba(120, 170, 255, .05);
  font-size: var(--fs-2xs); color: var(--ink-2);
}

/* Previous / next, so the section can be read straight through. */
.cpn {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px;
  margin-top: clamp(32px, 4vw, 56px); padding-top: var(--s-5);
  border-top: 1px solid var(--line);
}
@media (max-width: 620px) { .cpn { grid-template-columns: minmax(0, 1fr); } }
.cpn__item {
  display: flex; flex-direction: column; gap: 6px;
  padding: var(--s-4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: rgba(120, 170, 255, .04);
  transition: border-color var(--t-fast) var(--ease);
}
.cpn__item:hover { border-color: var(--accent-line); }
.cpn__item--next { text-align: right; }
.cpn__item--next:only-child { grid-column: 2; }
.cpn__dir {
  font-family: var(--font-mono); font-size: var(--fs-3xs);
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
.cpn__h { font-size: var(--fs-md); font-weight: 600; letter-spacing: -.01em; }

.cend { text-align: center; }
.cend h2 { font-size: clamp(24px, 2.4vw, 36px); }
.cend p { margin-top: var(--s-3); color: var(--ink-2); }
.cend__btns { display: flex; flex-wrap: wrap; gap: var(--s-3); justify-content: center; margin-top: var(--s-5); }

/* --- the section index, grouped by direction ------------------------------ */
/* A row of directions. Sparse ones sit side by side rather than each taking a
   full-width heading and a row with holes in it; every direction keeps its own
   heading, spanning exactly the columns its cases occupy. The packing is done
   in tools/build-cases.py, which is where ROW_CAP has to match the 4 here. */
.crow {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(16px, 2vw, 30px) clamp(8px, .8vw, 12px);
  align-items: start;
}
.crow + .crow { margin-top: clamp(20px, 2.4vw, 34px); }
.cgroup--n1 { grid-column: span 1; }
.cgroup--n2 { grid-column: span 2; }
.cgroup--n3 { grid-column: span 3; }
.cgroup--n4 { grid-column: span 4; }
.cgroup--n1 .ccards { grid-template-columns: minmax(0, 1fr); }
.cgroup--n2 .ccards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cgroup--n3 .ccards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cgroup--n4 .ccards { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Below the row breakpoint every direction takes the full width and its cases
   flow two, then one, across — the packing stops mattering. */
@media (max-width: 1080px) {
  .crow { grid-template-columns: minmax(0, 1fr); }
  .cgroup--n1, .cgroup--n2, .cgroup--n3, .cgroup--n4 { grid-column: 1 / -1; }
  .cgroup--n1 .ccards, .cgroup--n2 .ccards,
  .cgroup--n3 .ccards, .cgroup--n4 .ccards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 560px) {
  .cgroup--n1 .ccards, .cgroup--n2 .ccards,
  .cgroup--n3 .ccards, .cgroup--n4 .ccards { grid-template-columns: minmax(0, 1fr); }
}

.cgroup__h {
  display: flex; align-items: baseline; gap: var(--s-2);
  margin-bottom: var(--s-3); padding-bottom: var(--s-2);
  border-bottom: 1px solid var(--line);
  font-size: clamp(15px, 1.1vw, 18px); letter-spacing: -.01em; line-height: 1.25;
}
.cgroup__n { font-family: var(--font-mono); font-size: var(--fs-2xs); color: var(--accent); }
.cgroup__count {
  margin-left: auto; font-family: var(--font-mono); font-size: var(--fs-2xs);
  color: var(--ink-3);
}
.cpage__client { margin-top: var(--s-3); font-size: var(--fs-sm); color: var(--ink-3); }
.cpage__dir {
  margin-top: var(--s-4); padding-top: var(--s-3); border-top: 1px solid var(--line);
  font-family: var(--font-mono); font-size: var(--fs-3xs);
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
/* How many cases sit behind a direction — a link into that group. */
.svc__count {
  position: absolute; top: var(--s-4); right: var(--s-4); z-index: 2;
  min-width: 22px; height: 22px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill);
  border: 1px solid var(--line); background: rgba(120, 170, 255, .06);
  font-family: var(--font-mono); font-size: var(--fs-3xs); color: var(--c, var(--accent));
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.svc__count:hover { border-color: var(--c); background: rgba(120, 170, 255, .12); }

/* --- a case, laid out the way the deck lays out a slide -------------------- */
.cpage__top {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: start; gap: var(--s-5) var(--s-7);
}
@media (max-width: 780px) { .cpage__top { grid-template-columns: minmax(0, 1fr); } }
/* The headline figure, where the deck puts it: top right of the slide. */
.cmetric { margin: 0; text-align: right; }
@media (max-width: 780px) { .cmetric { text-align: left; } }
.cmetric dt {
  font-family: var(--font-mono); font-size: var(--fs-3xs);
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3);
}
.cmetric__v {
  margin: 4px 0 0; font-size: clamp(20px, 2vw, 30px); font-weight: 660;
  letter-spacing: -.02em; color: var(--c); white-space: nowrap;
}
.cmetric__n { margin: 2px 0 0; font-size: var(--fs-2xs); color: var(--ink-3); }

.cpage__task {
  margin-top: var(--s-5); max-width: 76ch;
  font-size: var(--fs-lg); line-height: 1.5; color: var(--ink-2);
}
.cpage__task b { color: var(--c); font-weight: 600; }

.csub {
  margin-top: clamp(30px, 3.4vw, 48px); padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono); font-size: var(--fs-3xs); font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3);
}

/* The process, in the deck's order. */
.csteps {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px; margin-top: var(--s-4); counter-reset: none;
}
/* A step is a card you can open. The card face is a button — the whole face,
   so there is no small target to hunt for — and it controls a panel that takes
   the block underneath. */
.cstep { display: flex; }
.cstep__hit {
  flex: 1; display: flex; flex-direction: column; gap: var(--s-2);
  width: 100%; padding: var(--s-4);
  border: 1px solid var(--line); border-top: 2px solid var(--c);
  border-radius: var(--r-md);
  background: linear-gradient(160deg, var(--surface), rgba(10, 16, 32, .8));
  font: inherit; color: inherit; text-align: left; cursor: pointer;
  position: relative; overflow: hidden;
  transition: border-color var(--t-mid) var(--ease),
              transform var(--t-mid) var(--ease);
}
/* The sheen is a pseudo-element rather than a background transition so it can
   light from the card's own corner, which reads as a response to the pointer in
   a way a flat colour change does not. */
.cstep__hit::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(circle at 12% 0%,
              color-mix(in oklab, var(--c) 22%, transparent), transparent 60%);
  opacity: 0; transition: opacity var(--t-mid) var(--ease);
  pointer-events: none;
}
.cstep__hit:hover, .cstep__hit:focus-visible {
  border-color: var(--c); transform: translateY(-2px);
}
.cstep__hit:hover::after, .cstep__hit:focus-visible::after { opacity: 1; }
.cstep__hit:active { transform: translateY(0); }

.cstep__ico {
  display: block; width: 24px; height: 24px;
  color: var(--c); opacity: .85;
  transition: opacity var(--t-mid) var(--ease), transform var(--t-mid) var(--ease);
}
.cstep__hit:hover .cstep__ico { opacity: 1; transform: scale(1.08); }
/* No stroke-width here: each glyph carries its own, divided by the scale it is
   fitted with, so the whole set renders at one weight. See tools/icons.py. */
.ico { width: 100%; height: 100%; display: block; fill: none;
       stroke: currentColor;
       stroke-linecap: round; stroke-linejoin: round; }

.cstep__h { font-size: var(--fs-md); font-weight: 620; letter-spacing: -.01em; }
.cstep__t { font-size: var(--fs-xs); color: var(--ink-2); line-height: 1.5; }

/* --- opened --------------------------------------------------------------- */
/* An opened card takes the block, it does not push it around: the other cards
   step out of the flow and the opened one spans the row. JS pins the list to
   the height it had while closed, so nothing below moves. */
.csteps.has-open .cstep:not(.is-open) { display: none; }
.csteps.has-open { align-content: start; }

/* The opened card is the frame; the face gives up its own. */
.cstep.is-open {
  grid-column: 1 / -1; align-self: start; flex-direction: column;
  border: 1px solid var(--c); border-top: 2px solid var(--c);
  border-radius: var(--r-md);
  background: linear-gradient(160deg, var(--surface), rgba(10, 16, 32, .8));
  overflow: hidden;
}
/* A header row: glyph and title on one line, the way back at the end of it. The
   face no longer toggles anything — only the button closes the card — so it
   stops behaving like a target: no pointer, no lift, and no sheen, whose bottom
   edge was drawing a seam across the card right under the title. */
.cstep.is-open .cstep__hit {
  flex-direction: row; align-items: center; gap: var(--s-3);
  padding: var(--s-5) 132px var(--s-3) var(--s-5);
  border: 0; border-radius: 0; background: none;
  transform: none; cursor: default;
}
.cstep.is-open .cstep__hit::after,
.cstep.is-open .cstep__hit:hover::after { opacity: 0; }
.cstep.is-open .cstep__hit:hover { transform: none; }
.cstep.is-open .cstep__hit:hover .cstep__ico { transform: none; }
.cstep.is-open .cstep__ico { flex: 0 0 30px; width: 30px; height: 30px; opacity: 1; }
.cstep.is-open .cstep__h { font-size: clamp(19px, 1.7vw, 26px); letter-spacing: -.02em; }
.cstep.is-open .cstep__t { display: none; }

/* The reading column starts under the title, not under the glyph: the glyph
   sits in its own gutter and the text below lines up with the words above it. */
.cstep__panel { border: 0; background: none; }
.cstep__panel-in {
  padding: 0 var(--s-5) var(--s-5) calc(var(--s-5) + 30px + var(--s-3));
  animation: cstep-open .4s var(--ease-out) both;
}
.cstep__back {
  position: absolute; top: var(--s-5); right: var(--s-5); z-index: 1;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  border: 1px solid var(--line-strong); border-radius: 999px;
  background: rgba(9, 14, 26, .8);
  font: inherit; font-size: var(--fs-2xs); color: var(--ink-2);
  cursor: pointer;
  transition: border-color var(--t-mid) var(--ease), color var(--t-mid) var(--ease);
}
.cstep__back:hover, .cstep__back:focus-visible {
  border-color: var(--c); color: var(--ink);
}

/* --- the text in an opened card ------------------------------------------- */
.cstep__lede {
  margin: 0; max-width: 62ch;
  font-size: var(--fs-lg); line-height: 1.55; color: var(--ink);
}
.cstep__detail { margin: var(--s-4) 0 0; max-width: 72ch; }
.cstep__detail p {
  margin: 0 0 var(--s-3);
  font-size: var(--fs-sm); line-height: 1.7; color: var(--ink-2);
}
.cstep__detail p:last-child { margin-bottom: 0; }

/* Who sees what is a list, so it is set as one: the role in the text colour,
   its scope beside it, and a rule per row to keep four of them scannable. */
.cstep__roles { list-style: none; margin: 0; padding: 0; display: grid; }
.cstep__roles li {
  padding: var(--s-3) 0;
  border-top: 1px solid var(--line);
  font-size: var(--fs-sm); line-height: 1.65; color: var(--ink-2);
}
.cstep__roles li:last-child { padding-bottom: 0; }
.cstep__roles b { font-weight: 640; color: var(--ink); }

/* A list of operations, set as a list — the chips read as filters you could
   click, which these are not. */
.cstep__bullets {
  margin: 0 0 var(--s-4); padding-left: 1.15em;
  list-style: disc;
}
.cstep__bullets li {
  margin: 0 0 5px;
  font-size: var(--fs-sm); line-height: 1.65; color: var(--ink-2);
}
.cstep__bullets li:last-child { margin-bottom: 0; }
.cstep__bullets li::marker { color: var(--c); }

@media (max-width: 620px) {
  .cstep.is-open .cstep__hit { padding: 56px var(--s-4) var(--s-3); }
  .cstep__panel-in { padding: 0 var(--s-4) var(--s-4); }
  .cstep__back { top: var(--s-4); right: var(--s-4); }
}

@keyframes cstep-open { from { opacity: 0; transform: translateY(6px); } }

@media (prefers-reduced-motion: reduce) {
  .cstep__hit, .cstep__ico, .cstep__hit::after { transition: none; }
  .cstep__hit:hover { transform: none; }
  .cstep__panel-in { animation: none; }
}

/* The highlighted band the deck runs under a diagram. */
.cstrip {
  margin-top: var(--s-4); padding: var(--s-4);
  border: 1px dashed var(--line-strong); border-radius: var(--r-md);
  background: rgba(120, 170, 255, .04);
  font-size: var(--fs-sm); line-height: 1.55; color: var(--ink-2);
}

.cchs {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-5) var(--s-7); margin-top: var(--s-4);
}
@media (max-width: 780px) { .cchs { grid-template-columns: minmax(0, 1fr); } }
.cch h3 { font-size: var(--fs-md); letter-spacing: -.01em; }
.cch p { margin-top: 6px; font-size: var(--fs-sm); line-height: 1.55; color: var(--ink-2); }

.couts {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-5) var(--s-7); margin-top: var(--s-5);
}
@media (max-width: 780px) { .couts { grid-template-columns: minmax(0, 1fr); } }
.cout h3 { font-size: var(--fs-md); letter-spacing: -.01em; color: var(--c); }
.cout p { margin-top: 6px; font-size: var(--fs-sm); line-height: 1.55; color: var(--ink-2); }

.cstack {
  margin-top: var(--s-4);
  font-family: var(--font-mono); font-size: var(--fs-xs); line-height: 1.7; color: var(--ink-2);
}
.ccard__task { color: var(--c); font-weight: 600; }

/* --- client marks ---------------------------------------------------------- */
/* Marks stand in for client names wherever those names appear — the landing's
   tiles, the case index, a case headline and its byline — so they live here,
   in the stylesheet every page loads.

   They keep their own colours: Alfa-Bank red, Sportmaster's red accent, the
   Beeline bee yellow. Nothing here recolours anything. The three lockups that
   ship black on transparent were swapped for their makers' dark-ground variant
   by tools/brand-marks.py, which repaints the black and leaves every other hue
   alone — so what renders is each brand's own logo, not a silhouette of it.

   Each mark carries its own height and baseline shift: a wordmark and a
   wordmark-with-badge do not sit the same way against one cap height. The
   numbers are the ones tuned for the portfolio deck, which uses these files. */
.bmark {
  --bms: 1em;                      /* the size the context sets the marks at */
  display: inline-block;
  height: calc(var(--bmh, 1) * var(--bms));
  width: auto;
  vertical-align: var(--bmv, -.12em);
}

/* Two numbers per mark, both derived rather than guessed — the tool that
   produces them and the reasoning behind each are in tools/metrology/.
   --bmh sizes the box so the mark's letters come out at the same optical size
   as the type around them; --bmv drops the box by the empty space under the
   mark so its baseline lands on the text's baseline. The baseline is taken as
   the median row where the mark's columns end, so a descender or a round
   overshoot cannot drag the whole lockup upward. */
.bmark--beeline       { --bmh: 0.896; --bmv: -0.108em; }
.bmark--alfabank      { --bmh: 1.058; --bmv: -0.344em; }
.bmark--sportmaster   { --bmh: 1.126; --bmv: -0.270em; }
.bmark--yandex-market { --bmh: 1.001; --bmv: -0.158em; }
.bmark--wildberries   { --bmh: 0.776; --bmv: -0.033em; }
.bmark--x5            { --bmh: 0.780; --bmv: -0.043em; }
.bmark--lamoda        { --bmh: 0.782; --bmv: -0.100em; }

/* In the byline the marks sit at the size of the type around them, held back a
   little so the row does not shout past the headline. */
.cpage__client .bmark { --bms: 1.1em; opacity: .82; }
