/* Quinine Cybersecurity: homepage hero visual (the markup between hero-visual:start/end in
   index.html). A static, accessible SVG of Q9 Continuous testing an AI system: the official Q in
   the core, connected nodes (API gateway, model, agent, RAG store, endpoints, evidence log) and a
   checkpoint on every trust boundary. Colours come only from tokens.css. Motion is CSS only
   (transform / opacity / stroke-dashoffset): the Q intro runs once (trace -> inner ring -> tail ->
   fill -> pulse -> settle), then one test probe at a time travels a connection and the checkpoint
   it crosses lights as it is tested. On a 32s loop the agent checkpoint is flagged, its evidence
   goes to the evidence log, and it passes when re-tested. A slow scan sweeps the trust boundaries.
   cyber-bg.js adds .is-paused while the figure is offscreen; html.cyber-hidden pauses everything
   while the tab is hidden. prefers-reduced-motion: the final, static state with no motion. */

.hero-visual.qh {
  --qh-ink: var(--q-ink, var(--color-ink));
  --qh-trace: var(--color-accent);
  --qh-wire: color-mix(in srgb, var(--color-accent) 52%, transparent);
  --qh-zone: color-mix(in srgb, var(--color-line-strong) 70%, transparent);
  --qh-fine: var(--color-line-fine);
  --qh-label: var(--color-text-muted);
  --qh-packet: var(--color-accent);
  --qh-signal: var(--color-signal);
  --qh-alert: var(--color-alert);
  --qh-plate: var(--color-surface);
  margin: 0; padding: clamp(8px, 1.2vw, 14px);
  background: var(--color-surface);
  border: 1px solid var(--color-line); border-radius: var(--radius-l);
  box-shadow: var(--shadow-2);
}
:root[data-theme="dark"] .hero-visual.qh {
  --qh-wire: color-mix(in srgb, var(--color-accent) 42%, transparent);
  --qh-packet: var(--citron);
}

