/* =============================================================
   Runtime Lightmap Baker — landing page
   Dark, cinematic. Green = primary accent, amber = secondary.
   ============================================================= */

/* ---------- Tokens ---------- */
:root{
  --bg-0:#0B0D0E;
  --bg-1:#121618;
  --bg-2:#171C1F;
  --panel:#1A1F22;

  --line:rgba(255,255,255,.08);
  --line-strong:rgba(255,255,255,.16);

  --text:#F2F5F4;
  --text-dim:#9AA5A4;
  --text-faint: #7A8482;

  --green:#45C64A;
  --green-bright:#5CE05F;
  --green-deep:#2E8A31;

  --amber:#FF8A1F;
  --amber-deep:#C96A12;

  --radius:14px;
  --maxw:1180px;

  /* layout scale */
  --topbar-h:68px;
  --pad-x:clamp(18px,4vw,40px);
  --sp-1:6px;
  --sp-2:12px;
  --sp-3:18px;
  --sp-4:26px;
  --sp-5:38px;
  --sp-6:56px;
  --sp-7:84px;
  --section-y:clamp(88px,11vw,120px);

  --font-display:'Anton','Arial Narrow',sans-serif;
  --font-body:'Inter',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --ease:cubic-bezier(.22,.61,.36,1);

  color-scheme:dark;
}

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

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

html,body{
  margin:0;
  padding:0;
  overflow-x:hidden;
}

body{
  min-height:100%;
  font-family:var(--font-body);
  font-size:17px;
  font-weight:400;
  line-height:1.65;
  color:var(--text);
  background-color:var(--bg-0);
  /* The page gradient lives on a composited fixed layer (body::before) instead
     of background-attachment:fixed, which forces a full-viewport repaint on
     every scroll frame (Chrome: kHasBackgroundAttachmentFixedObjects). */
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}

body::before{
  content:"";
  position:fixed;
  inset:0;
  z-index:-1;
  pointer-events:none;
  background:linear-gradient(180deg,var(--bg-0) 0%,var(--bg-1) 44%,var(--bg-0) 100%);
}

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

h1,h2,h3{
  font-family:var(--font-display);
  font-weight:400;
  text-transform:uppercase;
  letter-spacing:.6px;
  line-height:1.02;
  margin:0;
}

p{margin:0}
ul{margin:0;padding:0;list-style:none}

a{color:var(--green);text-decoration:none}
a:hover{color:var(--green-bright)}

button{font:inherit;color:inherit}

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

::selection{background:var(--green-deep);color:#fff}

/* anchor targets clear the fixed topbar */
[id]{scroll-margin-top:calc(var(--topbar-h) + 24px)}

.wrap{
  width:100%;
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--pad-x);
}

.skip-link{
  position:absolute;
  left:-9999px;
  top:0;
  z-index:200;
  padding:12px 18px;
  background:var(--green);
  color:var(--bg-0);
  font-weight:700;
}
.skip-link:focus{left:12px;top:12px}

/* =============================================================
   Buttons
   ============================================================= */
.btn{
  --btn-py:13px;
  --btn-px:22px;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:10px;
  padding:var(--btn-py) var(--btn-px);
  border:1px solid transparent;
  border-radius:10px;
  font-family:var(--font-body);
  font-weight:700;
  font-size:.86rem;
  letter-spacing:.9px;
  text-transform:uppercase;
  text-align:center;
  white-space:nowrap;
  cursor:pointer;
  transition:transform .22s var(--ease),background-color .22s var(--ease),
             box-shadow .22s var(--ease),border-color .22s var(--ease),color .22s var(--ease);
}

.btn--primary{
  background:var(--green);
  color:var(--bg-0);
  box-shadow:0 6px 22px -8px rgba(69,198,74,.65),0 0 0 1px rgba(92,224,95,.22) inset;
}
.btn--primary:hover{
  background:var(--green-bright);
  color:var(--bg-0);
  transform:translateY(-2px);
  box-shadow:0 12px 30px -10px rgba(92,224,95,.75),0 0 0 1px rgba(92,224,95,.35) inset;
}
.btn--primary:active{transform:translateY(0)}

.btn--ghost{
  background:rgba(255,255,255,.02);
  border-color:var(--line-strong);
  color:var(--text);
}
.btn--ghost:hover{
  color:var(--text);
  border-color:rgba(69,198,74,.55);
  background:rgba(69,198,74,.08);
  transform:translateY(-2px);
}
.btn--ghost:active{transform:translateY(0)}

.btn--sm{--btn-py:10px;--btn-px:16px;font-size:.76rem;letter-spacing:.8px;border-radius:9px}
.btn--lg{--btn-py:17px;--btn-px:30px;font-size:.92rem}

