/*
Theme Name: AffiNinja
Theme URI: https://affininja.com
Author: AffiNinja
Description: Stealth Kinetic — elite iGaming affiliate network theme. Technical brutalism, sharp geometry, kinetic yellow accents. Every section editable from the AffiNinja dashboard.
Version: 1.0.0
Requires at least: 6.0
Tested up to: 6.7
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: affininja
Tags: igaming, affiliate, dark, one-page, custom-colors
*/


/* ==========================================================================
   Tokens
   ========================================================================== */
:root{
  --accent:#FEE440;
  --bg:#0D0E12;
  --deep:#07080B;
  --surface:#15161B;
  --charcoal:#0D0E12;
  --text:#FFFFFF;
  --text-dim:rgba(255,255,255,.62);
  --light:#F4F3EE;
  --grey:#E7E6E0;
  --ink:#0D0E12;
  --ink-dim:rgba(13,14,18,.62);
  --border:rgba(255,255,255,.14);

  --font-display:'Syne',system-ui,-apple-system,'Segoe UI',sans-serif;
  --font-body:'Inter',system-ui,-apple-system,'Segoe UI',sans-serif;

  --shell:min(1560px,90vw);
  --gutter-x:20px;
  --gutter-x-lg:48px;
  --section-y:clamp(80px,11vw,168px);
  --header-h:84px;

  /* Bold geometry */
  --r-pill:999px;
  --r-card:28px;
  --r-sm:16px;

  /* Display scale */
  --fs-mega:clamp(40px,7.6vw,178px);
  --fs-display:clamp(38px,7.2vw,104px);
  --fs-h3:clamp(22px,2.4vw,34px);
  --fs-body:clamp(18px,1.45vw,27px);   /* running text, everywhere */
  /* Header type: same scale as body copy but capped at 24px, because uppercase
     bold reads larger than lowercase regular at identical size. Still shrinks
     with --fs-body on narrower screens. */
  --fs-header:min(var(--fs-body),24px);
  --head-gap:clamp(18px,2vw,34px);     /* section head -> its intro copy */

  --marquee-dur:30s;
  /* Hero figure geometry. On :root, not .hero, so the section below can size its
     clearance from the same token instead of guessing. */
  --fs-hero:min(var(--fs-mega),13svh);
  --art-h:min(clamp(340px,32vw,760px),58svh);
  /* How far the figure rises into the headline. The last line's box is
     0.84em (line-height), so .78 buried almost all of it. .40 puts the head's
     top at roughly the line's midpoint, leaving the upper half of the type
     readable behind it at every scale. */
  --art-overlap:calc(var(--fs-hero) * .40);
  --art-drop:clamp(64px,5vw,118px);
  --tape-drop:calc(var(--art-drop) * .52);
  --tape-h:min(clamp(150px,13.5vw,300px),26svh);
  --band-h:min(clamp(72px,6.6vw,148px),13svh);  /* explicit: the hem is derived from it */
  --tilt:3.8deg;                    /* the tape angle, mirrored per band */
  --ease:cubic-bezier(.22,1,.36,1);
}
@media (min-width:768px){ :root{ --gutter-x:var(--gutter-x-lg); } }

/* ==========================================================================
   Reset
   ========================================================================== */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{
  scroll-behavior:smooth;scroll-padding-top:var(--header-h);-webkit-text-size-adjust:100%;
  /* iOS rubber-band overscroll shows the root background past the last section.
     Match it to the footer so a pull past the end reads as more footer, not a
     different-coloured band — and stop the bounce where the browser allows it. */
  background:var(--deep);
  overscroll-behavior-y:none;
}
body{
  background:var(--bg);color:var(--text);
  font-family:var(--font-body);font-size:17px;line-height:1.6;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  overflow-x:clip;
}
img{max-width:100%;height:auto;display:block}
a{color:inherit;text-decoration:none}
button,input,select,textarea{font:inherit;color:inherit}
button{background:none;border:0;cursor:pointer}
ul,ol{list-style:none}
h1,h2,h3,h4{
  font-family:var(--font-display);font-weight:800;
  line-height:.88;letter-spacing:-.04em;text-transform:uppercase;
}
::selection{background:var(--accent);color:var(--ink)}
:where(a,button,input,select,textarea):focus-visible{outline:3px solid var(--accent);outline-offset:3px}

.skip-link{position:absolute;left:-9999px;top:0;z-index:300;
  background:var(--accent);color:var(--ink);padding:14px 22px;font-weight:700;border-radius:0 0 var(--r-sm) 0}
.skip-link:focus{left:0}

::-webkit-scrollbar{width:10px}
::-webkit-scrollbar-track{background:var(--deep)}
::-webkit-scrollbar-thumb{background:var(--accent);border-radius:var(--r-pill)}

.material-symbols-outlined{font-variation-settings:'FILL' 0,'wght' 300,'GRAD' 0,'opsz' 24;line-height:1;user-select:none}

/* ==========================================================================
   Layout
   ========================================================================== */
.shell{width:100%;max-width:var(--shell);margin-inline:auto;padding-inline:var(--gutter-x)}
.shell--narrow{max-width:860px}
.site-main{display:block;overflow-x:clip}

/* ==========================================================================
   Sticker accents — original geometric marks, purely decorative
   ========================================================================== */

/* ==========================================================================
   Buttons
   ========================================================================== */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:12px;
  padding:16px 30px;border:2px solid transparent;border-radius:var(--r-pill);
  font-family:var(--font-display);font-size:15px;font-weight:800;
  letter-spacing:.04em;text-transform:uppercase;white-space:nowrap;
  transition:background .3s var(--ease),color .3s var(--ease),
             border-color .3s var(--ease),transform .3s var(--ease);
}
.btn--lg{padding:20px 40px;font-size:17px}
.btn--accent{background:var(--accent);color:var(--ink);border-color:var(--accent)}
.btn--accent:hover{background:var(--ink);color:var(--accent);border-color:var(--ink)}
.btn--ghost{border-color:currentColor;color:inherit}
.btn--ghost:hover{background:var(--accent);color:var(--ink);border-color:var(--accent)}
.btn[disabled]{opacity:.5;pointer-events:none}