.qh-stage { position: relative; aspect-ratio: 640 / 560; border-radius: calc(var(--radius-l) - 6px); overflow: hidden; contain: layout paint; }
.qh-base { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.qh-base text { font-family: var(--font-mono-stack); font-size: 10px; font-weight: 560; letter-spacing: 0.08em; fill: var(--qh-label); }
.qh-base .qh-label--small { font-size: 8.5px; }
.qh-base .qh-label--zone { fill: var(--color-detail-ink); font-size: 8.5px; letter-spacing: 0.14em; }
.qh-base .qh-label--path { fill: var(--qh-trace); }
.qh-base .qh-label--term { font-size: 9.5px; fill: var(--color-text); }

.qh-dot { fill: color-mix(in srgb, var(--color-accent) 30%, transparent); }
.qh-fade-a { stop-color: white; }
.qh-fade-b { stop-color: black; }

.qh-zone { fill: none; stroke: var(--qh-zone); stroke-width: 1; stroke-dasharray: 14 5; }
.qh-zone--edge { stroke-dasharray: 2 6; }
.qh-zone--core { stroke: var(--qh-fine); stroke-dasharray: 18 4 2 4; }
.qh-zone--data { stroke: var(--qh-fine); fill: color-mix(in srgb, var(--color-accent) 5%, transparent); }

.qh-ring { fill: none; stroke: color-mix(in srgb, var(--color-accent) 22%, transparent); stroke-width: 1; }
.qh-ring--dash { stroke-dasharray: 2 6; stroke: color-mix(in srgb, var(--color-accent) 32%, transparent); }
.qh-ring--ticks { stroke-dasharray: 1.2 9.14; stroke-width: 6; stroke: color-mix(in srgb, var(--qh-fine) 55%, transparent); }
.qh-cross { fill: none; stroke: var(--qh-fine); stroke-width: 1; }

.qh-trace { fill: none; stroke: var(--qh-wire); stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round; }
.qh-trace--tls { stroke: var(--qh-trace); stroke-width: 2; }
.qh-trace--link { stroke-dasharray: 3 4; }
.qh-pad { fill: var(--qh-plate); stroke: var(--qh-trace); stroke-width: 1.4; }
.qh-gate { fill: var(--qh-plate); stroke: var(--qh-fine); stroke-width: 1.3; }

.qh-shape { fill: var(--qh-plate); stroke: var(--qh-trace); stroke-width: 1.5; stroke-linejoin: round; }
.qh-mark { fill: none; stroke: var(--qh-trace); stroke-width: 1.2; stroke-linecap: round; }
.qh-led { fill: var(--qh-signal); }

/* The Q: official geometry, scaled 0.6 (stroke widths are in Q units). */
.qh-q-fill { fill: var(--qh-ink); }
.qh-q-line { fill: none; stroke: var(--qh-trace); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; opacity: 0.55; }
.qh-q-pulse { fill: none; stroke: var(--qh-signal); stroke-width: 4; opacity: 0; transform-box: fill-box; transform-origin: center; }

/* Test probes: one short dash per connection (pathLength 100), hidden until it runs. */
.qh-probe { fill: none; stroke: var(--qh-packet); stroke-width: 2.6; stroke-linecap: round; stroke-dasharray: 6 200; stroke-dashoffset: 6; opacity: 0; }
/* Checkpoint overlays: light when a probe crosses the gate (signal), or when it is flagged (alert). */
.qh-hit { fill: var(--qh-signal); stroke: var(--qh-signal); stroke-width: 1.3; opacity: 0; }
.qh-hit--flag { fill: var(--qh-alert); stroke: var(--qh-alert); }
.qh-event { fill: none; stroke: var(--qh-signal); stroke-width: 1.6; opacity: 0; transform-box: fill-box; transform-origin: center; }
.qh-event--flag { stroke: var(--qh-alert); }
/* Trust-boundary scan: a short bright segment travelling the boundary outline. */
.qh-bound { fill: none; stroke: var(--qh-signal); stroke-width: 2; stroke-linecap: round; stroke-dasharray: 7 93; opacity: 0; }
.qh-bound--data { stroke-dasharray: 12 88; }

.qh-status-bar { fill: color-mix(in srgb, var(--color-accent) 6%, var(--qh-plate)); stroke: var(--color-line); stroke-width: 1; }
.qh-status-dot { fill: var(--qh-signal); stroke: color-mix(in srgb, var(--color-accent) 60%, transparent); stroke-width: 1; }
.qh-cursor { fill: var(--qh-trace); }


.qh-caption-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--qh-signal); box-shadow: 0 0 0 3px color-mix(in srgb, var(--qh-signal) 28%, transparent); }

/* ------------------------------------------------------------------ motion */
/* Probe schedule (16s loop, one probe every 2s from 2.8s; a probe crosses its whole path in 12%
   = 1.92s, so a checkpoint at fraction g of its path lights at start + 1.92s * g / 106):
   API gateway 2.8s (gate 4.03s) · model 4.8s (5.71s) · agent 6.8s (7.47s, flagged on the first
   pass of the 32s loop, passes on the re-test) · evidence 8.8s (gate 9.31s, log 10.61s) ·
   RAG 10.8s (11.08s, data boundary 12.24s) · user 12.8s (13.97s) · mobile 14.8s (15.57s) ·
   workload 16.8s (17.99s). */
