/* Grizzly Beam — HOME (homepage): dark-zone · banner · about · mq · stats · pj · sv · reveal-stage */

/* ---------- Dark zone + canvas ---------- */
/* Navy dark surface (brand book) — chosen 2026-07-27 via /bg-lab/.
   Note: .banner and .about use mix-blend-mode: difference, so this color
   also determines the heading color (|navy - #ECE8E1| = ~#D4BEA1). */
.dark-zone { position: relative; background: var(--navy); }
.gl-wrap { position: absolute; inset: 0; pointer-events: none; }
.gl-wrap canvas { position: sticky; top: 0; width: 100%; height: 100vh; display: block; }
.blend { position: relative; z-index: 2; mix-blend-mode: difference; }

/* ---------- Banner ---------- */
.banner { min-height: 100vh; display: flex; }
.banner__ctr { display: flex; flex-direction: column; justify-content: space-between; padding-top: 9.4rem; padding-bottom: 3.5rem; }
.banner__title {
  font-size: 6.25rem;                               /* 80px */
  line-height: 0.9; letter-spacing: -0.01em; font-weight: var(--w-display);   /* brand: Display/H1 */
  color: var(--tx-l);
}
.banner__word-slot { display: inline-block; overflow: visible; min-width: 6ch; }
.banner__word { display: inline-block; will-change: filter, opacity; }
.banner__cta { margin-top: 2.2rem; }
.banner__bottom { display: grid; grid-template-columns: 1fr auto; align-items: end; gap: 2rem; }
.banner__circle {
  width: 2.6rem; height: 2.6rem; border: 1px solid rgba(236, 232, 225, 0.4);
  border-radius: var(--r-10); display: grid; place-items: center; opacity: 0.7;
}
.banner__circle svg { width: 1.25rem; height: 1.25rem; }   /* §08: 16px inline */
.banner__meta { display: flex; flex-direction: column; align-items: end; gap: 1.4rem; }
.banner__desc { font-family: var(--f-body); font-size: 1.266rem; line-height: 1.45; max-width: 18.3rem; text-align: left; }

/* ---------- About ---------- */
.about { min-height: 100vh; display: flex; align-items: center; padding-block: 8rem; }
.about__eyebrow { position: absolute; left: 2.8125rem; }
.about__statement {
  font-size: 6.25rem; line-height: 1.02; letter-spacing: -0.01em; font-weight: var(--w-display);   /* brand: Display/H1 */
  color: var(--tx-l);
  max-width: 90rem; margin: 0 auto; padding-left: 9rem; text-indent: 0;
}
.about__statement .w { display: inline-block; opacity: 0.25; transition: opacity 0.4s ease; }
.about__statement .w.lit { opacity: 1; }
.about__line { position: relative; height: 1px; background: rgba(236, 232, 225, 0.25); margin: 4.5rem 9rem 0; }
.about__plus { position: absolute; right: 8rem; top: -0.8rem; font-size: 1.5rem; opacity: 0.7; }
.about__grid { display: grid; grid-template-columns: 1fr 1fr; margin-top: 4rem; padding-left: 9rem; gap: 2rem; }
.about__col-r { max-width: 28rem; justify-self: end; display: flex; flex-direction: column; gap: 2.2rem; }
/* The left column (three-line label) was removed on 2026-09-21; the right column keeps
   its place in the second track instead of sliding into the first. */
.about__col-r { grid-column: 2; }

/* ---------- Marquee ---------- */
.mq { position: relative; height: 100vh; overflow: clip; display: flex; flex-direction: column; justify-content: space-between; padding-block: 8.5rem 3rem; }
.mq__fade { position: absolute; inset: 0; background: var(--stone2); opacity: 0; z-index: 1; }
.mq__top { position: relative; z-index: 3; }
.mq__band { position: relative; z-index: 2; overflow: visible; white-space: nowrap; }
.mq__track { display: inline-flex; will-change: transform; }
.mq__item {
  font-size: 10.31rem;                              /* 132px */
  line-height: 1; letter-spacing: -0.01em; font-weight: var(--w-display);   /* brand: Display/H1 · §02 sentence case */
  color: var(--tx-l); padding-right: 0.3em;
}
.mq__item b { font-weight: var(--w-display); padding-inline: 0.22em; opacity: 0.9; }
.mq__item, .mq__top .label { transition: color 0.5s ease; }
.mq.past .mq__item { color: var(--ink); }
.mq.past .mq__top .label { color: var(--tx-g); }

