/* ============================================================
   EN¿GMA — shared tokens: type, the CTA, the seal.
   Loaded before the page's own stylesheet.

   The progress button and the puzzle-log takeover used to live
   here. They moved into assets/js/progress.js, which injects its
   own stylesheet — that module also runs on shop.enigmamade.com,
   which does not load this file, and two copies of those rules in
   two repos would drift apart within a week.

   TYPE — read this before changing it.
   I could not extract Derivative's actual stack: headless Chrome
   gets zero bytes from derivative.ca, and the fetch tool returns
   text with the CSS stripped. Rather than claim a match I can't
   verify, this is a close pairing in the same register —
   Space Grotesk for headings (technical, a bit odd, not Oswald)
   and Inter for body. Both free. Swap the two --font vars and
   the whole estate follows.
   ============================================================ */
:root{
  /* No escaped quotes in here. The stray apostrophe in a font name closed
     the string early and swallowed the rest of the block, so BOTH custom
     properties came out empty and everything fell back to Times. */
  --font-display: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-body:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;

  --ease:cubic-bezier(.22,.61,.36,1);
  --spring:cubic-bezier(.16,1.02,.3,1);
  /* The try-on button's curve — slow at both ends, fast through the
     middle. It was written out longhand in reward.css; it now has a
     name because the puzzle rollovers use the same move, and the two
     should stay identical without anyone having to remember to keep
     four magic numbers in step. */
  --wipe:cubic-bezier(.76,0,.24,1);

  /* The emphasised numeral on the 26 grid: the one that arrives on
     hover and the one a spent key keeps. Sized against the viewport
     rather than fixed, because the key itself is — .code is a clamp of
     the short edge, so a fixed numeral that looks right on a laptop is
     a speck on a large screen. */
  --n-big:clamp(20px, 3.6vh, 30px);

  --cta:#1b6cf3;          /* the flat, confident blue of a "Get it now" */
  --cta-hi:#3d87ff;
}

/* ============================================================
   CTA — one button, borrowed in spirit from Derivative's
   "Get it now": flat colour, generous padding, tight radius,
   no gradient, no glow. It reads as a control rather than an
   ornament, which is what makes it look current.
   ============================================================ */
.cta-solid{
  display:inline-flex;align-items:center;gap:12px;
  padding:15px 30px;border:0;border-radius:4px;cursor:pointer;
  font-family:var(--font-body);
  font-size:13px;font-weight:600;letter-spacing:.01em;
  text-transform:none;text-decoration:none;
  color:#fff;background:var(--cta);
  transition:background 180ms var(--ease), transform 180ms var(--ease);
}
.cta-solid:hover{background:var(--cta-hi);transform:translateY(-1px)}
.cta-solid:active{transform:translateY(0)}
.cta-solid svg{
  width:15px;height:15px;fill:none;stroke:currentColor;
  stroke-width:2;stroke-linecap:round;stroke-linejoin:round;
  transition:transform 260ms var(--spring);
}
.cta-solid:hover svg{transform:translateX(3px)}