@media (prefers-reduced-motion: no-preference) {
  .qh-zones, .qh-grid, .qh-rings { animation: qh-fade 600ms var(--ease-out) both; }
  .qh-q-outer { stroke-dasharray: 100 100; animation: qh-draw 1000ms var(--ease-trace) 200ms both, qh-settle 600ms ease 2200ms both; }
  .qh-q-inner { stroke-dasharray: 100 100; animation: qh-draw 600ms var(--ease-trace) 900ms both, qh-settle 600ms ease 2200ms both; }
  .qh-q-tail { stroke-dasharray: 100 100; animation: qh-draw 500ms var(--ease-trace) 1350ms both, qh-settle 600ms ease 2200ms both; }
  .qh-q-fill { animation: qh-fill 600ms var(--ease-out) 1700ms both; }
  .qh-q-pulse { animation: qh-pulse 900ms var(--ease-out) 2000ms both, qh-pulse-ambient 16s ease-out 18s infinite; }
  .qh-trace { stroke-dasharray: 100 100; animation: qh-draw 800ms var(--ease-trace) 1800ms both; }
  .qh-trace:nth-child(2n) { animation-delay: 1950ms; }
  .qh-trace:nth-child(3n) { animation-delay: 2100ms; }
  .qh-trace--link { stroke-dasharray: 3 4; animation: qh-fade 600ms ease 2300ms both; }
  .qh-pads, .qh-gates, .qh-nodes { animation: qh-fade 700ms var(--ease-out) 1500ms both; }

  .qh-bound { opacity: 0.75; animation: qh-fade 800ms ease 2400ms both, qh-bound 24s linear 2400ms infinite; }
  .qh-bound--data { animation-duration: 800ms, 11s; }

  .qh-probe { animation: qh-probe 16s linear infinite both; }
  .qh-probe--api { animation-delay: 2.8s; }
  .qh-probe--model { animation-delay: 4.8s; }
  .qh-probe--agent { animation-delay: 6.8s; }
  .qh-probe--evidence { animation-delay: 8.8s; }
  .qh-probe--rag { animation-delay: 10.8s; }
  .qh-probe--user { animation-delay: 12.8s; }
  .qh-probe--mobile { animation-delay: 14.8s; }
  .qh-probe--workload { animation-delay: 16.8s; }

  .qh-hit { animation: qh-hit 16s ease-out infinite both; }
  .qh-hit--api { animation-delay: 4.03s; }
  .qh-hit--model { animation-delay: 5.71s; }
  .qh-hit--evidence { animation-delay: 9.31s; }
  .qh-hit--rag { animation-delay: 11.08s; }
  .qh-hit--data { animation-delay: 12.24s; }
  .qh-hit--user { animation-delay: 13.97s; }
  .qh-hit--mobile { animation-delay: 15.57s; }
  .qh-hit--workload { animation-delay: 17.99s; }
  .qh-hit--flag { animation: qh-flag 32s ease-out 7.47s infinite both; }
  .qh-hit--agent-pass { animation: qh-hit-retest 32s ease-out 23.47s infinite both; }
  .qh-event--flag { animation: qh-ring 32s var(--ease-out) 8.61s infinite both; }
  .qh-led--log { animation: qh-led 16s ease-out 10.61s infinite both; }

  .qh-cursor { animation: qh-blink 1.2s steps(1) infinite; }

  .qh.is-paused *, :root.cyber-hidden .qh * { animation-play-state: paused !important; }
}