/* circular arrow badge inside buttons */
.btn__arrow{
  display:inline-grid;place-items:center;width:1.85em;height:1.85em;
  border-radius:50%;background:var(--ink);color:var(--accent);
  font-size:.72em;line-height:1;flex:none;
  transition:transform .4s var(--ease),background .3s,color .3s;
}
.btn--accent:hover .btn__arrow{background:var(--accent);color:var(--ink);transform:rotate(45deg)}
.btn--ghost .btn__arrow{background:currentColor;color:var(--bg)}

.btn__spinner{
  width:16px;height:16px;border:2px solid currentColor;border-right-color:transparent;
  border-radius:50%;animation:aff-spin .7s linear infinite;
}
@keyframes aff-spin{to{transform:rotate(360deg)}}

/* Standalone arrow badge (cards, list rows) */
.arrow-badge{
  display:grid;place-items:center;flex:none;
  width:clamp(44px,4vw,58px);aspect-ratio:1;border-radius:50%;
  background:var(--accent);color:var(--ink);font-size:20px;
  transition:transform .45s var(--ease),background .3s var(--ease),color .3s;
}

/* ==========================================================================
   Header
   ========================================================================== */
.site-header{
  position:fixed;inset:0 0 auto;z-index:100;height:var(--header-h);
  display:flex;align-items:center;isolation:isolate;
  background:transparent;
}
/* Full-width accent bar, on by default. Lives on ::before at z-index:-1 inside
   the header's own isolation context, so it paints behind the logo/nav/CTA but
   never behind the page. */
.site-header::before{
  /* Extends 100vh ABOVE the header. iOS Safari draws its status bar and URL pill
     as translucent chrome over the page, and content scrolling past the header
     showed through it. The yellow now fills that region, so the chrome tints
     yellow instead of flashing whatever card is scrolling underneath. Off-screen
     and invisible everywhere else. */
  content:"";position:absolute;inset:-100vh 0 0 0;z-index:-1;
  background:var(--accent);border-bottom:3px solid var(--ink);
}
/* Header contents are inked for the yellow bar. */
.site-header__cta{background:var(--ink);color:var(--accent);border-color:var(--ink)}
.site-header__cta:hover{background:#fff;color:var(--ink);border-color:#fff}
.site-header__cta .btn__arrow{background:var(--accent);color:var(--ink)}
.site-header__inner{
  display:flex;align-items:center;justify-content:space-between;gap:20px;
  width:100%;
}
.brand{display:inline-flex;align-items:center;flex:none}
.brand img{max-height:32px;width:auto}
.brand__text{
  font-family:var(--font-display);font-weight:800;
  font-size:calc(var(--fs-header) * 1.2);
  letter-spacing:-.04em;color:var(--ink);text-transform:uppercase;
}

/* nav is bare type — no plate, no blur */
.nav{display:none;align-items:center;gap:clamp(16px,1.9vw,36px)}
@media (min-width:980px){ .nav{display:flex} }
/* Header text now runs at --fs-body, so between the nav breakpoint and ~1300px
   the bar gets tight. Pull the gaps and button padding in rather than shrinking
   the type back down. */
@media (min-width:980px) and (max-width:1300px){
  .nav{gap:14px}
  .site-header__actions{gap:10px}
  .site-header__cta,.site-header__login{padding-inline:16px}
}
.nav__link{
  position:relative;padding:6px 0;
  /* Same px as body copy (cap heights measure within 0.3px). The nav only read
     larger because of weight 700 + uppercase + tracking, so the weight comes
     down rather than the size — shrinking it would make it genuinely smaller. */
  font-family:var(--font-display);font-size:var(--fs-header);font-weight:500;
  letter-spacing:.01em;text-transform:uppercase;color:var(--ink);
  transition:opacity .3s var(--ease);
}
.nav__link::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:2px;
  background:currentColor;transform:scaleX(0);transform-origin:left;
  transition:transform .35s var(--ease);
}
.nav__link:hover::after,.nav__link.is-active::after{transform:scaleX(1)}
.nav__link:hover,.nav__link.is-active{opacity:.62}

.site-header__actions{display:flex;align-items:center;gap:12px;flex:none}
.site-header__cta{padding:13px 24px;font-size:var(--fs-header)}
/* Both CTAs stay visible on mobile — with only four sections there is no
   hamburger, so these are the header's whole job there. */
@media (max-width:600px){
  .site-header__actions{gap:8px}
  .site-header__cta,.site-header__login{padding:11px 14px;font-size:12px;letter-spacing:.02em}
}

/* Secondary CTA: outlined against the yellow bar so JOIN DOJO stays primary. */
.site-header__login{
  padding:13px 22px;font-size:var(--fs-header);
  background:transparent;color:var(--ink);border:2px solid var(--ink);
}
.site-header__login:hover{background:var(--ink);color:var(--accent)}

@media (max-width:979px){
  .nav{
    position:fixed;inset:calc(var(--header-h) - 4px) var(--gutter-x) auto;
    display:flex;flex-direction:column;align-items:stretch;gap:4px;padding:10px;
    background:var(--surface);border-radius:var(--r-card);
    transform:translateY(-12px) scale(.98);opacity:0;visibility:hidden;
    transition:opacity .3s var(--ease),transform .3s var(--ease),visibility .3s;
  }
  .nav.is-open{transform:none;opacity:1;visibility:visible}
  .nav__link{padding:16px 20px;font-size:18px}
}

