/* ============================================================
   CreativeDigital — MASTER STYLESHEET
   Load order matters: tokens first, then base, then components.
   This file = tokens + reset + base layout only.
   Components live in site.css.
   ============================================================ */

@import url("tokens/colors.css?v=87b0357cdd");
@import url("tokens/typography.css?v=87b0357cdd");
@import url("tokens/spacing.css?v=87b0357cdd");
@import url("site.css?v=87b0357cdd");

/* ---------- reset ---------- */
*,*::before,*::after{box-sizing:border-box}
/* Kills the browser's own translucent grey tap-highlight on mobile. Without
   this, every tap flashes a default grey overlay over our own colours before
   our real :active state can be seen, which is what read as "grey with black
   text" — it was never our button colour, it was the OS's tap feedback
   sitting on top of it. We provide our own tap feedback everywhere on
   purpose, so the default one only ever gets in the way. */
*{-webkit-tap-highlight-color:transparent}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}

body{
  margin:0;
  background:var(--bg);
  color:var(--ink);
  font-family:var(--font-body);
  font-size:16px;
  line-height:var(--lh-body);
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  /* overflow-x lives on <html> only (see site.css). Setting it on both html
     and body makes the value propagate to the viewport and compute as hidden,
     which silently breaks every position:sticky on the site. */
}
body.no-scroll{overflow:hidden}

h1,h2,h3,h4,h5,h6{margin:0;font-weight:var(--fw-heavy)}
p,figure,ul,ol{margin:0}
ul,ol{padding:0;list-style:none}
img,svg,video{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button,input,textarea,select{font:inherit;color:inherit}
address{font-style:normal}

::selection{background:var(--accent);color:var(--accent-ink)}

:focus-visible{
  outline:2px solid var(--focus);
  outline-offset:3px;
}

/* ---------- skip link (a11y) ---------- */
.skip{
  position:absolute;left:-9999px;top:0;z-index:var(--z-toast);
  background:var(--accent);color:var(--accent-ink);
  padding:.75rem 1.25rem;font-family:var(--font-display);
  font-weight:var(--fw-heavy);text-transform:uppercase;font-size:var(--fs-xs);
}
.skip:focus{left:0}

/* ---------- layout primitives ---------- */
.wrap{
  width:100%;
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--gutter);
}
.wrap-narrow{max-width:1100px}

section{
  padding-block:var(--section-y);
  position:relative;
  background:var(--bg);
  color:var(--ink);
}
section.pad-lg{padding-block:var(--section-y-lg)}
section.pad-top-0{padding-top:0}
section.pad-bottom-0{padding-bottom:0}

.stack > * + *{margin-top:var(--s2)}
.stack-lg > * + *{margin-top:var(--s4)}

.hide{display:none !important}
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}

/* ---------- scroll reveal (base state) ---------- */
/* Subtler on purpose: a smaller rise with a faint settle-in scale reads as
   quality rather than "look, an animation." A 34px throw with a slow fade
   drew attention to the mechanic itself; this should be felt, not watched. */
/* NOTE the `.js` gate. These rules hide content until JS reveals it, so
   without the gate ANY script failure leaves the page blank — which is
   exactly what one unescaped apostrophe in site.js did: it killed the
   whole file and ~80% of the text vanished site-wide. The class is set by
   a tiny inline snippet in <head>, so the only way content stays hidden
   is if that one line runs AND the reveal system is alive. */
.js .rv{
  opacity:0;
  transform:translateY(16px) scale(.99);
  transition:opacity .6s var(--ease), transform .6s var(--ease);
}
.js .rv.in{opacity:1;transform:none}
/* Set together with .in to reveal without animating — used for above-the-fold
   content on every page after the first of a session, so a page transition
   dissolves into a finished page instead of one still moving. See the reveal
   block in build.py. */
.js .rv.now{transition:none}
.rv[data-d="1"]{transition-delay:.08s}
.rv[data-d="2"]{transition-delay:.16s}
.rv[data-d="3"]{transition-delay:.24s}
.rv[data-d="4"]{transition-delay:.32s}
.rv[data-d="5"]{transition-delay:.40s}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
  .js .rv{opacity:1;transform:none}
}

/* ---------- print ---------- */
@media print{
  .site-header,.site-footer,.wa-float,.mobile-bar,.modal-wrap{display:none !important}
  body{background:#fff;color:#000}
}
