/* ==========================================================================
   SVTAC — svt.ac
   Production stylesheet. See DESIGN.md before changing anything visual.
   ========================================================================== */

:root {
  /* Surfaces */
  --bg:       #121316;   /* the plate */
  --backdrop: #0B0C0E;   /* behind the plate, visible outside the frame */

  /* Ink */
  --bone:  #E8E9E6;      /* matches the logo's native fill */
  --muted: #8B8D91;
  --faint: #5A5C61;

  /* Structure */
  --line: #26282D;

  /* Accent — used sparingly: CTA, focus, active states */
  --accent: #FFFFFF;
  --accent-dim: rgba(255, 255, 255, 0.28);

  /* Type. System stack by design: zero font requests, no FOUT.
     See DESIGN.md for the Inter / IBM Plex upgrade path. */
  --sans: "Segoe UI Variable Display", "Segoe UI", -apple-system,
          BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  --mono: "Cascadia Mono", ui-monospace, "SF Mono", "Menlo", Consolas, monospace;

  /* Motion */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --in: 900ms;

  /* Rhythm. Safe-area insets keep content clear of notches and home bars. */
  --pad: clamp(22px, 5vw, 68px);
  --pad-l: max(var(--pad), env(safe-area-inset-left));
  --pad-r: max(var(--pad), env(safe-area-inset-right));
  --maxw: 1240px;

  /* >>> GENERATED MASK — do not edit by hand; see tools/sync-mask.py */
  --wordmark-mask: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='16 16 559.58 93.85' role='img' aria-label='SVTAC'><title>SVTAC</title><path transform='translate(10.192 108.268)' fill='%23000' d='M47.52 1.58L47.52 1.58Q38.94 1.58 31.42 0.07Q23.89-1.45 18.15-4.88Q12.41-8.32 9.11-13.93Q5.81-19.54 5.81-27.72L5.81-27.72L5.81-28.91Q5.81-29.57 5.94-29.96L5.94-29.96L28.78-29.96Q28.78-29.57 28.71-28.97Q28.64-28.38 28.64-27.98L28.64-27.98Q28.64-23.76 30.82-21.19Q33-18.61 36.96-17.49Q40.92-16.37 46.20-16.37L46.20-16.37Q49.10-16.37 51.61-16.63Q54.12-16.90 56.10-17.56Q58.08-18.22 59.60-19.21Q61.12-20.20 61.84-21.58Q62.57-22.97 62.57-24.82L62.57-24.82Q62.57-27.85 60.26-29.83Q57.95-31.81 54.05-33.13Q50.16-34.45 45.28-35.64Q40.39-36.83 35.11-38.15Q29.83-39.47 24.95-41.45Q20.06-43.43 16.17-46.46Q12.28-49.50 9.97-54.05Q7.66-58.61 7.66-65.08L7.66-65.08Q7.66-72.20 10.69-77.42Q13.73-82.63 19.07-85.93Q24.42-89.23 31.42-90.75Q38.41-92.27 46.33-92.27L46.33-92.27Q54.12-92.27 60.92-90.68Q67.72-89.10 73.00-85.73Q78.28-82.37 81.25-77.29Q84.22-72.20 84.35-65.08L84.35-65.08L84.35-63.49L61.64-63.49L61.64-64.42Q61.64-67.45 59.99-69.76Q58.34-72.07 55.04-73.46Q51.74-74.84 46.86-74.84Q41.98-74.84 38.61-73.92Q35.24-73.00 33.46-71.28Q31.68-69.56 31.68-67.19L31.68-67.19Q31.68-64.28 33.99-62.44Q36.30-60.59 40.26-59.27Q44.22-57.95 49.10-56.83Q53.99-55.70 59.20-54.45Q64.42-53.20 69.30-51.28Q74.18-49.37 78.14-46.40Q82.10-43.43 84.41-39.07Q86.72-34.72 86.72-28.51L86.72-28.51Q86.72-17.69 81.64-11.09Q76.56-4.49 67.65-1.45Q58.74 1.58 47.52 1.58Z M177.91 0L150.46 0L117.85-90.68L143.20-90.68L159.83-39.47Q160.36-37.88 161.15-35.31Q161.94-32.74 162.80-30.03Q163.66-27.32 164.18-25.21L164.18-25.21L165.11-25.21Q165.77-27.19 166.49-29.77Q167.22-32.34 168.01-34.91Q168.80-37.49 169.33-39.34L169.33-39.34L185.96-90.68L210.38-90.68L177.91 0Z M292.46 0L268.84 0L268.84-71.28L239.40-71.28L239.40-90.68L321.90-90.68L321.90-71.28L292.46-71.28L292.46 0Z M374.68 0L350.39 0L384.44-90.68L412.82-90.68L446.88 0L421.67 0L416.26-15.71L380.09-15.71L374.68 0ZM392.36-52.54L385.76-33.40L410.45-33.40L403.98-52.54Q403.45-53.99 402.73-56.17Q402.00-58.34 401.27-60.79Q400.55-63.23 399.89-65.74Q399.23-68.24 398.57-70.09L398.57-70.09L397.64-70.09Q397.12-67.58 396.19-64.42L396.19-64.42L394.21-58.08Q393.16-54.91 392.36-52.54L392.36-52.54Z M523.42 1.58L523.42 1.58Q508.76 1.58 498.53-3.50Q488.30-8.58 483.02-19.01Q477.74-29.44 477.74-45.41L477.74-45.41Q477.74-68.90 489.56-80.59Q501.37-92.27 523.42-92.27L523.42-92.27Q535.69-92.27 545.20-88.11Q554.70-83.95 560.05-75.70Q565.39-67.45 565.39-55.18L565.39-55.18L542.29-55.18Q542.29-60.98 539.98-65.14Q537.67-69.30 533.51-71.54Q529.36-73.79 523.42-73.79L523.42-73.79Q516.02-73.79 511.27-70.75Q506.52-67.72 504.28-62.04Q502.03-56.36 502.03-48.31L502.03-48.31L502.03-42.37Q502.03-34.32 504.28-28.58Q506.52-22.84 511.21-19.87Q515.89-16.90 523.28-16.90L523.28-16.90Q529.62-16.90 534.04-19.01Q538.46-21.12 540.77-25.28Q543.08-29.44 543.08-35.24L543.08-35.24L565.39-35.24Q565.39-22.97 560.18-14.78Q554.96-6.60 545.53-2.51Q536.09 1.58 523.42 1.58Z'/></svg>");
  /* <<< END GENERATED MASK */
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */

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

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

body {
  margin: 0;
  background: var(--backdrop);
  color: var(--bone);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  /* Suppresses the grey flash on tap without removing any focus affordance. */
  -webkit-tap-highlight-color: transparent;
}

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

img, svg { max-width: 100%; }

.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;
}