/* ==========================================================================
   Hero — mega type
   ========================================================================== */
.hero{
  position:relative;display:block;
  /* Top gap mirrors the gap under the headline: artH - overlap - drop
     + tapeDrop - tapeH/2 - bandH/2. Measured from the hero's OWN top edge, not
     from below the header — the header is fixed and floats over the hero, so
     adding --header-h on top of the matched gap pushed the headline a full
     header-height past centre.
     Capped at 280px: past ~1800px wide the figure is big enough that mirroring
     its footprint above the headline stops reading as balance and starts
     reading as dead space. Below that the cap never binds. */
  padding-block:min(
      calc(
        var(--art-h) - var(--art-overlap) - var(--art-drop)
        + var(--tape-drop) - (var(--tape-h) / 2) - (var(--band-h) / 2)
      ),
      280px
    ) 0;
  background-color:var(--deep);background-size:cover;background-position:center 78%;
  background-repeat:no-repeat;
  /* NOT clipped: the figure and the tape X deliberately hang into the section
     below. Horizontal containment is handled per-element with clip-path. */
  overflow:visible;z-index:3;
  /* x only. WebKit doesn't reliably carry body{overflow-x:clip} up to the
     viewport, so the half-cropped lanterns and the rotated hem/tape widened the
     page on iOS. clip (not hidden) keeps the vertical overhang intact. */
  overflow-x:clip;
}
/* The art is already near-black, so the veil only seats the headline under the
   header. No bottom wash: that was a solid black bar over the lower third,
   which is exactly where the stone path is — it erased the brickwork. The tape
   and hem already handle the transition into the next section. */
.hero__veil{position:absolute;inset:0;pointer-events:none;z-index:1;
  /* Only seats the headline under the header now. The edge vignette is gone —
     the artwork already carries its own falloff, and layering a second one on
     top was crushing the paving at the sides. */
  opacity:.72;   /* was injected from the removed Overlay Strength setting */
  background:linear-gradient(180deg,color-mix(in srgb,var(--deep) 62%,transparent) 0%,transparent 22%);
}
.hero__inner{
  position:relative;z-index:4;
  display:flex;flex-direction:column;align-items:center;
  text-align:center;
}

.hero__title{
  position:relative;z-index:1;
  font-size:var(--fs-hero);line-height:.84;letter-spacing:-.045em;
  margin-bottom:0;
}
.hero__title-a,.hero__title-b{display:block}
.hero__title-a{color:#fff}
.hero__title-b{color:var(--accent)}

/* In flow, between two negative margins: --art-overlap pulls it up into the
   headline, --art-drop pushes it past the hero's bottom edge. Because the hero
   has no viewport-derived height, both gaps are fixed at every size — nothing
   can open up between the headline and the figure. */
.hero__art{
  position:relative;z-index:1;display:flex;justify-content:center;
  margin-top:calc(var(--art-overlap) * -1);
  margin-bottom:calc(var(--art-drop) * -1);
}
.hero__art img{
  height:var(--art-h);width:auto;max-width:none;
  object-fit:contain;object-position:bottom;
  filter:drop-shadow(0 0 2px color-mix(in srgb,var(--accent) 50%,transparent));
}


/* ==========================================================================
   Tape marquee — rotated band that bridges two sections
   ========================================================================== */
/* Crossed tapes straddling the hero's bottom edge. One band sits behind the
   figure and one in front, so the X reads as tape stuck over a poster.
   They hang off .hero (not the figure's wrapper) so they stay pinned to the
   hero's real bottom edge now that the figure overhangs it.
   clip-path trims left/right only — `overflow:hidden` would also cut the
   vertical overhang onto the next section, which is the whole point. */
.hero__tape{
  position:absolute;left:50%;right:auto;width:100vw;margin-left:-50vw;
  bottom:calc(var(--tape-drop) * -1);
  height:var(--tape-h);
  clip-path:inset(-200% 0 -200% 0);pointer-events:none;
}
/* Lanterns sit on the road either side of the figure. z-index 2 keeps them
   under the tape (3/5) and under the figure (inside .hero__inner at 4), so they
   read as further back in the scene. */
.hero__lantern{
  position:absolute;z-index:2;pointer-events:none;
  height:min(clamp(150px,18vw,460px),40svh);
  bottom:calc(var(--tape-h) * .66);
  transform:translateX(-50%);
  filter:drop-shadow(0 18px 26px rgba(0,0,0,.55));
}
/* body and flame are separate layers on the SAME canvas, so stacking them at
   inset:0 registers them exactly — no offset maths, and the flame can be
   animated on its own. */
.hero__lantern img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}
.hero__lantern--l{left:19%;aspect-ratio:136/300}
.hero__lantern--r{left:81%;aspect-ratio:131/299}

/* Warm halo behind the flame, pulsing out of sync with it. */
.hero__lantern::before{
  content:"";position:absolute;left:50%;top:9%;
  width:135%;aspect-ratio:1;transform:translate(-50%,-50%);
  background:radial-gradient(circle,rgba(255,176,32,.42) 0%,rgba(255,140,16,.16) 38%,transparent 66%);
  animation:aff-flame-glow 2.9s ease-in-out infinite;
}
/* transform-origin sits at the flame's base (y=56 of 300 = ~18.7%) so it
   stretches and leans from the wick rather than from the canvas centre. */
.hero__lantern-flame{
  transform-origin:50% 18.7%;
  animation:aff-flame 2.6s ease-in-out infinite;
  will-change:transform,opacity;
}
.hero__lantern--r .hero__lantern-flame{animation-duration:3.1s;animation-delay:-.9s}
.hero__lantern--r::before{animation-duration:3.4s;animation-delay:-1.1s}

/* Flicker lives mostly in brightness, not geometry: the shape barely moves
   (<=2.5% scale, <=0.4deg lean) while opacity carries the guttering. Larger
   transforms read as the whole flame bouncing. */
