/* ============================================================
   build.contrapaul.com: layout, frames, motion
   ------------------------------------------------------------
   Every tab is a stack of .frame sections. On a wide screen a
   frame is one viewport tall and is a slide; on a phone frames
   read as one long page. js/deck.js steps between them.

   Motion: an element with [data-reveal] arrives the first time
   its frame is on screen, then stays (reveal-once, as in
   make/localai). A headline with [data-words] arrives a word at
   a time. --i staggers siblings. js/deck.js sets --p (-1 to 1)
   on frames while scrolling, for the drift between frames.
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

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

@media (min-width: 900px) and (hover: hover) {
  html.is-talk { scroll-snap-type: y proximity; }
}
html.is-tweening { scroll-snap-type: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: clamp(17px, 1.05vw + 8px, 22px);
  line-height: 1.5;
  overflow-x: hidden;
}

/* Film grain over everything: an inline SVG, so nothing is fetched. */
body::after {
  content: '';
  position: fixed;
  inset: -50%;
  pointer-events: none;
  z-index: 60;
  opacity: var(--grain-opacity);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}

a { color: inherit; }
img, video { max-width: 100%; display: block; }
code, kbd, .mono { font-family: var(--font-mono); font-size: .86em; }
code { background: var(--code-bg); padding: .08em .35em; border-radius: 4px; }
kbd { border: 1px solid var(--line-strong); border-bottom-width: 2px; padding: .05em .4em; border-radius: 5px; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* ---------- top bar ------------------------------------------ */

.bar {
  position: fixed; inset: 0 0 auto 0; z-index: 40;
  height: var(--bar-h);
  display: flex; align-items: center; gap: 18px;
  padding: 0 clamp(14px, 3vw, 36px);
  background: linear-gradient(to bottom, color-mix(in srgb, var(--bg) 92%, transparent), transparent);
  transition: opacity .5s var(--ease-out), transform .5s var(--ease-out);
}
html.is-presenting .bar { opacity: 0; transform: translateY(-100%); pointer-events: none; }
html.is-presenting .bar:focus-within { opacity: 1; transform: none; pointer-events: auto; }

.brand {
  font-family: var(--font-display); font-weight: 900; font-size: 22px;
  letter-spacing: .02em; text-transform: uppercase; text-decoration: none;
  white-space: nowrap;
}
.brand span { color: var(--muted); font-weight: 600; }

.bar nav { flex: 1; min-width: 0; }
.tabs {
  display: flex; gap: 4px; margin: 0; padding: 0; list-style: none;
  overflow-x: auto; scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs a {
  display: block; padding: 6px 12px; border-radius: 999px;
  font-family: var(--font-display); font-weight: 800; font-size: 17px;
  letter-spacing: .06em; text-transform: uppercase; text-decoration: none;
  color: var(--muted); white-space: nowrap;
  transition: color .3s, background .3s;
}
.tabs a:hover { color: var(--ink); }
.tabs a.is-active { color: var(--bg); background: var(--ink); }
.tabs a kbd { font-size: 11px; margin-left: 6px; opacity: .55; border-color: currentColor; }

.theme-toggle {
  flex: none;
  border: 1px solid var(--line-strong); background: transparent; color: var(--ink);
  border-radius: 999px; padding: 6px 12px; font: 600 14px var(--font-body); cursor: pointer;
}

@media (max-width: 640px) {
  .bar { gap: 10px; }
  .brand span, .tabs a kbd { display: none; }
  .tabs { gap: 0; }
  .tabs a { padding: 6px 6px; font-size: 15px; letter-spacing: .02em; }
  .theme-toggle { padding: 5px 9px; font-size: 13px; }
}

/* ---------- tab panels and frames ----------------------------- */

.tab-panel { display: none; }
.tab-panel.is-active { display: block; }

.frame {
  --hue: var(--hue-intro);
  --p: 0;
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  padding: calc(var(--bar-h) + 4vh) var(--gutter) 7vh;
  display: grid;
  align-content: center;
  /* clip, not hidden: a hidden box can still be scrolled internally (focusing
     a link inside it does that), which slid a whole frame up by 167px. */
  overflow: hidden;
  overflow: clip;
  scroll-snap-align: start;
  isolation: isolate;
}

/* The glow: a slow radial bloom in the section's hue. */
.frame::before {
  content: '';
  position: absolute; inset: -20%;
  z-index: -1;
  background:
    radial-gradient(40% 50% at var(--gx, 78%) var(--gy, 22%), color-mix(in srgb, var(--hue) calc(var(--glow-strength) * 100%), transparent), transparent 70%),
    radial-gradient(35% 45% at 12% 88%, color-mix(in srgb, var(--hue) calc(var(--glow-strength) * 45%), transparent), transparent 70%);
  animation: drift 26s var(--ease-in-out) infinite alternate;
}
@keyframes drift {
  from { transform: translate3d(-2%, -1%, 0) scale(1); }
  to   { transform: translate3d(2%, 2%, 0) scale(1.08); }
}

/* Drift between frames, set from scroll by js/deck.js (wide screens). */
.frame > .inner {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  transform: translate3d(0, calc(var(--p) * -7vh), 0) scale(calc(1 - (var(--pa, 0) * .05)));
  opacity: calc(1 - (var(--pa, 0) * .55));
  will-change: transform, opacity;
}

.frame.is-divider .inner { text-align: left; }

/* Frame number, for the presenter. */
.frame-no {
  position: absolute; right: var(--gutter); bottom: 3.2vh;
  font: 700 13px var(--font-mono); letter-spacing: .12em; color: var(--muted);
}

/* ---------- type --------------------------------------------- */

.kicker {
  font: 700 clamp(12px, .8vw + 6px, 16px) var(--font-mono);
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--hue);
  margin: 0 0 2.2vh;
}

.display, .h1, .h2 {
  font-family: var(--font-display);
  text-transform: uppercase;
  line-height: .9;
  letter-spacing: -.005em;
  margin: 0;
  text-wrap: balance;
}
.display { font-weight: 900; font-size: clamp(56px, 10.5vw, 196px); }
.h1 { font-weight: 900; font-size: clamp(44px, 7vw, 132px); }
.h2 { font-weight: 800; font-size: clamp(34px, 4.6vw, 86px); line-height: .95; }
.h3 {
  font-family: var(--font-display); font-weight: 800; text-transform: uppercase;
  font-size: clamp(24px, 2.4vw, 44px); line-height: 1; margin: 0 0 .5em; letter-spacing: .01em;
}
.accent { color: var(--hue); }
.outline { color: transparent; -webkit-text-stroke: 2px var(--ink); }

.lede {
  font-size: clamp(22px, 2vw + 6px, 44px);
  line-height: 1.25; font-weight: 500;
  max-width: 34ch; margin: 3vh 0 0; color: var(--ink-soft);
  text-wrap: pretty;
}
.big-list {
  list-style: none; margin: 4vh 0 0; padding: 0;
  font-size: clamp(22px, 1.7vw + 8px, 42px); font-weight: 500; line-height: 1.25;
}
.big-list li { padding: .45em 0; border-top: 1px solid var(--line); }
.big-list li:last-child { border-bottom: 1px solid var(--line); }
.big-list b { color: var(--hue); font-weight: 600; }

ol.steps { counter-reset: s; list-style: none; padding: 0; margin: 3vh 0 0; }
ol.steps > li {
  counter-increment: s; position: relative; padding: .5em 0 .5em 2.6em;
  border-top: 1px solid var(--line); font-size: clamp(20px, 1.3vw + 8px, 34px); line-height: 1.3;
}
ol.steps > li::before {
  content: counter(s, decimal-leading-zero);
  position: absolute; left: 0; top: .62em;
  font: 700 .62em var(--font-mono); color: var(--hue);
}

.prose { max-width: 70ch; }
.prose p, .prose li { color: var(--ink-soft); }
.prose h3 { margin-top: 1.6em; }

/* ---------- glossary links ------------------------------------ */

a.gloss {
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-color: color-mix(in srgb, var(--hue) 75%, transparent);
  text-decoration-thickness: .08em;
  text-underline-offset: .14em;
  cursor: help;
}
a.gloss:hover, a.gloss:focus-visible { color: var(--hue); outline: none; }

#gloss-tip {
  position: fixed; z-index: 80;
  width: min(420px, calc(100vw - 24px));
  padding: 16px 18px;
  background: var(--card);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  box-shadow: var(--shadow);
  font-size: 18px; line-height: 1.45; color: var(--ink);
  opacity: 0; transform: translateY(6px); pointer-events: none;
  transition: opacity .18s, transform .25s var(--ease-out);
}
#gloss-tip.is-visible { opacity: 1; transform: none; }
#gloss-tip strong {
  display: block; margin-bottom: 4px;
  font: 800 15px var(--font-display); letter-spacing: .1em; text-transform: uppercase; color: var(--hue-glossary);
}
#gloss-tip .tip-more { display: block; margin-top: 8px; font: 700 12px var(--font-mono); letter-spacing: .08em; color: var(--muted); }