/* a span that only looks like a button (its parent <a> is the link) */
.btn--static{pointer-events:none}

/* =============================================================
   Topbar
   ============================================================= */
.topbar{
  position:fixed;
  inset:0 0 auto 0;
  z-index:100;
  height:var(--topbar-h);
  background:rgba(11,13,14,.55);
  border-bottom:1px solid transparent;
  -webkit-backdrop-filter:blur(12px);
  backdrop-filter:blur(12px);
  transition:background-color .3s var(--ease),border-color .3s var(--ease);
}
.topbar.is-scrolled{
  background:rgba(11,13,14,.92);
  border-bottom-color:var(--line);
  /* At 92% opacity the blur is invisible, but it would still re-read and
     re-blur the strip on every scroll frame. Drop it in the scrolled state. */
  -webkit-backdrop-filter:none;
  backdrop-filter:none;
}

.topbar__inner{
  height:100%;
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--pad-x);
  display:flex;
  align-items:center;
  gap:var(--sp-4);
}

.brand{
  display:flex;
  align-items:center;
  gap:11px;
  color:var(--text);
  min-width:0;
}
.brand:hover{color:var(--text)}
.brand__mark{
  border-radius:8px;
  flex:none;
  box-shadow:0 0 0 1px var(--line-strong);
}
.brand__name{
  font-family:var(--font-display);
  text-transform:uppercase;
  font-size:19px;
  letter-spacing:.8px;
  line-height:1;
  white-space:nowrap;
}

.nav{
  margin-left:auto;
  display:flex;
  align-items:center;
  gap:clamp(14px,2.2vw,30px);
}
.nav a{
  color:var(--text-dim);
  font-size:.9rem;
  font-weight:500;
  letter-spacing:.2px;
  padding:6px 2px;
  position:relative;
  transition:color .2s var(--ease);
}
.nav a::after{
  content:"";
  position:absolute;
  left:0;right:0;bottom:0;
  height:2px;
  background:var(--green);
  transform:scaleX(0);
  transform-origin:left;
  transition:transform .25s var(--ease);
}
.nav a:hover{color:var(--text)}
.nav a:hover::after{transform:scaleX(1)}

/* the nav's auto margin pushes both the nav and the CTA right; when the nav
   is hidden the CTA takes over that job (see the 860px block below) */
.topbar__cta{flex:none}

@media (max-width:860px){
  .nav{display:none}
  .topbar__cta{margin-left:auto}
}
@media (max-width:560px){
  .brand__name{display:none}
  .topbar__cta{font-size:.7rem;--btn-px:13px}
  /* "Get it on the Unity Asset Store" is too long for a phone topbar and the
     button is nowrap, so drop the lead-in and keep the part that matters. */
  .topbar__cta .btn__long{display:none}
}

/* =============================================================
   Hero
   ============================================================= */
.hero{
  position:relative;
  isolation:isolate;
  min-height:100vh;
  min-height:100svh;
  display:flex;
  align-items:center;
  justify-content:center;
  padding-top:calc(var(--topbar-h) + clamp(40px,7vh,80px));
  padding-bottom:clamp(150px,19vh,200px);
  overflow:hidden;
  text-align:center;
}

/* Full-bleed scene backdrop.
   Stacking inside .hero (which is isolate + overflow:hidden):
     -3 photo   ->   -2 scrim   ->   -1 brand glow   ->   content
   The asset is tone-mapped rather than merely darkened: midtones are lifted
   (exposure 1.40) and highlights roll off toward a 0.36 ceiling instead of
   clipping to white. That is what lets the scene be bright while its PEAK
   luminance stays low enough for the type to survive - a flat darken cannot do
   both. Measured peak is 0.366, so the 0.57 plateau keeps the worst case at
   ~4.6:1 against --text across the content column, and the 0.06 edge leaves the
   scene almost unobscured where no text sits.
   Retuning: EXPO/PEAK live in the generator, the falloff in the stops below.
   Change either and the contrast numbers need rechecking. */
.hero__bg{
  position:absolute;
  inset:0;
  z-index:-3;
  display:block;
  pointer-events:none;
}
.hero__bg img{
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:50% 40%;
}

.hero__scrim{
  position:absolute;
  inset:0;
  z-index:-2;
  pointer-events:none;
  background:
    /* fade the foot of the hero into the page so the section seam vanishes */
    linear-gradient(180deg,
      transparent 52%,
      rgba(11,13,14,.86) 88%,
      var(--bg-0) 100%),
    /* A wide plateau holds ~.75 across the whole content column so body text
       clears 4.5:1, then falls away quickly so the scene reads at the edges. */
    radial-gradient(95% 80% at 50% 40%,
      rgba(11,13,14,.60) 0%,
      rgba(11,13,14,.57) 62%,
      rgba(11,13,14,.30) 85%,
      rgba(11,13,14,.06) 100%);
}