@keyframes aff-flame{
  0%,100%{transform:scale(1,1) rotate(0deg);opacity:1}
  17%    {transform:scale(.993,1.022) rotate(-.35deg);opacity:.94}
  33%    {transform:scale(1.012,.992) rotate(.28deg);opacity:1}
  50%    {transform:scale(.997,1.014) rotate(-.18deg);opacity:.91}
  67%    {transform:scale(1.008,.996) rotate(.3deg);opacity:.985}
  84%    {transform:scale(.999,1.007) rotate(-.12deg);opacity:.955}
}
@keyframes aff-flame-glow{
  0%,100%{opacity:.82;transform:translate(-50%,-50%) scale(1)}
  30%    {opacity:.66;transform:translate(-50%,-50%) scale(.975)}
  60%    {opacity:.95;transform:translate(-50%,-50%) scale(1.025)}
}

.hero__tape--back{z-index:3}
.hero__tape--front{z-index:5}
.hero__hem{
  position:absolute;left:50%;width:150vw;margin-left:-75vw;
  top:calc(100% - .5 * var(--tape-h) + var(--tape-drop) + var(--band-h) / 2);
  /* Only as tall as the wedge. The hero sits above the next section, so any
     extra height here blanks out the top of that section's content. */
  /* z-index 0, not 1: the back tape is also 1 and the hem comes later in the
     DOM, so at 1 it painted over band A wherever that band dips below the hem's
     diagonal — the tape vanished into the white. */
  height:clamp(110px,12vw,260px);z-index:2;pointer-events:none;
  background:var(--light);
  transform:rotate(var(--tilt));transform-origin:50% 0;
}
.marquee__band{
  position:absolute;left:50%;width:134%;
  height:var(--band-h);display:flex;align-items:center;
  background:var(--accent);color:var(--ink);
  border-block:3px solid var(--ink);
  overflow:hidden;
}
/* Staggered so the two tapes meet at a point left of centre instead of
   overlapping along their whole length. */
.marquee__band--a{top:50%;transform:translate(-50%,-50%) rotate(calc(var(--tilt) * -1))}
.marquee__band--b{top:50%;transform:translate(-50%,-50%) rotate(var(--tilt))}
.marquee__track{display:flex;width:max-content;animation:aff-marquee var(--marquee-dur) linear infinite}
/* Band B runs the other way so the pair never reads as one doubled stripe. */
.marquee__band--b .marquee__track{animation-direction:reverse}
.marquee__group{display:flex;align-items:center;gap:42px;padding-right:42px}
.marquee__text{
  font-family:var(--font-display);font-weight:800;
  font-size:min(clamp(19px,2.4vw,46px),calc(var(--band-h) * .46));letter-spacing:-.01em;
  text-transform:uppercase;color:var(--ink);white-space:nowrap;
}
.marquee__sep{color:var(--ink);font-size:clamp(12px,1.2vw,18px)}
.marquee__img{height:clamp(30px,3.4vw,46px);width:auto;object-fit:contain}
@keyframes aff-marquee{from{transform:translate3d(0,0,0)}to{transform:translate3d(-50%,0,0)}}

/* ==========================================================================
   Section head
   ========================================================================== */
.sec-head{
  display:flex;flex-direction:column;align-items:flex-start;gap:18px;
  margin-bottom:clamp(40px,5vw,72px);max-width:min(100%,920px);
}
/* Title block left, CTA right. The aside is bottom-aligned so the button sits
   on the headline's baseline rather than floating beside its cap height. */
.sec-head--split{
  max-width:none;display:grid;gap:var(--head-gap);grid-template-columns:1fr;
  margin-bottom:clamp(28px,2.6vw,44px);
}
.sec-head--split .sec-head__main{
  display:flex;flex-direction:column;align-items:flex-start;gap:18px;
  max-width:min(100%,920px);
}
.sec-head__intro{
  font-size:var(--fs-body);line-height:1.5;
  color:var(--sec-dim,var(--text-dim));
}

/* Multi-paragraph body copy under a section head. */
/* A .sec-intro belongs to the head above it, so the head's usual section-sized
   bottom margin is wrong there — it produced 72px in Deals against 34px in
   Benefits, which builds its head as a grid and uses the row gap. */