/* ---------- Stats (light A) ---------- */
.stats {
  background: linear-gradient(0deg, var(--paper) 0%, var(--stone2) 100%);
  color: var(--ink);
  padding-block: 6.5rem 7.5rem;
}
.stats__grid { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 6rem; align-items: stretch; }
.stats__right { display: flex; flex-direction: column; justify-content: center; }
/* Was rgba(236,232,225,0.65), i.e. a color meant for a DARK background in a light
   section - ratio 1.00, the element blended into the background. */
.stats__eyebrow { display: block; color: var(--tx-g); margin-bottom: 2.4rem; }
.stat { border-top: 1px solid rgba(22, 24, 28, 0.35); padding-top: 1.2rem; }
.stat + .stat { margin-top: 2.4rem; }
.stat__clip { overflow: hidden; }
.stat__num {
  display: inline-block; font-size: 10rem; line-height: 0.9;
  letter-spacing: -0.01em; font-weight: var(--w-display); color: var(--ink);   /* brand: Display/H1 */
}
.stat__num sup { font-size: 0.42em; vertical-align: 0.9em; letter-spacing: 0; }
.stat__desc {
  margin-top: 1.1rem; max-width: 30rem;
  font-family: var(--f-body); font-size: 1.266rem; font-weight: var(--w-body-strong);
  line-height: 1.35; color: var(--ink);
}
.stats__cols { display: grid; grid-template-columns: 1fr 1fr; gap: 2.4rem; padding-top: 0.4rem; }
.stats__col p { color: var(--tx-g); font-size: 1.1rem; line-height: 1.55; }
.stats__col p + p { margin-top: 1.4rem; }
.partners { margin-top: 5.5rem; }
/* opacity: 0.55 produced rgb(157,152,144), ratio 2.36 - AA fail. */
.partners__title { color: var(--tx-g); }
/* Partner logos: five of them on a six-track grid, two tracks per cell, so the first
   row holds three and the second row holds two, centered under it (the fourth cell
   starts on track 2). Thin rules inherit the tone of the old separators. All logos are monochrome, in the text tone: the original colors
   (attic42 orange, CEX teal) would compete with the amber CTA. Height is set per
   logo via --lh, so they share the same optical weight, not the same height. */
.partners__grid {
  list-style: none; margin-top: 2.4rem;
  display: grid; grid-template-columns: repeat(6, 1fr);
  border-top: 1px solid rgba(92, 86, 78, 0.25);
}
.partners__cell {
  display: flex; align-items: center; justify-content: center;
  height: 8.4rem; padding-inline: 1.2rem;
  grid-column: span 2;
  border-bottom: 1px solid rgba(92, 86, 78, 0.25);
}
.partners__cell:nth-child(4) { grid-column: 2 / span 2; }
.partners__cell:not(:nth-child(3n)):not(:last-child) { border-right: 1px solid rgba(92, 86, 78, 0.25); }
.partners__logo {
  display: block; height: var(--lh, 2.2rem); width: auto; max-width: 100%;
  object-fit: contain; filter: brightness(0); opacity: 0.72;
}
@media (max-width: 599px) {
  .partners__grid { grid-template-columns: repeat(2, 1fr); }
  .partners__cell, .partners__cell:nth-child(4) { grid-column: auto; height: 7.6rem; }
  .partners__cell:not(:nth-child(3n)):not(:last-child) { border-right: 0; }
  .partners__cell:nth-child(odd):not(:last-child) { border-right: 1px solid rgba(92, 86, 78, 0.25); }
  .partners__cell:last-child { grid-column: 1 / -1; }
}
html.has-js .stat__num { transform: translateY(110%); }