/* ---------- reveal motion ------------------------------------- */

[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 34px, 0);
  filter: blur(6px);
  transition:
    opacity .9s var(--ease-out),
    transform 1.1s var(--ease-out),
    filter .9s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 110ms + var(--d, 0ms));
}
[data-reveal='left'] { transform: translate3d(-48px, 0, 0); }
[data-reveal='right'] { transform: translate3d(48px, 0, 0); }
[data-reveal='zoom'] { transform: scale(.92); }
.frame.is-in [data-reveal] { opacity: 1; transform: none; filter: none; }

/* Words of a headline rise out of a mask, one after another. */
.w { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: .06em; margin-bottom: -.06em; }
.w > span {
  display: inline-block;
  transform: translate3d(0, 105%, 0);
  transition: transform 1s var(--ease-out);
  transition-delay: calc(var(--wi, 0) * 70ms + var(--d, 0ms));
}
.frame.is-in .w > span { transform: none; }

/* Before JS runs, nothing is hidden. */
html:not(.js) [data-reveal] { opacity: 1; transform: none; filter: none; }
html:not(.js) .w > span { transform: none; }

/* ---------- rail, counter, blank ------------------------------ */

.rail {
  position: fixed; right: 14px; top: 50%; z-index: 30;
  transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 7px;
  transition: opacity .4s;
}
.rail button {
  width: 8px; height: 8px; padding: 0; border-radius: 50%;
  border: 1px solid var(--line-strong); background: transparent; cursor: pointer;
  transition: background .3s, transform .3s var(--ease-out), border-color .3s;
}
.rail button.is-past { background: var(--line-strong); border-color: transparent; }
.rail button.is-current { background: var(--ink); border-color: var(--ink); transform: scale(1.45); }
.rail.is-dense { gap: 4px; }
.rail.is-dense button { width: 6px; height: 6px; }
@media (max-width: 760px) { .rail { display: none; } }