.is-hidden { display: none !important; }

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

/* Mono micro-label — the workhorse of this design. */
.label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0;
}

/* Keyboard focus is always visible; pointer focus never is. */
a:focus-visible,
input:focus-visible,
button:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 3px;
  border-radius: 1px;
}

/* --------------------------------------------------------------------------
   The plate — an inset frame and vignette that make the page read as an
   object rather than a document.
   -------------------------------------------------------------------------- */

.frame {
  position: fixed;
  top:    max(clamp(10px, 1.4vw, 18px), env(safe-area-inset-top));
  right:  max(clamp(10px, 1.4vw, 18px), env(safe-area-inset-right));
  bottom: max(clamp(10px, 1.4vw, 18px), env(safe-area-inset-bottom));
  left:   max(clamp(10px, 1.4vw, 18px), env(safe-area-inset-left));
  border: 1px solid var(--line);
  pointer-events: none;
  z-index: 5;
}

.vignette {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background: radial-gradient(ellipse 90% 78% at 50% 44%,
              transparent 30%, rgba(0, 0, 0, 0.55) 100%);
}

/* Fine monochrome noise. The cheapest way to stop a flat dark page reading
   as a void. Above 4% it becomes visible as texture. */
.grain {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 6;
  opacity: 0.032;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  z-index: 2;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding-top: max(clamp(20px, 3.5vh, 34px), env(safe-area-inset-top));
  padding-bottom: clamp(20px, 3.5vh, 34px);
  overflow: hidden;
  /* Brushed-metal surface: a raking sheen over the base plate. */
  background:
    linear-gradient(115deg, rgba(255, 255, 255, 0.028) 0%, transparent 38%),
    var(--bg);
}