@keyframes qh-fade { from { opacity: 0; } }
@keyframes qh-draw { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
@keyframes qh-settle { from { opacity: 1; } to { opacity: 0.55; } }
@keyframes qh-fill { from { opacity: 0; } to { opacity: 1; } }
@keyframes qh-pulse { from { opacity: 0.85; transform: scale(1); } to { opacity: 0; transform: scale(1.32); } }
@keyframes qh-pulse-ambient { 0% { opacity: 0.45; transform: scale(1); } 7% { opacity: 0; transform: scale(1.22); } 100% { opacity: 0; transform: scale(1.22); } }
@keyframes qh-bound { from { stroke-dashoffset: 0; } to { stroke-dashoffset: -100; } }
@keyframes qh-probe {
  0% { stroke-dashoffset: 6; opacity: 0; }
  0.4% { opacity: 1; }
  11.6% { opacity: 1; }
  12%, 100% { stroke-dashoffset: -100; opacity: 0; }
}
@keyframes qh-hit { 0% { opacity: 0; } 0.6% { opacity: 0.95; } 5% { opacity: 0.7; } 9%, 100% { opacity: 0; } }
@keyframes qh-hit-retest { 0% { opacity: 0; } 0.3% { opacity: 0.95; } 2.5% { opacity: 0.7; } 4.5%, 100% { opacity: 0; } }
@keyframes qh-flag { 0% { opacity: 0; } 0.3% { opacity: 1; } 7% { opacity: 1; } 9%, 100% { opacity: 0; } }
@keyframes qh-ring {
  0% { opacity: 0; transform: scale(0.7); }
  0.4% { opacity: 1; }
  3.5% { opacity: 0; transform: scale(1.25); }
  100% { opacity: 0; transform: scale(1.25); }
}
@keyframes qh-led { 0%, 100% { fill-opacity: 1; } 1% { fill-opacity: 0.2; } 2% { fill-opacity: 1; } 3% { fill-opacity: 0.2; } 4% { fill-opacity: 1; } }
@keyframes qh-blink { 50% { fill-opacity: 0; } }

/* ------------------------------------------------------------------ small screens */
@media (max-width: 767.98px) {
  .qh-base .qh-detail { display: none; }
  .qh-base text { font-size: 15px; letter-spacing: 0.04em; }
  .qh-base .qh-label--small, .qh-base .qh-label--zone, .qh-base .qh-label--term { font-size: 14px; }
  .qh-zones .qh-label--zone:last-of-type { display: none; }
  .qh-trace { stroke-width: 2.2; }
  .qh-ring--dash { display: none; }
}

@media (forced-colors: active) {
  .qh-q-fill { fill: CanvasText; }
  .qh-bound, .qh-probe { display: none; }
  .qh-hit { fill: Highlight; stroke: Highlight; }
}

/* Homepage hero headline: the product-led H1 is longer than the old one, so it uses a smaller
   display size to stay readable (sizes only; no token changes). */
.hero__copy .display { font-size: clamp(2.2rem, 1.3rem + 2.7vw, 3.5rem); text-wrap: balance; }

/* ------------------------------------------------------------------ hero copy: lead wrap
   The copy already shares one left edge and the --space-* rhythm (home.css, home-sections.css).
   text-wrap: pretty keeps the lead from ending on a single orphaned word (it did at 375px);
   browsers without it simply wrap as before. The copy has no entrance animation: it is shown
   at first paint, and the load-time motion budget belongs to the nav Q and the Living Q. */
.hero__copy .hero__lead { text-wrap: pretty; }

/* ------------------------------------------------------------------ hero layout */
/* Bottom padding: the Ask-AI row is the last item, and the next section brings its own top
   padding, so the hero closes with one --space-7..--space-8 step instead of up to 104px. */
.hero { padding-bottom: clamp(var(--space-7), 4vw, var(--space-8)); }
/* Stacked layout on tablets (768–1024px): the visual is capped at 640px, so centre it in the
   column rather than leaving the space on its right empty. */
@media (min-width: 768px) and (max-width: 1024px) {
  .hero__grid > .hero-visual.qh { width: 100%; margin-inline: auto; }
}

/* ------------------------------------------------------------------ Living Q Signature
   (formerly living-q.css; folded in here so the homepage makes no extra stylesheet request) */
/* Quinine Cybersecurity: the Living Q Signature (living-q.js, docs/brand-q.md "Living Q Signature").
   Drives the official Q (Q_GEOMETRY, never redrawn) inside any [data-living-q] host. On the
   homepage that host is the hero figure and the Q is the one already at its centre.
   Host states (data-living-q):
     ""          markup default, before living-q.js runs: Q hidden, revealed settled after 1.6 s
                 if the module never runs
     ready       mounted, waiting to enter the viewport: Q hidden
     assembling  construction guides draw, ring and counter stroke in, tail resolves, fill
                 settles, guides fade (2.0 s)
     settled     static final state, identical to the reduced-motion / no-JS mark
   [data-living-q-trace] on a settled host: one faint outline trace (hover, pointer: fine).
   Without JS (no :root.js) and under prefers-reduced-motion the Q is settled at once.
   Colours: --q-trace (guides) and --q-pulse (hover trace) from tokens.css only. Motion: opacity
   and stroke-dashoffset only, so nothing moves the layout. */

.lq-guide, .lq-trace { fill: none; opacity: 0; pointer-events: none; }
.lq-guide { stroke: var(--q-trace); stroke-width: var(--lq-guide-width, 1.5); }
.lq-trace { stroke: var(--q-pulse); stroke-width: var(--lq-trace-width, 3.2); stroke-linecap: round; stroke-linejoin: round; }

/* No JS: the settled Q immediately (cancels any older CSS-only intro on the same parts). */
:root:not(.js) [data-living-q] :is(.lq-fill, .lq-line, .lq-pulse),
[data-living-q="settled"] :is(.lq-fill, .lq-line, .lq-pulse) { animation: none; }

@media (prefers-reduced-motion: no-preference) {
  /* Before the module runs: hidden, with a settled reveal if it never does. */
  :root.js [data-living-q=""] :is(.lq-fill, .lq-line) { animation: lq-await 1ms linear 1600ms both; }
  :root.js [data-living-q=""] .lq-pulse,
  [data-living-q="ready"] .lq-pulse,
  [data-living-q="assembling"] .lq-pulse { animation: none; }
  [data-living-q="ready"] :is(.lq-fill, .lq-line) { animation: none; opacity: 0; }

  /* Assembly: 0-0.8 s guides, 0.25-1.45 s outer ring -> counter -> tail, 1.3-1.9 s fill,
     1.45-2.0 s guides fade and the outline settles to its resting weight. */
  [data-living-q="assembling"] .lq-guide { opacity: 0.5; stroke-dasharray: 100 100; }
  [data-living-q="assembling"] .lq-guide--ring { animation: lq-draw 650ms var(--ease-trace) 0ms both, lq-out 500ms var(--ease-out) 1450ms forwards; }
  [data-living-q="assembling"] .lq-guide--counter { animation: lq-draw 600ms var(--ease-trace) 120ms both, lq-out 500ms var(--ease-out) 1450ms forwards; }
  [data-living-q="assembling"] .lq-guide--axis { animation: lq-draw 460ms var(--ease-trace) 300ms both, lq-out 500ms var(--ease-out) 1500ms forwards; }
  [data-living-q="assembling"] .lq-guide--base { animation: lq-draw 440ms var(--ease-trace) 380ms both, lq-out 500ms var(--ease-out) 1500ms forwards; }

  [data-living-q="assembling"] .lq-line { opacity: 0.9; stroke-dasharray: 100 100; }
  [data-living-q="assembling"] .lq-outer { animation: lq-draw 800ms var(--ease-trace) 250ms both, lq-rest 500ms var(--ease-out) 1500ms forwards; }
  [data-living-q="assembling"] .lq-inner { animation: lq-draw 600ms var(--ease-trace) 650ms both, lq-rest 500ms var(--ease-out) 1500ms forwards; }
  [data-living-q="assembling"] .lq-tail { animation: lq-draw 450ms var(--ease-trace) 1000ms both, lq-rest 500ms var(--ease-out) 1500ms forwards; }
  [data-living-q="assembling"] .lq-fill { animation: lq-fill 600ms var(--ease-out) 1300ms both; }

  /* Hero coupling: the test probes stay out of sight until the Q has assembled. Hiding (rather
     than pausing) keeps hero.css's probe timeline untouched. */
  .qh:is([data-living-q="ready"], [data-living-q="assembling"]) :is(.qh-probes, .qh-hits, .qh-events) { visibility: hidden; }

  /* Hover: the outline traces once, faintly. */
  [data-living-q="settled"][data-living-q-trace] .lq-trace { stroke-dasharray: 100 100; animation: lq-trace 1400ms var(--ease-in-out) both; }
}

@keyframes lq-await { from { opacity: 0; } }
@keyframes lq-draw { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
@keyframes lq-out { to { opacity: 0; } }
@keyframes lq-rest { to { opacity: 0.55; } }
@keyframes lq-fill { from { opacity: 0; } to { opacity: 1; } }
@keyframes lq-trace {
  0% { stroke-dashoffset: 100; opacity: 0; }
  12% { opacity: 0.6; }
  78% { stroke-dashoffset: 0; opacity: 0.6; }
  100% { stroke-dashoffset: 0; opacity: 0; }
}

/* A standalone Living Q built by createLivingQMark() (living-q.js). Hero styles cover the hero. */
.lq-mark { display: block; width: 100%; height: auto; overflow: visible; --lq-guide-width: 2; --lq-trace-width: 5; }
.lq-mark .lq-fill { fill: var(--q-ink); }
.lq-mark .lq-line { fill: none; stroke: var(--q-trace); stroke-width: var(--lq-line-width, 4); stroke-linecap: round; stroke-linejoin: round; opacity: 0.55; }

@media (forced-colors: active) {
  .lq-guide, .lq-trace { display: none; }
}