.hero__glow{
  position:absolute;
  inset:-20% -10% 0 -10%;
  z-index:-1;
  pointer-events:none;
  background:
    radial-gradient(58% 46% at 50% 30%,rgba(69,198,74,.11),transparent 70%),
    radial-gradient(46% 40% at 82% 78%,rgba(255,138,31,.07),transparent 72%),
    radial-gradient(70% 55% at 12% 88%,rgba(69,198,74,.05),transparent 75%);
}

.hero__inner{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:var(--sp-4);
}

.hero__icon{
  width:132px;
  height:132px;
  border-radius:26px;
  box-shadow:
    0 0 0 1px rgba(69,198,74,.34),
    0 0 0 6px rgba(69,198,74,.07),
    0 30px 60px -22px rgba(0,0,0,.9);
}

.hero__title{
  font-size:clamp(2.6rem,7vw,5.4rem);
  line-height:.95;
  letter-spacing:1px;
  max-width:14ch;
  margin-top:var(--sp-1);
  background:linear-gradient(180deg,#FFFFFF 12%,#C9D2D0 100%);
  -webkit-background-clip:text;
  background-clip:text;
  color:transparent;
}

.hero__sub{
  color:var(--text-dim);
  font-size:clamp(1rem,1.9vw,1.22rem);
  max-width:36ch;
  text-wrap:balance;
}

/* Compatibility line. .hero__inner is a flex column with gap:var(--sp-4);
   the negative margin pulls this up so it reads as a second line of the
   subline rather than a separate block. */
.hero__compat{
  margin-top:calc(var(--sp-4) * -0.62);
  color:var(--text-dim);
  font-size:clamp(.9rem,1.5vw,1.02rem);
  letter-spacing:.2px;
  text-wrap:balance;
}
.hero__compat strong{
  color:var(--text);
  font-weight:700;
}

.chips{
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:10px;
  margin-top:var(--sp-1);
}
.chip{
  display:inline-flex;
  align-items:center;
  gap:9px;
  padding:8px 16px;
  border:1px solid var(--line);
  border-radius:999px;
  background:rgba(255,255,255,.025);
  color:var(--text-dim);
  font-size:.83rem;
  font-weight:500;
  letter-spacing:.2px;
  white-space:nowrap;
}
.chip__dot{
  width:7px;
  height:7px;
  border-radius:50%;
  background:var(--green);
  box-shadow:0 0 10px rgba(69,198,74,.85);
  flex:none;
}

/* Three actions, each a button with its own caption underneath. align-items
   stretch so buttons in a row share a height even when one caption wraps to
   more lines than another. */
.hero__actions{
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  align-items:stretch;
  gap:14px 18px;
  margin-top:var(--sp-3);
}

.action{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:9px;
  max-width:19rem;
}
.action .btn{width:100%}

/* "Get it on the Unity Asset Store" is the longest label on the page. At the
   19rem cap above, .action .btn{width:100%} pins the pill narrower than its
   own nowrap text, so the label has always spilled past its rounded edges -
   invisible until the sale flash landed on the corner it spills into. Give
   just this action the width its label actually needs. */
.hero__actions .action:first-child{max-width:23rem}

.action__note{
  font-size:.78rem;
  line-height:1.45;
  color:var(--text-dim);
  text-wrap:balance;
  max-width:17rem;
}


/* Icon riding inside a button label; currentColor so it follows the ghost /
   primary foreground including the hover shift. */
.btn__icon{
  flex:none;
  opacity:.92;
}

/* Three long nowrap labels do not fit a phone, and the page sets
   overflow-x:hidden, so without this they are silently CLIPPED rather than
   wrapping. Stack them full width and allow wrapping instead. */
@media (max-width:720px){
  .hero__actions{
    width:100%;
    flex-direction:column;
    align-items:stretch;
    gap:16px;
  }
  .action,
  .action__note{max-width:none}
  .hero__actions .btn{
    width:100%;
    white-space:normal;
    line-height:1.3;
    --btn-px:16px;
  }
}

/* scroll cue — sits clear of the diagonal edge below it */
.scrollcue{
  position:absolute;
  left:50%;
  bottom:clamp(64px,8vh,96px);
  transform:translateX(-50%);
  z-index:2;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:8px;
  color:var(--text-faint);
  transition:color .25s var(--ease);
}
.scrollcue:hover{color:var(--green)}
.scrollcue__line{
  width:1px;
  height:38px;
  background:linear-gradient(180deg,transparent,var(--line-strong));
}
.scrollcue__chev{animation:cue 2.4s var(--ease) infinite}

@keyframes cue{
  0%,100%{transform:translateY(0);opacity:.55}
  50%{transform:translateY(6px);opacity:1}
}

/* no room for the cue on short viewports (landscape phones) */
@media (max-height:640px){
  .scrollcue{display:none}
}

/* diagonal brand motif: green hairline slash closing the hero */
.hero__edge{
  position:absolute;
  left:0;right:0;bottom:-1px;
  height:clamp(56px,8vw,132px);
  z-index:1;
  pointer-events:none;
}
.hero__edge::before,
.hero__edge::after{
  content:"";
  position:absolute;
  left:0;right:0;
  clip-path:polygon(0 100%,100% 0,100% 100%);
}
.hero__edge::before{
  top:0;bottom:0;
  background:var(--green);
  opacity:.85;
  /* fade the hairline out at both ends so it reads as a cut, not a laser */
  -webkit-mask-image:linear-gradient(90deg,transparent 0%,#000 16%,#000 84%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0%,#000 16%,#000 84%,transparent 100%);
}
.hero__edge::after{
  top:2px;bottom:-8px;
  background:var(--bg-0);
}

/* =============================================================
   Sections & headings
   ============================================================= */
.section{
  position:relative;
  padding-block:var(--section-y);
}

.sechead{
  /* No measure cap here: it capped the whole header at ~665px, so even a
     31-character title wrapped while the column had 1100px available. The
     paragraph keeps its own cap (.sechead__sub, 56ch) - that is the part that
     actually needs a readable measure. */
  margin-bottom:clamp(34px,5vw,54px);
}
.eyebrow{
  font-size:.72rem;
  font-weight:600;
  letter-spacing:2.4px;
  text-transform:uppercase;
  color:var(--text-faint);
  margin-bottom:var(--sp-2);
}
.sechead__title{
  font-size:clamp(1.9rem,4.2vw,3.1rem);
  letter-spacing:.8px;
}
/* A long title at the full 3.1rem measures ~1378px - wider than the 1100px
   column, so it wraps however wide the window gets. This ceiling brings it to
   ~1030px so it sits on one line, while short titles keep the full size. */
.sechead__title--long{
  font-size:clamp(1.75rem,3.4vw,2.3rem);
}
.rule{
  display:block;
  width:64px;
  height:3px;
  border-radius:2px;
  margin-top:18px;
  background:linear-gradient(90deg,var(--amber),var(--amber-deep));
}
.sechead__sub{
  color:var(--text-dim);
  margin-top:18px;
  font-size:1.02rem;
  max-width:56ch;
}

.note{
  margin-top:var(--sp-4);
  color:var(--text-faint);
  font-size:.87rem;
  /* No measure cap: this is a single short line, and 60ch broke it onto two
     rows while the column still had ~250px spare. .wrap already bounds it. */
}



/* =============================================================
   YouTube facade (click-to-load)
   ============================================================= */
.yt-box{
  position:relative;
  aspect-ratio:16/9;
  width:100%;
  border-radius:var(--radius);
  overflow:hidden;
  background:var(--bg-2);
  border:1px solid var(--line);
}
.yt-box--wide{
  box-shadow:0 40px 90px -46px rgba(0,0,0,.95),0 0 0 1px rgba(255,255,255,.03);
}

.yt-facade{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  padding:0;
  margin:0;
  border:0;
  background:var(--bg-2);
  cursor:pointer;
  display:block;
}
.yt-facade:focus-visible{outline-offset:-3px}

.yt-facade__thumb{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:cover;
  transition:transform .5s var(--ease),filter .35s var(--ease);
}
.yt-facade__scrim{
  position:absolute;
  inset:0;
  background:
    radial-gradient(60% 60% at 50% 50%,rgba(0,0,0,.18),rgba(0,0,0,.5) 100%),
    linear-gradient(180deg,rgba(11,13,14,.05),rgba(11,13,14,.65));
  transition:opacity .35s var(--ease);
}

.yt-facade__play{
  position:absolute;
  left:50%;
  top:50%;
  transform:translate(-50%,-50%);
  width:88px;
  height:88px;
  border-radius:50%;
  display:grid;
  place-items:center;
  color:var(--bg-0);
  background:var(--green);
  box-shadow:0 0 0 1px rgba(92,224,95,.5),0 14px 40px -12px rgba(69,198,74,.8);
  transition:transform .3s var(--ease),background-color .3s var(--ease);
}
.yt-facade__play svg{margin-left:4px}

.yt-facade__hint{
  position:absolute;
  left:18px;
  bottom:16px;
  font-size:.72rem;
  font-weight:600;
  letter-spacing:1.6px;
  text-transform:uppercase;
  color:var(--text-dim);
}

.yt-facade:hover .yt-facade__thumb{transform:scale(1.035)}
.yt-facade:hover .yt-facade__scrim{opacity:.72}
.yt-facade:hover .yt-facade__play{
  transform:translate(-50%,-50%) scale(1.07);
  background:var(--green-bright);
}

.yt-box iframe{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  border:0;
  display:block;
}

@media (max-width:640px){
  .yt-facade__play{width:66px;height:66px}
  .yt-facade__play svg{width:26px;height:26px}
  .yt-facade__hint{display:none}
}

/* =============================================================
   Demo section
   ============================================================= */
.section--demo{
  position:relative;
  isolation:isolate;
  overflow:hidden;
}
.demo__glow{
  position:absolute;
  inset:0;
  z-index:-1;
  pointer-events:none;
  background:
    radial-gradient(52% 48% at 78% 26%,rgba(69,198,74,.10),transparent 72%),
    radial-gradient(46% 44% at 14% 82%,rgba(255,138,31,.06),transparent 74%);
}

.demo-card{
  position:relative;
  display:block;
  border-radius:calc(var(--radius) + 6px);
  overflow:hidden;
  border:1px solid var(--line);
  background:var(--bg-2);
  box-shadow:0 50px 110px -52px rgba(0,0,0,.95);
  transition:border-color .3s var(--ease),box-shadow .3s var(--ease),transform .3s var(--ease);
}
.demo-card:hover{
  border-color:rgba(69,198,74,.4);
  box-shadow:0 60px 120px -50px rgba(0,0,0,1),0 0 46px -20px rgba(69,198,74,.4);
}

.demo-card__img{
  width:100%;
  height:auto;
  display:block;
  transition:transform .6s var(--ease);
}
.demo-card__scrim{
  position:absolute;
  inset:0;
  /* Decorative only. Without this it swallows taps: it is positioned, so it
     paints above the non-positioned CTA on mobile no matter what the DOM
     order is, and the buttons underneath become untappable. */
  pointer-events:none;
  background:linear-gradient(180deg,rgba(11,13,14,.34) 0%,rgba(11,13,14,.62) 55%,rgba(11,13,14,.86) 100%);
  transition:opacity .35s var(--ease);
}
/* Two actions centred over the artwork. */
.demo-card__cta{
  position:absolute;
  inset:0;
  display:flex;
  align-items:center;
  justify-content:center;
  gap:18px;
  padding:var(--sp-4);
}
/* Each action sits on its own plate. Measured on the actual screenshot, the
   image under this band peaks at luminance 1.0 (blown concrete/sky), so a mere
   scrim left the caption at 2.2:1 and the button text at 2.1:1 - both far below
   AA. An 0.86 plate puts the worst case above 5:1 no matter what is behind it,
   and keeps the rest of the artwork bright.
   Equal flex-basis so the pair match width; without it each hugs its own label
   (248px vs 272px) and they look misaligned. */
.demo-card__cta .action{
  flex:0 1 17rem;
  max-width:17rem;
  gap:10px;
  padding:16px 16px 13px;
  background:rgba(11,13,14,.86);
  border:1px solid var(--line-strong);
  border-radius:var(--radius);
  -webkit-backdrop-filter:blur(10px);
          backdrop-filter:blur(10px);
}
.demo-card__cta .btn--ghost{
  background:rgba(255,255,255,.04);
  border-color:var(--line-strong);
}
.demo-card__cta .btn--ghost:hover{
  background:rgba(69,198,74,.14);
  border-color:rgba(92,224,95,.7);
}
.demo-card__cta .action__note{color:var(--text-dim)}

.demo-card:hover .demo-card__img{transform:scale(1.03)}
.demo-card:hover .demo-card__scrim{opacity:.9}

/* On a phone the card image is only ~158px tall while two stacked plates need
   ~224px, so overlaying them spills outside the card. Below this width the CTA
   leaves the overlay and flows underneath the image, inside the same card. */
@media (max-width:720px){
  /* The CTA has left the overlay, so nothing sits on the photo any more - the
     scrim would only dim the buttons (visibly greying the lower one). */
  .demo-card__scrim{display:none}
  .demo-card__cta{
    /* relative + z-index so the buttons stay above anything absolutely
       positioned inside the card, belt and braces alongside pointer-events */
    position:relative;
    z-index:1;
    flex-direction:column;
    gap:12px;
    padding:var(--sp-3);
  }
  .demo-card__cta .action{
    flex:0 0 auto;
    max-width:none;
    width:100%;
    background:transparent;
    border:0;
    padding:0;
    -webkit-backdrop-filter:none;
            backdrop-filter:none;
  }
  .demo-card__cta .action__note{color:var(--text-dim)}
}
@media (max-width:560px){
  .demo-card .btn--lg{--btn-py:13px;--btn-px:16px;font-size:.74rem;white-space:normal}
  .demo-card__cta .action__note{font-size:.72rem}
}

/* =============================================================
   Cards / grid
   ============================================================= */
.grid-2{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(20px,2.6vw,32px);
}
@media (max-width:860px){
  .grid-2{grid-template-columns:minmax(0,1fr)}
}

.card{
  background:var(--panel);
  border:1px solid var(--line);
  border-radius:var(--radius);
  padding:clamp(20px,2.4vw,28px);
  transition:border-color .3s var(--ease),transform .3s var(--ease);
}
.card:hover{border-color:var(--line-strong)}
.card__title{
  font-size:1.24rem;
  letter-spacing:.7px;
  margin-bottom:var(--sp-3);
}
.card__text{
  color:var(--text-dim);
  font-size:.94rem;
  margin-top:var(--sp-3);
}

/* =============================================================
   Footer
   ============================================================= */
.footer{
  position:relative;
  border-top:1px solid var(--line);
  padding-block:clamp(52px,7vw,78px);
  background:linear-gradient(180deg,rgba(255,255,255,.014),transparent 60%);
}
.footer__grid{
  display:grid;
  grid-template-columns:1.5fr 1fr 1fr;
  gap:clamp(28px,4vw,54px);
  align-items:start;
}
@media (max-width:760px){
  .footer__grid{grid-template-columns:minmax(0,1fr);gap:34px}
}

.brand--footer .brand__name{
  display:inline;
  font-size:20px;
}
.footer__copy{
  margin-top:var(--sp-3);
  color:var(--text-faint);
  font-size:.85rem;
}
.footer__heading{
  font-size:.98rem;
  letter-spacing:1.4px;
  color:var(--text);
  margin-bottom:var(--sp-3);
}
.footer__list li + li{margin-top:8px}
.footer__list a{
  font-size:.94rem;
  color:var(--green);
  word-break:break-word;
}
.footer__list a:hover{text-decoration:underline;text-underline-offset:3px}

/* =============================================================
   Scroll reveal
   Only engages when JS can actually run and motion is welcome —
   so a no-JS visitor still sees everything.
   ============================================================= */
@media (prefers-reduced-motion:no-preference){
  .js-reveal .reveal{
    opacity:0;
    transform:translateY(18px);
    transition:opacity .7s var(--ease),transform .7s var(--ease);
    will-change:opacity,transform;
  }
  .js-reveal .reveal.is-visible{
    opacity:1;
    transform:none;
    will-change:auto;      /* release the compositor layer once revealed */
  }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
  .scrollcue__chev{animation:none}
  .btn:hover,.demo-card:hover .demo-card__img,
  .yt-facade:hover .yt-facade__thumb,
  .yt-facade:hover .yt-facade__play{transform:none}
  .demo-card:hover .btn--static{transform:none}
  .yt-facade:hover .yt-facade__play{transform:translate(-50%,-50%)}
}

/* ---------- Very wide screens ---------- */
@media (min-width:1700px){
  /* Scale the ROOT: every size on the page is rem-based, so body{font-size}
     would not move any of it. */
  :root{--maxw:1320px; font-size:18px}
}

/* =============================================================
   Long-form copy ("What it does") + Read more expander
   ============================================================= */
.prose{
  position:relative;
  max-width:74ch;
  margin-top:var(--sp-5);
  color:var(--text-dim);
  font-size:1rem;
  line-height:1.72;
}
.prose > * + *{margin-top:var(--sp-3)}
.prose strong{color:var(--text);font-weight:600}
.prose code{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:.9em;
  padding:1px 6px;
  border-radius:5px;
  background:rgba(255,255,255,.05);
  color:var(--text);
}
.prose h3{
  margin-top:var(--sp-6);
  font-size:clamp(1.2rem,2.4vw,1.55rem);
  color:var(--text);
}
.prose h4{
  margin:0 0 6px;
  font-family:var(--font-body);
  font-weight:700;
  font-size:1rem;
  letter-spacing:0;
  text-transform:none;
  color:var(--text);
}
.prose__lead{font-size:1.06rem}
.prose__closing{
  margin-top:var(--sp-5);
  padding-left:16px;
  border-left:2px solid var(--green-deep);
  color:var(--text);
}
.emoji,.card__icon{font-size:1.1em;line-height:1}

/* three feature cards */
.cards{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
  gap:14px;
}
.card{
  padding:20px;
  background:var(--panel);
  border:1px solid var(--line);
  border-radius:var(--radius);
}
.card p{margin:0;font-size:.94rem}
.card__icon{margin-bottom:10px !important;font-size:1.5rem}

/* use-case definition list */
.deflist dt{
  margin-top:var(--sp-3);
  font-weight:700;
  color:var(--text);
}
.deflist dd{margin:4px 0 0;padding-left:26px}

/* bulleted lists with a green tick/dot */
.ticks li{position:relative;padding-left:24px}
.ticks li + li{margin-top:9px}
.ticks li::before{
  content:"";
  position:absolute;
  left:4px;
  top:.65em;
  width:7px;height:7px;
  border-radius:50%;
  background:var(--green);
}
.ticks--plain li::before{background:var(--text-faint);width:5px;height:5px;left:5px}

/* ---------- Read more ----------
   Collapsed state is applied by a class that site.js sets, NOT by default CSS:
   if the script fails to run the whole section must stay readable rather than
   be permanently clipped. mask-image fades the CONTENT to transparent, so it
   works over any backdrop - an overlay gradient would need to know the page
   background, which changes down the page. */
.readmore{display:none}

.js-collapse .prose{
  max-height:26rem;
  overflow:hidden;
  -webkit-mask-image:linear-gradient(180deg,#000 58%,transparent 100%);
          mask-image:linear-gradient(180deg,#000 58%,transparent 100%);
}
.js-collapse .prose.is-open{
  max-height:none;
  -webkit-mask-image:none;
          mask-image:none;
}

.js-collapse .readmore{
  display:inline-flex;
  align-items:center;
  gap:9px;
  margin-top:var(--sp-4);
  padding:11px 20px;
  background:rgba(255,255,255,.02);
  border:1px solid var(--line-strong);
  border-radius:10px;
  color:var(--text);
  font-weight:700;
  font-size:.82rem;
  letter-spacing:.9px;
  text-transform:uppercase;
  cursor:pointer;
  transition:border-color .22s var(--ease),background-color .22s var(--ease),
             transform .22s var(--ease);
}
.js-collapse .readmore:hover{
  border-color:rgba(69,198,74,.55);
  background:rgba(69,198,74,.08);
  transform:translateY(-2px);
}
.readmore__chev{
  flex:none;
  color:var(--green);
  transition:transform .28s var(--ease);
}
.readmore[aria-expanded="true"] .readmore__chev{transform:rotate(180deg)}

@media (prefers-reduced-motion:reduce){
  .readmore,.readmore__chev{transition:none}
  .js-collapse .readmore:hover{transform:none}
}

/* =============================================================
   Sale ribbon - fixed to the top-right corner of the viewport
   -------------------------------------------------------------
   Geometry: a square box clipped at the corner, with a band rotated
   45deg across it. For the band to sit centred on the corner's
   diagonal, its centre must land at (--ribbon/2) in from both edges -
   hence `top: 50% of the box minus half the band height` and
   `right: -50% of the box`. The band is given an explicit height so
   that sum stays exact instead of drifting with the font metrics.
   ============================================================= */
:root{
  --ribbon:252px;      /* how far the ribbon reaches along each edge */
  --ribbon-h:72px;     /* band thickness */
}

.saleribbon{
  position:fixed;
  top:0;
  right:0;
  width:var(--ribbon);
  height:var(--ribbon);
  overflow:hidden;
  z-index:120;                 /* over the topbar (100), under skip-link (200) */
  pointer-events:none;         /* the clipped corner must not eat clicks */
}

.saleribbon__band{
  pointer-events:auto;         /* ...but the band itself is a link */
  position:absolute;
  width:calc(var(--ribbon) * 2);
  height:var(--ribbon-h);
  top:calc(var(--ribbon) / 2 - var(--ribbon-h) / 2);
  right:calc(var(--ribbon) / -2);
  transform:rotate(45deg);

  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:3px;

  /* Amber, not green: the CTAs are green, and a promo badge in the same
     colour reads as just another button instead of a price change. */
  background:linear-gradient(180deg,#FFA645,var(--amber-deep));
  color:#2A1400;
  box-shadow:0 8px 28px rgba(0,0,0,.52),inset 0 2px 0 rgba(255,255,255,.4);
  text-shadow:0 1px 0 rgba(255,255,255,.25);
  transition:filter .2s var(--ease);
}
.saleribbon:hover .saleribbon__band,
.saleribbon:focus-visible .saleribbon__band{filter:brightness(1.08)}
.saleribbon:focus-visible{outline:none}
.saleribbon:focus-visible .saleribbon__band{
  box-shadow:0 0 0 3px var(--green-bright),0 6px 20px rgba(0,0,0,.5);
}

.saleribbon__now{
  font-weight:800;
  font-size:22px;
  line-height:1;
  letter-spacing:.3px;
  white-space:nowrap;
}
.saleribbon__was{
  font-weight:600;
  font-size:17px;
  line-height:1;
  opacity:.72;
  white-space:nowrap;
}

/* Screen readers get "was EUR 55.19"; sighted users get the strike-through. */
.saleribbon__sr{
  position:absolute;
  width:1px;height:1px;
  padding:0;margin:-1px;
  overflow:hidden;
  clip-path:inset(50%);
  white-space:nowrap;
  border:0;
}

/* The topbar CTA is right-aligned inside a centred, max-width container, so
   the distance from it to the viewport edge is its own padding PLUS whatever
   the centring already contributes. Subtract the latter, or wide screens get
   pushed twice as far left as they need to be. */
.topbar__inner{
  padding-right:max(
    var(--pad-x),
    calc(var(--ribbon) + 22px - max(0px, (100vw - var(--maxw)) / 2))
  );
}
/* The button is right-aligned, so its long form grows LEFTWARD and never
   encroaches on the ribbon - only the total width of brand + nav + button
   does. Keep the full wording while that still fits. */
@media (max-width:1380px){
  .topbar__cta .btn__long{display:none}
}
/* The ribbon still claims a good slice of the topbar on a small laptop. The
   nav links are duplicated further down the page, so they are what yields -
   this raises the threshold of the existing 860px rule. */
@media (max-width:1099px){
  .nav{display:none}
  .topbar__cta{margin-left:auto}
}

@media (max-width:1380px){
  :root{--ribbon:225px;--ribbon-h:65px}
  .saleribbon__now{font-size:19.5px}
  .saleribbon__was{font-size:15px}
}
@media (max-width:1100px){
  :root{--ribbon:180px;--ribbon-h:53px}
  .saleribbon__now{font-size:16px}
  .saleribbon__was{font-size:12px}
}
@media (max-width:760px){
  :root{--ribbon:135px;--ribbon-h:41px}
  .saleribbon__now{font-size:12px;letter-spacing:0}
  .saleribbon__was{font-size:9.5px}
}
@media (max-width:420px){
  :root{--ribbon:108px;--ribbon-h:33px}
  .saleribbon__now{font-size:10px}
  .saleribbon__was{font-size:8px}
}

/* Printing a fixed corner overlay just stamps it over the first page. */
@media print{ .saleribbon{display:none} }

/* =============================================================
   Miniature sale flash - the corner ribbon, shrunk onto a button
   -------------------------------------------------------------
   Same two-part construction as .saleribbon: a square clipper at the
   corner, and a band of height --flash-h rotated 45deg inside it,
   centred at --flash/2 in from both edges so it sits square across
   that corner.

   The CLIPPER carries overflow:hidden, not the button. Putting it on
   the button instead looks identical until a label is too long for
   its container - .action caps the hero button at 19rem while the
   label wants ~22rem - and then the button silently crops its own
   text. Clipping only the badge leaves the label exactly as it was.

   aria-hidden: every button carrying this goes to the same store
   page and the full-size ribbon already announces the sale, so
   repeating "minus fifty percent" would only pad the link names.
   ============================================================= */
.btn--sale{
  position:relative;
  --flash:34px;      /* reach along each edge */
  --flash-h:14px;    /* band thickness */
}
.btn__sale{
  position:absolute;
  top:0;
  right:0;
  width:var(--flash);
  height:var(--flash);
  overflow:hidden;
  border-top-right-radius:inherit;   /* follow whatever radius the button has */
  pointer-events:none;               /* the whole button is already the link */
}
.btn__sale-band{
  position:absolute;
  width:calc(var(--flash) * 2);
  height:var(--flash-h);
  top:calc(var(--flash) / 2 - var(--flash-h) / 2);
  right:calc(var(--flash) / -2);
  transform:rotate(45deg);

  display:flex;
  align-items:center;
  justify-content:center;

  background:linear-gradient(180deg,#FFA645,var(--amber-deep));
  color:#2A1400;
  font-size:7.5px;
  font-weight:800;
  line-height:1;
  letter-spacing:.2px;
  text-shadow:0 1px 0 rgba(255,255,255,.28);
}

/* Hero and demo buttons are taller, so the flash scales with them. */
.btn--lg.btn--sale{--flash:48px;--flash-h:18px}
.btn--lg.btn--sale .btn__sale-band{font-size:9px}

/* Against the green primary a hairline keeps the two accents apart. */
.btn--primary.btn--sale .btn__sale-band{
  box-shadow:0 0 0 1px rgba(11,13,14,.2);
}

@media (max-width:560px){
  .topbar__cta.btn--sale{--flash:29px;--flash-h:12px}
  .topbar__cta.btn--sale .btn__sale-band{font-size:6.5px}
}