.progress {
  position: fixed; left: 0; bottom: 0; height: 3px; z-index: 30;
  width: calc(var(--progress, 0) * 100%);
  background: var(--hue-cur, var(--ink));
  transition: width .5s var(--ease-out), background .5s;
}

#blank {
  position: fixed; inset: 0; z-index: 100; background: #000;
  opacity: 0; pointer-events: none; transition: opacity .35s;
}
html.is-blank #blank { opacity: 1; pointer-events: auto; cursor: none; }

/* ---------- placeholders (Paul fills these in) ---------------- */

.ph {
  display: grid; place-items: center; text-align: center;
  min-height: 22vh; padding: 3vh 2vw;
  border: 2px dashed color-mix(in srgb, var(--hue) 55%, transparent);
  border-radius: 18px;
  background: var(--placeholder);
  color: var(--muted);
  font: 600 clamp(14px, 1vw + 6px, 20px) var(--font-mono);
  letter-spacing: .02em;
}
.ph::before {
  content: 'TO ADD';
  display: block; margin-bottom: .6em;
  font-size: .7em; letter-spacing: .2em; color: var(--hue);
}
.fill { color: var(--hue); }

/* ---------- footer -------------------------------------------- */

.site-foot {
  padding: 5vh var(--gutter) 6vh;
  border-top: 1px solid var(--line);
  color: var(--muted); font-size: 15px;
}
.site-foot p { margin: .3em 0; max-width: 80ch; }

/* ---------- reduced motion ------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  .frame::before { animation: none; }
  .frame > .inner { transform: none !important; opacity: 1 !important; }
  [data-reveal] { transform: none !important; filter: none !important; transition: opacity .3s; transition-delay: 0s; }
  .w > span { transform: none !important; transition: none; }
}

@media print {
  .bar, .rail, .progress, #blank, #gloss-tip, body::after { display: none !important; }
  .tab-panel { display: block !important; }
  .frame { min-height: auto; break-inside: avoid; }
  [data-reveal], .w > span { opacity: 1 !important; transform: none !important; filter: none !important; }
}