/* ---------- Projects pin ---------- */
.pj { position: relative; background: linear-gradient(0deg, var(--stone3) 0%, var(--paper) 55%); }
.pj__sticky { position: sticky; top: 0; height: 100vh; overflow: clip; }
/* Projects section heading. INVISIBLE for now, but present in the
   accessibility tree and in the outline (clip technique, not display:none).
   Why it is not visible: the cards are 628px tall at 1440 and already fill
   short laptop screens without a label. Measured with the label at top: 9rem:
     1440x720   overlap 88px      1366x657   bottom clipped 48px
     1440x800   overlap 48px      1440x740   bottom clipped 27px
     1440x900   gap 2px           1536x730   bottom clipped 32px
   Reserving space via .pj__gallery padding-top fixes 900+
   but clips the cards on all three real laptops above. A visible label requires
   the cards to become viewport-height aware, which is a design decision.
   Once that is resolved, this goes here:
     position: absolute; top: 9rem; left: 2.8125rem; color: var(--tx-g); */
.pj__eyebrow {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
.pj__gallery {
  position: absolute; inset: 0;
  display: flex; align-items: center; gap: 6rem;
  padding-left: 55vw; will-change: transform;
}
.pj__card { flex: 0 0 auto; display: flex; flex-direction: column; gap: 1.4rem; }
.pj__card--lg .pj__media { width: 66rem; }
.pj__card--md .pj__media { width: 51rem; }
.pj__card--drop { transform: translateY(6rem); }
.pj__card--rise { transform: translateY(-3rem); }
.pj__media { position: relative; border-radius: var(--r-10); overflow: hidden; background: #16181C; }
/* The mockups are 1536x1024, so 3/2 crops nothing and holds the height before loading. */
.pj__media { aspect-ratio: 3 / 2; }
.pj__media picture { display: contents; }
.pj__shot { width: 100%; height: 100%; object-fit: cover; display: block; }
.pj__n {
  position: absolute; left: 1.1rem; top: 0.9rem;
  font-family: var(--f-mono); font-size: 0.78rem; letter-spacing: 0.18em;
  color: rgba(236, 232, 225, 0.85);
  background: rgba(18, 19, 23, 0.55); padding: 0.24rem 0.5rem;
  border-radius: var(--r-6);
}
.pj__media.is-missing .pj__shot { display: none; }
.pj__meta { display: grid; grid-template-columns: auto 1fr auto; align-items: start; gap: 2rem; color: var(--ink); }
.pj__name { font-size: 2.53rem; line-height: 1; letter-spacing: -0.005em; font-weight: var(--w-h2); }   /* brand: H2 */
.pj__kind {
  font-family: var(--f-mono); font-size: 0.8rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--tx-g); margin-bottom: 0.6rem;
}
.pj__kind-a { color: var(--ink); font-weight: 600; }
.pj__sep { margin-inline: 0.5em; }
.pj__desc { color: var(--tx-g); max-width: 26rem; }
.pj__endcap { flex: 0 0 auto; width: 34rem; color: var(--ink); display: flex; flex-direction: column; gap: 2.5rem; }
.pj__endcap-text { font-size: 2.1rem; line-height: 1.25; letter-spacing: 0; }   /* brand: H3 */

/* ---------- Services (no pin) ----------
   Was: .sv — a full-screen scene over the gallery, in the same pin, with word
   stacking and sequential details. Now a list of rows over an animated SVG backdrop
   (block below). The rows use the same hairline language as .wpa__list and .stat. */
.hs { position: relative; background: var(--ink); color: var(--tx-l); padding-block: 7rem 6.5rem; overflow: clip; }
/* ---------- Backdrop: beams at the angle of the mark ----------
   Was: a showreel video (7.4 MB, every frame decoded) under a 0.93 overlay.
   The overlay had to be that heavy because the showreel recorded Serbian-language
   sites, so their text showed through beneath the English copy. When a backdrop
   has to be dimmed by 93% to stay out of the way, it is no longer a backdrop but a cost.

   Now: inline SVG, zero requests and no decoding. Seventeen beams at
   24 degrees — the slope is measured from the mark itself (it matches the rotate(24)
   already present in the work card SVGs). Colors are from the brand book: bone at 0.04-0.085
   and Beam Amber at 0.16, and only on two beams out of seventeen.

   Only three things move: two beam layers and the glow. Only transform and
   opacity are animated, with no JS and no rAF loop. The layers slide along their length
   (translateY is inside the rotated parent), so you don't see the beams traveling
   but the light moving through them. Two different speeds create parallax.
   `alternate` is the same pattern .svc-plus already uses on the service pages. */
/* The beam backdrop was moved to core.css — the Book a call modal uses the same one,
   and it runs on every page, while home.css is loaded only on the homepage. */

.hs__inner { position: relative; z-index: 1; }
.hs__eyebrow { display: block; color: rgba(236, 232, 225, 0.65); }
.hs__list { margin-top: 3.2rem; border-top: 1px solid rgba(236, 232, 225, 0.16); }
.hsi {
  display: grid; grid-template-columns: 3.4rem minmax(0, 20rem) minmax(0, 1fr) 6.3rem;
  gap: 2.6rem; align-items: start;
  padding-block: 2.5rem;
  border-bottom: 1px solid rgba(236, 232, 225, 0.16);
}
.hsi__n { color: rgba(236, 232, 225, 0.5); padding-top: 0.55rem; }
.hsi__title { font-size: 2.53rem; line-height: 1.05; letter-spacing: -0.005em; font-weight: var(--w-h2); }   /* brand: H2 */
.hsi__body { color: rgba(236, 232, 225, 0.72); max-width: 38rem; padding-top: 0.35rem; }
.hsi__glyph { width: 6.3rem; opacity: 0.5; justify-self: end; }
.hsi__glyph svg { width: 100%; height: auto; display: block; }
.hs__foot { display: flex; justify-content: space-between; align-items: center; gap: 2rem; margin-top: 3.4rem; }

/* ---------- Web in practice + testimonial ---------- */
/* Reveal stage: audit (light) → FAQ (dark), in-place crossfade during the pin */
.reveal-stage { position: relative; }
.rs__sticky { position: relative; }
.rs__layer { display: flex; align-items: center; padding-block: 6rem; }
.rs__layer > .ctr { width: 100%; }
.rs__layer--audit { background: linear-gradient(0deg, var(--stone3) 0%, var(--paper) 100%); color: var(--ink); }
.rs__layer--faq { background: var(--ink); color: var(--tx-l); }
.rs__layer--tst { background: var(--paper); color: var(--ink); }
html.has-js .rs__sticky { height: 100vh; overflow: clip; }
html.has-js .rs__layer { position: absolute; inset: 0; padding-block: 0; }
html.has-js .rs__layer--faq, html.has-js .rs__layer--tst { opacity: 0; visibility: hidden; }
html.has-js .rs__layer--tst .tst { padding-block: 0; }

/* ---------- Responsive ---------- */
@media (max-width: 1023px) {
  .hsi { grid-template-columns: 3rem minmax(0, 16rem) minmax(0, 1fr); gap: 2rem; }
  .hsi__glyph { display: none; }
  .stats__grid { grid-template-columns: 1fr; gap: 4rem; }
  .stat__num { font-size: 7.6rem; }
  .stats__cols { grid-template-columns: 1fr; }

  /* The card is tied to the viewport, not to a fixed 66rem/51rem. Without this
     .pj__meta stays a grid 'auto 1fr auto' and stretches the card beyond the screen
     width (786px @390, 792px @768), so no card is fully visible
     at any scroll position; .pj__sticky has overflow: clip, so the
     clipping happens silently. 78vw leaves a peek of the next card.
     At 1023, 78vw = 798px, practically equal to the natural 792px, so the breakpoint
     causes no jump. */
  .pj__card { width: 78vw; }
  .pj__card--lg .pj__media, .pj__card--md .pj__media { width: 100%; }
  .pj__meta { grid-template-columns: 1fr; gap: 1rem; }
  .pj__desc { max-width: none; }
  .pj__endcap { width: 78vw; }
  .pj__gallery { gap: 3rem; padding-left: 12vw; }

  /* Marquee: below 1024 only 32-50% of the phrase is visible (measured on staging:
     390px = 32%, 768px = 38%, 1023px = 50%; at 1440 it is 67%, at 1920 89%).
     A band slowly moving through such a small slice doesn't read as an effect
     but as a bug, so below this breakpoint the words stack one under another and
     don't move. The pin and drift are disabled by gsap.matchMedia in home.js.
     This also removes the empty strip between the label and the band: the column now
     fills the middle of the section. */
  /* Without a moving band, a full 100vh left about 400px of dead
     space around the column (measured at 390x844: a 227px column in an 844px section),
     and min-height: 70vh still gave 63px above versus 198px below.
     The height now actually follows the content: symmetric padding, a fixed gap
     below the label, no space-between pushing the column to the bottom. */
  .mq { height: auto; padding-block: 6rem; justify-content: flex-start; }
  /* The band is intentionally full-bleed while it scrolls; the static column must align
     with the label above, so it gets the same padding as .ctr (2.8125rem). */
  .mq__band { display: block; white-space: normal; padding-inline: 2.8125rem; margin-top: 4rem; }
  .mq__track { display: block; width: 100%; transform: none !important; }
  .mq__item + .mq__item { display: none; }   /* the clone only serves the infinite band */
  /* font-size: 0 drops the spaces and &nbsp; between words, which would otherwise,
     as anonymous inline boxes, create empty lines in the column. */
  .mq__item { display: block; padding-right: 0; font-size: 0; }
  .mq__item b { display: none; }             /* the dots are separators of the horizontal band */
  .mq__w { display: block; font-size: min(6rem, 14vw); line-height: 1.04; }
}
@media (max-width: 767px) {
  .hs { padding-block: 5rem 4.5rem; }
  .hsbg__mark { width: 96%; height: 34%; right: -10%; opacity: 0.05; }
  .hsi { grid-template-columns: 2.6rem minmax(0, 1fr); gap: 1rem 1.6rem; padding-block: 2rem; }
  .hsi__title { font-size: 1.85rem; }
  .hsi__body { grid-column: 2; padding-top: 0.6rem; }
  .hs__foot { flex-direction: column; align-items: flex-start; gap: 1.4rem; }
  .banner__title { font-size: 3.75rem; line-height: 0.93; letter-spacing: -0.01em; }   /* brand: Display/H1 */
  /* .about__eyebrow is position: absolute without top, so on desktop it sits
     left of the text thanks to padding-left: 9rem on .about__statement.
     Here that padding is removed, the text lands at x=34 - exactly where the eyebrow is,
     both at T=42 - and they overlap over the full height (17px). So on mobile
     the eyebrow goes back into the flow, above the heading. */
  .about__eyebrow { position: static; display: block; margin-bottom: 1.8rem; }
  .about__statement { font-size: 3.4rem; padding-left: 0; }
  .about__grid { grid-template-columns: 1fr; padding-left: 0; }
  .about__col-r { grid-column: auto; }
  .about__line { margin-inline: 0; }
  .banner__bottom { grid-template-columns: 1fr; gap: 2.6rem; }
  .banner__meta { align-items: flex-start; }
  /* At 767 the band goes to 6rem; in the column the size is carried by .mq__w, and .mq__item
     must stay at 0 so the &nbsp; between words doesn't create an empty line. */
  .mq__item { font-size: 0; }
  html.has-js .rs__sticky { height: auto; overflow: visible; }
  html.has-js .rs__layer { position: static; opacity: 1 !important; visibility: visible !important; padding-block: 6rem; }
  html.has-js .rs__layer--tst .tst { padding-block: 2rem 0; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .hsbg__glow, .hsbg__layer--a, .hsbg__layer--b, .hsbg__beam { animation: none; }
  html.has-js .stat__num { transform: none !important; }
  html.has-js .rs__sticky { height: auto !important; overflow: visible !important; }
  html.has-js .rs__layer { position: static !important; opacity: 1 !important; visibility: visible !important; padding-block: 6rem !important; }
  .mq__fade { opacity: 1; }
  .about__statement .w { opacity: 1; }
  .gl-wrap { display: none; }
}