.sec-head:has(+ .sec-intro){margin-bottom:var(--head-gap)}
.sec-intro{
  font-size:var(--fs-body);line-height:1.5;
  color:var(--sec-dim,var(--text-dim));
  margin-bottom:clamp(30px,3.4vw,56px);
}
.sec-intro p{margin-bottom:.8em}
.sec-intro p:last-child{margin-bottom:0}
.sec-intro--centred{max-width:72ch;margin-inline:auto;text-align:center;margin-bottom:clamp(18px,2vw,30px)}
@media (min-width:900px){
  /* centre, not end: end-aligned the button tracked the bottom of the whole
     copy block and drifted low as paragraphs were added. */
  .sec-head--split{grid-template-columns:minmax(0,1fr) auto;align-items:center}
  .sec-head__aside{justify-self:end}
  /* second row, spanning both columns, so the paragraph runs the full content
     width and carries on under the CTA instead of stopping at the left column */
  .sec-head--split .sec-head__intro{grid-column:1 / -1;max-width:none}
}
.sec-head__lead{
  max-width:58ch;font-size:var(--fs-body);line-height:1.55;
  color:var(--sec-dim,var(--text-dim));
}
.section-title{
  font-size:var(--fs-display);line-height:.86;letter-spacing:-.045em;
  color:var(--sec-head,#fff);margin:0;max-width:15ch;text-wrap:balance;
}

/* ==========================================================================
   Benefit cards — big rounded blocks
   ========================================================================== */
.benefits{
  /* The hero's figure hangs --art-drop past the hero's edge into this section,
     so an anchor jump must skip at least that much or you arrive looking at its
     feet. Deriving the skip from the overhang keeps it correct at every scale;
     deriving it from this section's padding did not. */
  --anchor-skip:calc(var(--art-drop) + 12px);
  /* On arrival the heading sits at (pad-top - anchor-skip - header-h) below the
     header, and the cards end --section-y above the fold. Deriving pad-top from
     --section-y makes those two gaps identical instead of coincidentally close. */
  --pad-top:calc(var(--section-y) + var(--anchor-skip) + var(--header-h));
  padding-block:var(--pad-top) var(--section-y);
  position:relative;z-index:1;
  /* Negative because html already sets scroll-padding-top (header-h + 16);
     this cancels that and skips the overhang on top. */
  scroll-margin-top:calc(0px - var(--anchor-skip) - var(--header-h));
  /* Tall enough that after the skip the section still fills the viewport, so
     the next section's black never shows on arrival. */
  min-height:calc(100svh + var(--anchor-skip));
  /* That min-height leaves slack whenever the content is shorter than the
     viewport. Flexing the shell and pushing the cards down with margin-top:auto
     puts the slack between the lead and the cards instead of stranding it as
     dead space underneath them. It self-balances: shorter viewport, less slack. */
  display:flex;flex-direction:column;
}
.benefits > .shell{flex:1;display:flex;flex-direction:column}
.benefits .cards{margin-top:auto}
.cards{display:grid;gap:clamp(16px,1.6vw,22px);grid-template-columns:1fr}
@media (min-width:880px){ .cards{grid-template-columns:repeat(3,1fr)} }

.card{
  position:relative;isolation:isolate;display:flex;flex-direction:column;
  background:var(--sec-card,var(--surface));
  border:2px solid var(--sec-line,var(--border));
  --card-pad:clamp(26px,2.6vw,38px);
  border-radius:var(--r-card);
  overflow:hidden;min-height:clamp(320px,34vw,420px);
}
/* Accent panel across the top, figure centred in it; the copy sits on the
   card's own dark ground below. The art bleeds edge to edge, so the padding
   lives on the text rather than on the card. */
.card__art{
  display:flex;align-items:flex-end;justify-content:center;
  background:var(--accent);
  height:clamp(160px,14vw,220px);padding:var(--card-pad) var(--card-pad) 0;
}
.card__art img{max-height:100%;width:auto;max-width:82%;object-fit:contain}
.card__title{
  font-size:var(--fs-h3);color:var(--sec-head,#fff);
  margin:clamp(22px,2.4vw,32px) 0 14px;padding-inline:var(--card-pad);
}
.card__text{
  color:var(--sec-dim,var(--text-dim));font-size:var(--fs-body);line-height:1.5;
  padding:0 var(--card-pad) var(--card-pad);margin-bottom:auto;
}

/* Capabilities cards stay black whatever palette the section runs. */
.benefits .card,.deals .card{background:var(--ink);border-color:var(--ink)}
.benefits .card__title,.deals .card__title{color:#fff}
/* --sec-head is ink on a light section, and these cards are inverted to black,
   so the "best for" value was black on black. */
.deals .deal__best{color:#fff}
.benefits .card__text,.deals .card__text{color:var(--text-dim)}
/* The mascots are near-black, so they vanish on a black card. A drop-shadow traces
   the real alpha silhouette, which rims every mascot whether or not its own artwork
   carries a yellow accent — a radial halo behind it does not. */
.benefits .card__art img{filter:drop-shadow(0 10px 18px rgba(0,0,0,.28))}

/* ==========================================================================
   The Way — full-bleed statement block
   ========================================================================== */
/* Full viewport height, content centred. min-height (not height) so it still
   grows if the steps ever outrun the screen on a short viewport. */
.way{
  position:relative;padding-block:var(--section-y);overflow:hidden;
  /* Not 100svh: these sections start below the fixed header, so a full
     viewport height overruns the fold by exactly --header-h and the bottom gap
     gets clipped while the top keeps its full padding. */
  min-height:calc(100svh - var(--header-h));display:flex;align-items:center;
}
/* Full-bleed dojo interior behind the method steps, veiled so the cards and
   display type stay legible over it. */
.way__bg{
  position:absolute;inset:0;z-index:0;pointer-events:none;
  background-size:cover;background-position:center;background-repeat:no-repeat;
}
.way__bg::after{
  content:"";position:absolute;inset:0;
  background:
    /* Top band buried outright — the roof structure sat right behind the
       headline. Solid to 30%, then released so the side panels survive. */
    linear-gradient(180deg,
      var(--sec-bg,var(--bg)) 0%,
      var(--sec-bg,var(--bg)) 30%,
      color-mix(in srgb,var(--sec-bg,var(--bg)) 70%,transparent) 46%,
      transparent 64%),
    /* Dark core, clear edges — the reverse of a normal vignette. It buries the
       centre of the interior so the lit shoji panels down each side are the
       only thing that reads, and the cards sit on flat black. */
    radial-gradient(58% 96% at 50% 54%,
      var(--sec-bg,var(--bg)) 0%,
      var(--sec-bg,var(--bg)) 42%,
      color-mix(in srgb,var(--sec-bg,var(--bg)) 72%,transparent) 74%,
      transparent 100%),
    /* bottom seam */
    linear-gradient(0deg,
      color-mix(in srgb,var(--sec-bg,var(--bg)) 85%,transparent) 0%,
      transparent 24%);
}
.way .shell{position:relative;z-index:2;width:100%}

/* --- The method: three numbered steps, then the payoff they add up to ----- */
.way__flow{
  --step-gap:clamp(18px,2.4vw,40px);
  list-style:none;display:grid;grid-template-columns:1fr;gap:var(--step-gap);
}
@media (min-width:900px){ .way__flow{grid-template-columns:repeat(3,1fr)} }

.way-step{
  position:relative;isolation:isolate;
  padding:clamp(28px,2.8vw,42px);
  border:2px solid var(--sec-line,var(--border));border-radius:var(--r-card);
  background:var(--sec-card,var(--surface));
  display:flex;flex-direction:column;align-items:flex-start;
}
/* the + that used to be the equation operator now bridges the cards */
@media (min-width:900px){
  .way-step + .way-step::before{
    content:"+";position:absolute;z-index:2;
    left:calc(var(--step-gap) / -2);top:50%;transform:translate(-50%,-50%);
    font-family:var(--font-display);font-weight:800;line-height:1;
    font-size:clamp(26px,2.6vw,44px);color:var(--accent);
  }
}
.way-step__num{
  position:absolute;top:clamp(14px,1.4vw,22px);right:clamp(18px,1.8vw,28px);
  font-family:var(--font-display);font-weight:800;line-height:1;
  font-size:clamp(46px,5vw,86px);letter-spacing:-.05em;
  color:var(--sec-head,#fff);opacity:.09;pointer-events:none;
}
.way-step__kicker{
  font-family:var(--font-display);font-size:12px;font-weight:800;
  letter-spacing:.2em;text-transform:uppercase;
  color:var(--accent);margin-bottom:10px;
}
.way-step__label{
  font-family:var(--font-display);font-weight:800;text-transform:uppercase;
  font-size:clamp(30px,3.4vw,52px);line-height:.92;letter-spacing:-.04em;
  color:var(--sec-head,#fff);margin-bottom:14px;
}
.way-step__text{color:var(--sec-dim,var(--text-dim));font-size:var(--fs-body);line-height:1.5}

.way__payoff{
  position:relative;margin-top:clamp(30px,3.4vw,56px);
  display:grid;gap:clamp(14px,1.8vw,30px);align-items:center;
  grid-template-columns:1fr;
  padding:clamp(28px,3vw,46px) clamp(26px,3vw,52px);
  border:3px solid var(--ink);border-radius:var(--r-card);
  background:var(--accent);color:var(--ink);
}
@media (min-width:900px){
  .way__payoff{grid-template-columns:auto 1fr;column-gap:clamp(30px,3.6vw,64px)}
}
.way__payoff-head{display:flex;flex-direction:column;gap:4px}
.way__payoff-title{
  font-family:var(--font-display);font-weight:800;text-transform:uppercase;
  font-size:clamp(34px,4.4vw,72px);line-height:.88;letter-spacing:-.045em;
}
.way__payoff-sub{
  font-family:var(--font-body);font-size:clamp(12px,1vw,15px);font-weight:700;
  letter-spacing:.24em;text-transform:uppercase;opacity:.62;
}
.way__payoff-text{
  font-size:var(--fs-body);line-height:1.5;max-width:62ch;
  color:color-mix(in srgb,var(--ink) 78%,transparent);
}

/* ==========================================================================
   Warriors
   ========================================================================== */
.deals{
  padding-block:var(--section-y);position:relative;
  /* Not 100svh: these sections start below the fixed header, so a full
     viewport height overruns the fold by exactly --header-h and the bottom gap
     gets clipped while the top keeps its full padding. */
  min-height:calc(100svh - var(--header-h));display:flex;align-items:center;
}
.deals > .shell{width:100%}

/* Deal cards reuse .card's shell; the yellow panel carries the model name
   instead of a mascot, since these have no artwork. */
.deal{justify-content:flex-start}
.deal__head{
  background:var(--accent);color:var(--ink);
  padding:clamp(22px,2.2vw,30px);
  display:flex;flex-direction:column;gap:5px;
}
.deal__kicker{
  font-family:var(--font-display);font-size:13px;font-weight:800;
  letter-spacing:.2em;text-transform:uppercase;opacity:.62;
}
.deal__name{
  font-family:var(--font-display);font-weight:800;text-transform:uppercase;
  font-size:clamp(34px,3.8vw,58px);line-height:.92;letter-spacing:-.04em;
}
.deal .card__text{padding-top:clamp(20px,1.9vw,24px);margin-bottom:clamp(16px,1.7vw,22px)}
.deal__best{
  margin-top:auto;padding:0 var(--card-pad) var(--card-pad);
  display:flex;flex-direction:column;gap:4px;
  font-size:clamp(14px,1.05vw,17px);color:var(--sec-head,#fff);
}
.deal__best span{
  font-family:var(--font-display);font-size:12px;font-weight:800;
  letter-spacing:.2em;text-transform:uppercase;color:var(--accent);
}

/* ==========================================================================
   Contact
   ========================================================================== */
.contact{
  padding-block:var(--section-y);position:relative;
  /* Not 100svh: these sections start below the fixed header, so a full
     viewport height overruns the fold by exactly --header-h and the bottom gap
     gets clipped while the top keeps its full padding. */
  min-height:calc(100svh - var(--header-h));display:flex;align-items:center;
}
.contact > .shell{width:100%}
.contact__inner{display:flex;justify-content:center}
.contact__body{min-width:0;width:100%}
.contact__head{margin-bottom:clamp(20px,2.2vw,30px);text-align:center}
/* .section-title carries a max-width with no auto margins, so inside a centred
   head its box stays left-aligned and its centred text lands off-centre. */
.contact__head .section-title{margin-inline:auto}
.contact__sub{color:var(--sec-dim,var(--text-dim));font-size:var(--fs-body);line-height:1.5;margin-top:16px}
.contact__links{display:flex;flex-wrap:wrap;gap:12px;margin-top:18px;justify-content:center}
.contact__link{
  display:inline-flex;align-items:center;gap:9px;
  padding:12px 22px;border-radius:var(--r-pill);
  border:2px solid var(--sec-line,var(--border));color:var(--sec-head,#fff);
  font-family:var(--font-display);font-size:13px;font-weight:800;
  letter-spacing:.06em;text-transform:uppercase;
  transition:background .3s var(--ease),color .3s var(--ease),border-color .3s var(--ease);
}
.contact__link:hover{background:var(--accent);color:var(--ink);border-color:var(--accent)}
.contact__link .material-symbols-outlined{font-size:19px}

.form{
  display:flex;flex-direction:column;gap:18px;
  background:var(--sec-card,var(--surface));
  border:2px solid var(--sec-line,var(--border));
  border-radius:var(--r-card);padding:clamp(22px,2.4vw,34px);
}
.form__row{display:grid;gap:18px;grid-template-columns:1fr}
@media (min-width:640px){ .form__row{grid-template-columns:1fr 1fr} }
/* At content width a single stacked column leaves the fields absurdly wide, so
   the form itself becomes a two-column grid. */
@media (min-width:900px){
  .form{
    display:grid;align-items:start;
    grid-template-columns:1fr 1fr;
    column-gap:clamp(20px,2.2vw,36px);row-gap:14px;
  }
  .form__row{grid-column:1 / -1}
  .field--site{grid-column:1}
  .field--source{grid-column:2}
  .field--message{grid-column:1 / -1}
  .form__msg,.form__actions{grid-column:1 / -1}
}
.field{display:flex;flex-direction:column}
.field__label{
  font-family:var(--font-display);font-size:12px;font-weight:800;
  letter-spacing:.12em;text-transform:uppercase;
  color:var(--sec-dim,var(--text-dim));margin-bottom:6px;
}
.field__input{
  width:100%;padding:16px 20px;border-radius:var(--r-pill);
  background:var(--sec-input,var(--bg));
  border:2px solid var(--sec-line,var(--border));
  color:var(--sec-head,#fff);font-size:16px;
  transition:border-color .3s var(--ease);
}
.field__input::placeholder{color:var(--sec-ph,rgba(255,255,255,.34))}
.field__input:focus{outline:0;border-color:var(--accent)}
textarea.field__input{border-radius:var(--r-sm);resize:vertical;min-height:108px;line-height:1.55}
.field__select{
  appearance:none;cursor:pointer;padding-right:48px;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),
                   linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 26px) 52%,calc(100% - 20px) 52%;
  background-size:6px 6px,6px 6px;background-repeat:no-repeat;
}
.field__select option{background:var(--bg);color:#fff}
.field--hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.form__actions{margin-top:6px}
.form__actions .btn{width:100%}
.form__msg{padding:16px 22px;border-radius:var(--r-sm);
  border:2px solid var(--sec-line,var(--border));font-size:15px;text-align:center}
.form__msg.is-ok{border-color:var(--accent);color:var(--accent)}
.form__msg.is-error{border-color:#ff6b6b;color:#ff9b9b}

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer{background:var(--deep);padding-block:clamp(52px,6vw,84px)}
.site-footer__inner{
  display:flex;flex-direction:column;align-items:center;gap:26px;text-align:center;
}
@media (min-width:900px){
  .site-footer__inner{flex-direction:row;justify-content:space-between;text-align:left}
}
.site-footer__brand{
  font-family:var(--font-display);font-weight:800;
  font-size:clamp(28px,3.6vw,54px);letter-spacing:-.045em;
  color:var(--accent);text-transform:uppercase;
}
.site-footer__nav{display:flex;flex-wrap:wrap;justify-content:center;gap:10px}
@media (min-width:900px){
  .site-footer__inner{gap:clamp(24px,4vw,64px)}
  .site-footer__nav{flex:0 1 auto;flex-wrap:nowrap}
  .site-footer__copy{flex:0 1 240px;text-align:right}
}
.site-footer__nav a{
  padding:10px 18px;border-radius:var(--r-pill);
  border:2px solid var(--border);font-size:13px;font-weight:600;color:#fff;
  transition:background .3s var(--ease),color .3s var(--ease),border-color .3s;
}
.site-footer__nav a:hover{background:var(--accent);color:var(--ink);border-color:var(--accent)}
.site-footer__copy{font-size:12px;color:var(--text-dim);letter-spacing:.06em}

/* ==========================================================================
   Inner pages
   ========================================================================== */
.page{padding-block:calc(var(--header-h) + 72px) var(--section-y)}
.entry__title{font-size:var(--fs-display);color:#fff;margin-bottom:22px}
.entry__meta{color:var(--text-dim);font-size:13px;margin-bottom:28px}
.entry__lead{color:var(--text-dim);font-size:19px;margin-bottom:32px}
.entry__content{color:var(--text-dim);line-height:1.8}
.entry__content > * + *{margin-top:1.2em}
.entry__content h2,.entry__content h3{color:#fff;margin-top:1.8em}
.entry__content a{color:var(--accent);text-decoration:underline}
.entry__content blockquote{border-left:4px solid var(--accent);padding-left:22px;font-style:italic}
.pager{margin-top:48px}
.pager a,.pager .current{display:inline-block;padding:10px 18px;
  border:2px solid var(--border);border-radius:var(--r-pill);margin-right:8px}
.pager .current{border-color:var(--accent);color:var(--accent)}
.page--404{text-align:center}

/* ==========================================================================
   Reveal fallback
   Hiding is applied by JS (html.reveal-on) only once the observer exists,
   so content can never be stranded invisible.
   ========================================================================== */
.reveal-on [data-reveal]{opacity:0}

/* ==========================================================================
   Section palettes
   Each section exposes --sec-* tokens; components read those, so one
   data-bg attribute re-colours the whole block and stays legible.
   ========================================================================== */
:root{
  --sec-bg:var(--bg);
  --sec-text:var(--text);
  --sec-dim:var(--text-dim);
  --sec-head:#fff;
  --sec-card:var(--surface);
  --sec-line:var(--border);
  --sec-input:var(--bg);
  --sec-ph:rgba(255,255,255,.34);
}
section[data-bg]{background:var(--sec-bg);color:var(--sec-text);position:relative}

section[data-bg="dark"]{--sec-bg:var(--bg)}
section[data-bg="deep"]{--sec-bg:var(--deep)}

section[data-bg="light"],
section[data-bg="grey"]{
  --sec-text:var(--ink);
  --sec-dim:var(--ink-dim);
  --sec-head:var(--ink);
  --sec-line:var(--ink);          /* hard black outlines — brutalist */
  --sec-input:#fff;
  --sec-ph:rgba(13,14,18,.4);
}
section[data-bg="light"]{--sec-bg:var(--light);--sec-card:#fff}
section[data-bg="grey"]{ --sec-bg:var(--grey); --sec-card:#fff}

section[data-bg="accent"]{
  --sec-bg:var(--accent);
  --sec-text:var(--ink);
  --sec-dim:rgba(13,14,18,.7);
  --sec-head:var(--ink);
  --sec-card:#fff;
  --sec-line:var(--ink);
  --sec-input:#fff;
  --sec-ph:rgba(13,14,18,.4);
}

/* On yellow and light sections the accent pills must invert to stay visible */
section[data-bg="accent"] .way-step + .way-step::before{color:var(--ink)}
section[data-bg="accent"] .way-step__kicker{color:var(--ink);opacity:.7}
section[data-bg="accent"] .way__payoff{background:var(--ink);color:var(--accent);border-color:var(--ink)}
section[data-bg="accent"] .way__payoff-text{color:color-mix(in srgb,var(--accent) 78%,transparent)}
section[data-bg="accent"] .btn--accent{background:var(--ink);color:var(--accent);border-color:var(--ink)}
section[data-bg="accent"] .btn--accent:hover{background:#fff;color:var(--ink);border-color:#fff}
section[data-bg="accent"] .btn--accent .btn__arrow{background:var(--accent);color:var(--ink)}

/* ==========================================================================
   Characters
   ========================================================================== */

/* ==========================================================================
   Hero key art — responsive framing
   ========================================================================== */
@media (max-width:767px){
  /* The hero tokens are driven by vw, and on a narrow screen every one of them
     bottomed out on its clamp floor — the hero collapsed to ~55vh with a 40px
     headline. Re-scale them for mobile so the composition keeps its proportions.
     The old block also pinned padding-top to the header (killing the space above
     the H1) and painted an opaque veil that buried the brickwork; both are gone,
     so the balanced padding and the light veil now apply here too. */
  :root{
    --fs-mega:clamp(40px,14vw,88px);
    /* No overlap on mobile. The headline wraps to a short final line ("DOJO.")
       which centres right under the centred figure, so any overlap eats the
       middle glyphs — the J became unreadable. Where the line breaks depends on
       the copy and the screen, so the figure starts below the type instead. */
    --art-overlap:0px;
    --art-h:min(clamp(320px,110vw,560px),50svh);
    --art-drop:clamp(44px,9vw,72px);
    /* Steeper cross on mobile. The bands separate by 2*d*tan(tilt) from the
       crossing point, so on a narrow screen 3.8deg left them only ~26px apart at
       the frame edge while each band is thicker than that — they merged and the
       back band's text sat under the front one. 9deg clears the thickness. */
    --tilt:9deg;
    --tape-h:min(clamp(150px,38vw,230px),26svh);
    --band-h:min(clamp(48px,12vw,74px),9svh);
  }
  /* Mobile opts out of the symmetric top gap. The rule balances the headline
     against the space the figure occupies below it, but on a tall narrow screen
     that figure is huge relative to the viewport, so the matching gap above
     reads as dead air. Pinned to the header instead. */
  .hero{padding-block:calc(var(--header-h) + clamp(32px,9vw,64px)) 0}

  /* Lanterns move to the frame edges and get cropped in half. At 19%/81% they
     crowded the figure on a narrow screen; anchored to the edges they read as
     foreground depth without competing for the centre. translateX(-50%) on the
     base rule does the halving: left:0 centres one on the left edge, left:100%
     the other on the right. */
  .hero__lantern{height:min(clamp(280px,95vw,460px),46svh)}
  .hero__lantern--l{left:0}
  .hero__lantern--r{left:100%}

  .sec-head__aside .btn{width:100%;justify-content:space-between}

  /* --- everything centres on mobile ------------------------------------ */
  .sec-head,
  .sec-head--split .sec-head__main{align-items:center;text-align:center}
  .sec-head__aside{justify-self:center}
  .sec-head__lead,.sec-head__intro{margin-inline:auto}

  .sec-intro{text-align:center}

  /* text-align only — these are flex columns, so align-items:center would set
     the CROSS axis and shrink-wrap the children (it collapsed the card's yellow
     art panel to the width of its image). */
  .card{text-align:center}
  .card__art{justify-content:center}

  /* The base rule sets align-items:flex-start, which shrink-wraps the short
     children (kicker, label) so text-align has nothing to centre inside them.
     stretch lets them fill the card, then the text actually centres. */
  .way-step{text-align:center;align-items:stretch}
  .way-step__num{display:none}      /* the 01/02/03 ghosts crowd a narrow card */
  .way__payoff{justify-items:center;text-align:center}
  .way__payoff-head{align-items:center}

  .deal{text-align:center}
  .deal__head{align-items:center}
  .deal__best{align-items:center}

  .contact__head{text-align:center}
  .field__label{text-align:center}
  .form__actions .btn{justify-content:center}
}

/* ==========================================================================
   Atmosphere
   ========================================================================== */
body::after{
  content:"";position:fixed;inset:0;z-index:400;pointer-events:none;
  opacity:.035;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Sections that sit against the rotated tape need clearance */