/* Fine directional grain, like a brushed finish. */
.hero__grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.75;
  background-image: repeating-linear-gradient(96deg,
    rgba(232, 233, 230, 0.020) 0 1px, transparent 1px 5px);
  -webkit-mask-image: radial-gradient(ellipse 80% 64% at 32% 46%, #000 0%, transparent 74%);
          mask-image: radial-gradient(ellipse 80% 64% at 32% 46%, #000 0%, transparent 74%);
}

.hero__bar {
  position: relative;
  display: flex;
  justify-content: space-between;
  gap: 16px;
}

.hero__core { position: relative; }
.hero__foot { position: relative; }

/* The SVG defines the box; .maskfill paints through it. */
.markblock {
  position: relative;
  display: block;
  width: min(58vw, 700px);
  max-width: 100%;
}

.wordmark { margin: 0; line-height: 0; }

.wordmark svg {
  display: block;
  width: 100%;
  height: auto;
  fill: var(--bone);
}

.maskfill {
  position: absolute;
  inset: 0;
  display: none;
  background-image: linear-gradient(102deg,
    #C6C8C5 0%, #C6C8C5 34%, #FFFFFF 46%, #FFFFFF 50%,
    #C6C8C5 62%, #A9ACA9 100%);
  background-size: 320% 100%;
  background-position: 100% 0;
  background-repeat: no-repeat;
}

/* Only swap to the painted wordmark where masking actually works. Anywhere
   else the plain bone SVG stays visible, so the logo can never vanish. */
@supports ((-webkit-mask-image: url("#m")) or (mask-image: url("#m"))) {
  .maskfill {
    display: block;
    -webkit-mask: var(--wordmark-mask) left center / contain no-repeat;
            mask: var(--wordmark-mask) left center / contain no-repeat;
  }
  .wordmark svg { visibility: hidden; }
}

.tagline {
  font-family: var(--mono);
  font-size: clamp(9.5px, 1.05vw, 12px);
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--muted);
  margin: clamp(18px, 2.4vw, 30px) 0 0;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Subscribe
   -------------------------------------------------------------------------- */

.signup { max-width: 460px; }
.signup__label { margin-bottom: 12px; }

.field {
  display: flex;
  align-items: center;
  gap: 14px;
  border-bottom: 1px solid var(--line);
  transition: border-color 460ms var(--ease);
}

.field:focus-within { border-bottom-color: var(--accent); }

.field input[type="email"] {
  flex: 1;
  min-width: 0;
  background: none;
  border: 0;
  color: var(--bone);
  font-family: var(--sans);
  /* 16px is a hard floor: any smaller and iOS Safari zooms the viewport on
     focus, which the user then has to pinch back out of. */
  font-size: 16px;
  letter-spacing: 0.01em;
  /* Touch target, not decoration. */
  padding: 12px 0;
}

.field input[type="email"]::placeholder { color: var(--faint); opacity: 1; }
.field input[type="email"]:focus { outline: none; }

.field button {
  flex: none;
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  transition: opacity 300ms var(--ease);
  /* 44px minimum touch target per WCAG 2.5.5 / Apple HIG. */
  min-height: 44px;
  padding: 0 4px;
}

.field button:hover { opacity: 0.62; }
.field button:disabled { opacity: 0.4; cursor: default; }

.consent {
  margin: 14px 0 0;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--faint);
  max-width: 44ch;
}

.consent a { color: var(--muted); }

/* Honeypot — never shown, never announced, never focusable. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* The status line only ever gets content from main.js, so it exists — and
   reserves its space — only when the script ran. CSP forbids the inline
   noscript <style> that would otherwise do this. */
.status {
  display: none;
  margin: 12px 0 0;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  min-height: 1.2em;
  color: var(--accent);
}

.js .status { display: block; }

.status[data-state="error"] { color: #E0685E; }

/* --------------------------------------------------------------------------
   Sections
   -------------------------------------------------------------------------- */

.section {
  position: relative;
  z-index: 2;
  background: var(--bg);
  border-top: 1px solid var(--line);
  padding-block: clamp(56px, 9vw, 116px);
}

.section__head { margin-bottom: clamp(24px, 3.4vw, 40px); }

.contacts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(232px, 1fr));
  gap: clamp(28px, 4vw, 56px);
  margin: 0;
}

.contact__label { margin-bottom: 10px; }

.contact__link {
  display: inline-block;
  color: var(--bone);
  text-decoration: none;
  font-size: clamp(16px, 1.9vw, 20px);
  letter-spacing: -0.01em;
  position: relative;
  padding: 6px 0;
}

.contact__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 2px;
  width: 100%; height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 520ms var(--ease);
}

.contact__link:hover::after,
.contact__link:focus-visible::after { transform: scaleX(1); }

.contact__note {
  margin: 6px 0 0;
  font-size: 13px;
  color: var(--faint);
  max-width: 34ch;
  line-height: 1.5;
}