.cta-ghost{
  display:inline-flex;align-items:center;gap:10px;
  padding:14px 26px;border-radius:4px;cursor:pointer;
  border:1px solid rgba(255,255,255,.28);background:transparent;
  font-family:var(--font-body);font-size:13px;font-weight:500;
  color:rgba(255,255,255,.78);text-decoration:none;
  transition:border-color 180ms var(--ease), color 180ms var(--ease);
}
.cta-ghost:hover{border-color:rgba(255,255,255,.7);color:#fff}
@media (prefers-reduced-motion:reduce){
  *{transition-duration:.01ms !important}
}

/* ============================================================
   THE HEADER — one definition, every page.

   It used to be declared separately in home.css and team.css
   with different padding and a different --pad, so the mark and
   the menu jumped several pixels when you crossed from a puzzle
   to Collab. Now both pages inherit this and neither restates
   the geometry.

   The whole bar is pointer-events:none with the links switched
   back on. It is a fixed, full-width element that is mostly
   empty space, and on Collab that empty space was sitting over
   the top row of rider tiles and swallowing every click on them.
   ============================================================ */
.nav{
  position:fixed;top:0;left:0;right:0;z-index:50;
  display:flex;align-items:flex-start;justify-content:space-between;
  gap:20px;
  padding:34px clamp(18px,4vw,64px) 0;
  pointer-events:none;
}
.nav a,.nav button{pointer-events:auto}

/* ---------- the veil ----------
   On the pages whose content runs up under the fixed header, the header
   needs something to sit on or the two collide and the menu is read as
   part of whatever scrolled behind it. This is that something: a soft
   fall-off from the top of the page, painted underneath the links
   (z-index:-1 inside the header's own stacking context) and never in the
   way of a click.

   Opt-in with class="nav veil", because the puzzle pages are single
   full-bleed photographs and a black wash across the top of one is a
   smudge, not a header. */
.nav.veil::before{
  content:'';
  position:absolute;top:0;left:0;right:0;
  /* past the header's own box, so the gradient has room to reach zero
     rather than ending on a visible edge */
  height:calc(100% + 54px);
  background:linear-gradient(to bottom,
    rgba(0,0,0,.92) 0%,
    rgba(0,0,0,.70) 42%,
    rgba(0,0,0,.30) 72%,
    transparent 100%);
  pointer-events:none;
  z-index:-1;
}
.nav a{color:inherit;text-decoration:none}
.nav .mark{width:60px;fill:#fff;filter:drop-shadow(0 2px 14px rgba(0,0,0,.65))}

.nav nav{padding-top:16px}
.nav ul{
  display:flex;align-items:baseline;gap:clamp(16px,2.4vw,30px);
  list-style:none;margin:0;padding:0;
}
.nav ul a{
  position:relative;display:inline-block;padding:6px 0;
  font-family:var(--font-body);
  font-size:10.5px;letter-spacing:.28em;text-transform:uppercase;font-weight:500;
  color:rgba(255,255,255,.72);text-shadow:0 1px 12px rgba(0,0,0,.7);
  transition:color .24s var(--ease);
}
.nav ul a:hover,
.nav ul a[aria-current="page"]{color:#fff}
/* The rule wipes in from the left on hover and simply stays put on the
   page you are already on — same behaviour as the shop's header, so the
   two sites feel like one estate. */
.nav ul a::after{
  content:'';position:absolute;left:0;right:100%;bottom:0;height:1px;
  background:currentColor;
  transition:right 380ms var(--ease);
}
.nav ul a:hover::after,
.nav ul a[aria-current="page"]::after{right:0}

@media (max-width:479px){
  .nav{padding-top:26px}
  .nav .mark{width:46px}
  .nav ul{gap:16px}
  .nav ul a{font-size:10px;letter-spacing:.18em}
}

/* ============================================================
   Sequential load-in.

   Pure CSS for the same reason as the shop's: the stylesheet blocks
   render, so the from-state is up at first paint and the page never
   flashes finished before it animates. Nothing here needs script, so
   nothing here can leave a page blank if script fails.
   ============================================================ */
@media (prefers-reduced-motion: no-preference){
  @keyframes seq-in  { from{opacity:0;transform:translateY(12px)} to{opacity:1;transform:none} }
  @keyframes seq-fade{ from{opacity:0} to{opacity:1} }

  body > header.nav{ animation:seq-fade .5s ease-out backwards; animation-delay:.06s }
  body > footer.footer{ animation:seq-fade .5s ease-out backwards; animation-delay:.30s }

  /* The puzzle stage is a stack of absolutely positioned slides that the
     home script shows and hides by hand, and it runs its own intro
     besides. Everything under #stage is excluded below — an earlier
     version of this block staggered its children, which meant the two
     slides that are meant to stay hidden animated up to full opacity
     and then snapped back to nothing. That was the flash of half a
     puzzle on every first load. */

  /* Everything else is in normal flow and can stagger. */
  main.select > *,
  main.section:not(#stage) > *,
  .wrap > .stage,
  .copy > *{ animation:seq-in .62s cubic-bezier(.22,.68,.24,1) backwards }

  .reveal{ animation:none }

  .wrap > .stage{ animation-delay:.10s }

  main.select > *:nth-child(1),
  main.section:not(#stage) > *:nth-child(1){ animation-delay:.08s }
  main.select > *:nth-child(2),
  main.section:not(#stage) > *:nth-child(2){ animation-delay:.18s }
  main.select > *:nth-child(3),
  main.section:not(#stage) > *:nth-child(3){ animation-delay:.28s }
  main.select > *:nth-child(n+4),
  main.section:not(#stage) > *:nth-child(n+4){ animation-delay:.36s }

  /* The reward pages read top to bottom — eyebrow, name, the paragraph,
     the facts, then the button. Worth taking its time over. */
  .copy > *:nth-child(1){ animation-delay:.22s }
  .copy > *:nth-child(2){ animation-delay:.32s }
  .copy > *:nth-child(3){ animation-delay:.42s }
  .copy > *:nth-child(4){ animation-delay:.52s }
  .copy > *:nth-child(5){ animation-delay:.62s }
  .copy > *:nth-child(6){ animation-delay:.72s }
  .copy > *:nth-child(n+7){ animation-delay:.80s }
}

/* ---------- the entrance shared with the seal ----------
   The seal is appended by script rather than parsed with the page,
   so the delay runs from the moment it is inserted, not from load.
   It comes in last, after the page has settled.

   Named `prog-enter` because the progress button used it first. The
   button now brings its own copy (`pz-enter`) from progress.js; this
   one stays because the seal still animates with it. */
@media (prefers-reduced-motion: no-preference){
  @keyframes prog-enter{ from{opacity:0;transform:translateY(14px) scale(.9)} to{opacity:1;transform:none} }
}

/* ============================================================
   THE SEAL — bottom left, links to the certificate page.

   Sized and placed to mirror the progress button in the opposite
   corner, so the two read as a pair of controls rather than as two
   unrelated blobs. Quiet by default: this is a way through for
   someone already curious, not a call to action.
   ============================================================ */
.seal{
  position:fixed;left:clamp(14px,2.4vw,28px);bottom:clamp(14px,2.4vw,28px);
  z-index:200;
  width:58px;height:58px;display:block;
  color:rgba(255,255,255,.55);
  transition:color 260ms var(--ease), transform 400ms var(--spring);
}
.seal:hover,.seal:focus-visible{ color:#fff;transform:scale(1.06) }
.seal:focus-visible{ outline:1px solid #fff;outline-offset:4px;border-radius:50% }
.seal svg{ width:100%;height:100%;display:block;overflow:visible }

.seal-legend{
  font-family:var(--font-body);
  font-size:8.4px;font-weight:600;letter-spacing:.06em;
  fill:currentColor;
}
/* Hairlines, not outlines. vector-effect keeps them one pixel however
   the SVG is scaled — without it a 58px render of a 100-unit viewBox
   draws them at 0.58px and they turn to grey mush. */
.seal-hair{
  fill:none;stroke:currentColor;stroke-width:1;
  vector-effect:non-scaling-stroke;opacity:.4;
  transition:opacity 260ms var(--ease);
}
.seal:hover .seal-hair{ opacity:.7 }
.seal-mark{ fill:currentColor }

@media (prefers-reduced-motion: no-preference){
  @keyframes seal-turn{ to{ transform:rotate(360deg) } }
  /* Slow enough to be a detail rather than a distraction — a full turn
     takes most of a minute. transform-box/origin are both needed: an
     SVG group's default origin is the user-space zero, not its own
     centre, so without them this orbits off screen. */
  .seal-turn{
    transform-box:view-box;transform-origin:50% 50%;
    animation:seal-turn 48s linear infinite;
  }
  .seal:hover .seal-turn{ animation-duration:12s }
}

/* It arrives with everything else rather than popping in on its own. */
@media (prefers-reduced-motion: no-preference){
  .seal{ animation:prog-enter .5s var(--spring) backwards; animation-delay:.5s }
}

