/* GridCifra loader and launch panel — page-specific styles for /gridcifra.
 *
 * Loaded after styles.css, which supplies every colour, font and scheme. Nothing
 * here defines a palette: the block below is a set of private names for the
 * loader's own vocabulary, each pointing at a Conversion Grid token, so the page
 * follows the visitor's light or dark preference exactly like the rest of the
 * site. The loader was already using six of these values before it moved here.
 *
 * Two rules to keep when editing:
 *   --sky is for graphics and large display type. Anything at body size takes
 *   --sky-deep, which clears AA on paper.
 *   The accent means signal, not decoration.
 */
:root {
  /* Surfaces and text. "night" is simply the page surface, whichever it is. */
  --color-cg-night: var(--paper);
  --color-cg-night-raised: var(--paper-2);
  --color-cg-ink: var(--ink);
  --color-cg-muted: var(--ink-3);
  --color-cg-rule: var(--line);
  --color-gc-ink: var(--ink);
  --color-gc-rule-strong: var(--line-2);

  /* Graphics and large display type. */
  --color-cg-sky: var(--sky);
  /* Kickers, labels and links — body size, so the AA-safe blue. */
  --color-cg-sky-text: var(--sky-deep);

  /* The mark, drawn the way the lockup on this site already draws it: solid ink
   * for the G and the C, the two tiles held back. Mixed against the surface
   * rather than towards transparent, because the loader animates each piece's
   * opacity and two lots of transparency compound into a ghost. */
  --color-metal-high: var(--ink);
  --color-metal-mid: color-mix(in oklch, var(--ink) 80%, var(--paper));
  --color-metal-low: color-mix(in oklch, var(--ink) 55%, var(--paper));

  --color-error: oklch(48% 0.16 25);

  --font-wordmark: var(--display);
  --font-display: var(--sans);
  --font-body: var(--sans);
  --font-data: var(--mono);

  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-md: 1.25rem;
  --text-lg: 1.5625rem;
  --text-2xl: 2.441rem;

  --space-3xs: 0.125rem;
  --space-2xs: 0.25rem;
  --space-xs: 0.5rem;
  --space-sm: 0.75rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2.5rem;
  --space-2xl: 4rem;
  --space-3xl: 6rem;
  --space-4xl: 9rem;

  --page-gutter: clamp(20px, 4vw, 64px);
  --page-max: var(--maxw);

  --radius-sm: 0.375rem;
  --radius-md: 10px;
  --radius-lg: 14px;
  --radius-round: 999rem;

  --rule-thin: 1px;
  --rule-strong: 2px;

  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  --dur-micro: 120ms;
  --dur-short: 220ms;
  --dur-long: 480ms;
  --dur-brand: 620ms;

  --z-base: 1;
  --z-raised: 10;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-error: oklch(78% 0.13 25);
  }
}

/* Reactive launch panel. The page resolves into this and stops here, so it stays
 * in the night palette: the loader finishes assembling and the panel is simply
 * what the assembled mark was assembling towards. Four things make it reactive —
 * the grid lights under the pointer, the console leans towards it, the content
 * arrives on entering the viewport, and the form answers as it is typed.
 */
/* ============================================================
   LOADER · draw, then fill
   The mark is stroked open and traced on, then the fill rises behind the line
   and the stroke retires. Each shape carries pathLength="1" in the markup, so
   one normalised dash length traces any of them whatever its real perimeter.
   Only the dash offset and two opacities animate — nothing moves, so no layout
   is touched and the page underneath is already painted.

   The line draws in the accent because a drawing line is signal, which is the
   one job the accent has. The fill lands in ink and the accent leaves with the
   stroke, so the finished mark is the ordinary one.
   ============================================================ */
html.is-loading {
  overflow: hidden;
}

.loader {
  position: fixed;
  inset: 0;
  /* The site's scale is nav 50, cookie banner 120, skip link 200. The splash
   * goes over the banner but under the skip link, so a keyboard visitor can
   * still tab straight past it — and any keypress dismisses it anyway. */
  z-index: 150;
  display: grid;
  place-items: center;
  background: var(--paper);
  transition:
    opacity 560ms var(--ease-out),
    visibility 560ms;
}

.loader.out {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.loader__mark {
  width: clamp(104px, 15vw, 168px);
  height: auto;
}

.mk__p {
  fill: var(--ink);
  fill-opacity: 0;
  stroke: var(--sky-deep);
  stroke-width: 1.4;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}

.loader.run .mk__p {
  animation:
    cg-draw 850ms var(--ease-out) forwards,
    cg-fill 520ms var(--ease-out) forwards;
}

/* The two solid tiles settle at 55%, matching the canonical mark, so they sit
 * behind the letterforms rather than level with them. This has to precede the
 * delay rules: the animation shorthand resets delay. */
.loader.run .mk__p--tile {
  animation:
    cg-draw 850ms var(--ease-out) forwards,
    cg-fill-tile 520ms var(--ease-out) forwards;
}

.loader.run .mk__p--1 { animation-delay: 0ms, 800ms; }

.loader.run .mk__p--2 { animation-delay: 130ms, 930ms; }

.loader.run .mk__p--3 { animation-delay: 260ms, 1060ms; }

.loader.run .mk__p--4 { animation-delay: 390ms, 1190ms; }

@keyframes cg-draw {
  to { stroke-dashoffset: 0; }
}

@keyframes cg-fill {
  to { fill-opacity: 1; stroke-opacity: 0; }
}

@keyframes cg-fill-tile {
  to { fill-opacity: 0.55; stroke-opacity: 0; }
}

/* Failsafe, independent of JavaScript. If the driver never runs — a syntax
 * error, a CSP that drops inline script, an extension that strips it — this
 * still clears the overlay rather than leaving someone on a covered page. */
.loader {
  animation: cg-failsafe 0s linear 6s forwards;
}

@keyframes cg-failsafe {
  to { opacity: 0; visibility: hidden; pointer-events: none; }
}

/* Without JavaScript the overlay would never be told to draw or to leave, and
 * an empty outline is worse than no loader at all. */
html:not(.js) .loader {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .loader { display: none; }
  html.is-loading { overflow: auto; }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