.footer {
  position: relative;
  z-index: 2;
  background: var(--bg);
  border-top: 1px solid var(--line);
  padding-top: clamp(28px, 3.6vw, 40px);
  padding-bottom: max(clamp(28px, 3.6vw, 40px), env(safe-area-inset-bottom));
}

.footer__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px 28px;
}

.footer a {
  color: var(--faint);
  text-decoration: none;
  transition: color 300ms var(--ease);
  padding: 4px 0;
}

.footer a:hover { color: var(--bone); }

/* --------------------------------------------------------------------------
   Document pages — privacy, 404, subscribed
   -------------------------------------------------------------------------- */

.doc {
  position: relative;
  z-index: 2;
  padding-block: clamp(56px, 8vw, 104px);
  max-width: 68ch;
  min-height: 72svh;
}

.doc h1 {
  font-size: clamp(26px, 3.4vw, 38px);
  font-weight: 500;
  letter-spacing: -0.02em;
  margin: 0 0 8px;
}

.doc h2 {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.01em;
  margin: 40px 0 10px;
  color: var(--bone);
}

.doc p, .doc li { color: var(--muted); font-size: 15px; line-height: 1.7; }
.doc ul { padding-left: 18px; }
.doc li { margin-bottom: 6px; }

.doc a {
  color: var(--bone);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--accent-dim);
}

.doc a:hover { text-decoration-color: var(--accent); }
.doc .back { display: inline-block; margin-bottom: 40px; }

.doc--centre {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 82svh;
}

/* --------------------------------------------------------------------------
   Motion
   Small and performant. Barely noticeable, enough to be intriguing.
   Everything settles — nothing loops.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {

  /* Entrance stagger lives here, not in inline style attributes, so that
     style-src never needs 'unsafe-inline'. */
  .hero__bar .label:nth-child(1) { --d: 0ms; }
  .hero__bar .label:nth-child(2) { --d: 70ms; }
  .wordmark { --d: 180ms; }
  .tagline  { --d: 520ms; }
  .signup   { --d: 700ms; }

  .reveal {
    opacity: 0;
    transform: translateY(16px);
    animation: rise var(--in) var(--ease) var(--d, 0ms) forwards;
  }

  @keyframes rise { to { opacity: 1; transform: none; } }

  /* The wordmark wipes in behind its own edge. */
  .wordmark.reveal {
    clip-path: inset(0 100% 0 0);
    animation: rise var(--in) var(--ease) var(--d) forwards,
               wipe 1150ms var(--ease) var(--d) forwards;
  }

  @keyframes wipe { to { clip-path: inset(0 0 0 0); } }

  /* One hard highlight rakes across the wordmark, then parks on flat metal.
     no-repeat matters: the sweep must land on a defined resting state. */
  .maskfill {
    animation: rake 2600ms cubic-bezier(0.4, 0, 0.2, 1) 500ms forwards;
  }

  @keyframes rake { to { background-position: 0% 0; } }

  /* Sections lift once as they enter. Hidden only under .js: the reveal
     depends on IntersectionObserver in main.js, so without JavaScript the
     section must simply be visible. */
  .js .obs {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity 900ms var(--ease), transform 900ms var(--ease);
  }

  .js .obs.is-in { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal, .obs, .js .obs { opacity: 1; transform: none; clip-path: none; }
  /* Park the wordmark on its resting metal rather than mid-sweep. */
  .maskfill { background-position: 0% 0; }
}

/* --------------------------------------------------------------------------
   Narrow
   -------------------------------------------------------------------------- */

@media (max-width: 720px) {
  .markblock { width: 100%; }
  .tagline { letter-spacing: 0.3em; }
}

/* Short landscape phones: let the hero shrink rather than trapping content. */
@media (max-height: 520px) and (orientation: landscape) {
  .hero { min-height: auto; padding-block: 40px; }
  .hero__core { margin-block: 32px; }
}

/* --------------------------------------------------------------------------
   Print — the decoration is meaningless on paper; the contact details are not
   -------------------------------------------------------------------------- */

@media print {
  .frame, .vignette, .grain, .hero__grid, .maskfill { display: none !important; }
  body { background: #fff; color: #000; }
  .hero { min-height: auto; background: none; padding-block: 0; }
  .wordmark svg { visibility: visible !important; fill: #000; width: 300px; }
  .label, .tagline, .contact__note { color: #444; }
  .contact__link { color: #000; }
  .signup, .status, .consent { display: none; }
  .section, .footer { border-color: #ccc; background: none; }
  a { text-decoration: underline; }
}
