/* =============================================================================
   FACTORY INVESTIGATOR — Cinematic Layer  ·  CSS  ·  v1.0  ·  2026-06-01
   -----------------------------------------------------------------------------
   ADDITIVE layer on top of factory-investigator.css. Pairs with
   factory-investigator-cinematic.js and is enqueued by
   factory-investigator-snippets-cinematic.php (Snippet 26). Turn the whole layer
   off by deactivating that one snippet — the static site keeps working.

   TWO INDEPENDENT CONCERNS:
     (A) DARK MODE  — always-on theme tokens (doc 09 §4). The no-flash <head>
         script (Snippet 26) sets data-theme BEFORE first paint, defaulting to
         dark; localStorage persists a manual toggle. NOT gated on JS.
     (B) MOTION     — the 8 signature moments. ALL gated behind `html.fi-cin`,
         a class the JS adds ONLY when prefers-reduced-motion is not set. So
         without JS, or with reduced-motion, every element is fully visible and
         nothing animates. Reveal targets are never hidden unless motion is on.

   PERFORMANCE: target < 25KB minified. Only compositor-friendly properties
   animate (opacity, transform, stroke-dashoffset, filter). No width/height/top
   animations → no layout thrash. IntersectionObserver drives all scroll reveals
   (no scroll listeners). Comments here strip out on minify.
   ============================================================================= */


/* =============================================================================
   (A) DARK MODE — token overrides   (authoritative hex = design doc 09 §4)
   -----------------------------------------------------------------------------
   Selector is `html[data-theme="dark"]` (specificity 0,1,1) ON PURPOSE: WordPress
   prints the Customizer "Additional CSS" (which re-declares :root light tokens)
   at wp_head priority 101 — AFTER this enqueued file. A plain [data-theme="dark"]
   (0,1,0) would tie :root and lose on source order; html[...] outranks :root so
   the dark palette wins no matter the print order.
   ============================================================================= */
html[data-theme="dark"] {
  --ink:        #F5F1E8;   /* paper becomes the text */
  --paper:      #161310;   /* deep charcoal page */
  --card:       #1F1A14;   /* slightly lifted cards */
  --steel:      #4A7A95;   /* lighter blueprint blue (visible on dark) */
  --brass:      #C99550;   /* candlelit metal */
  --brass-text: #D4A66B;   /* brighter small brass text */
  --oxide:      #B85A4D;   /* lighter oxide red */
  --grey:       #9B948A;
  --lead:       #E8E0D0;
  --hair:       #2E2820;
  --rule:       #3A3328;

  /* derived surfaces that must also flip for legibility (not in doc 09, required
     so zebra rows + focus ring stay readable on dark) */
  --row-zebra:  #221C15;
  --focus-ring: 0 0 0 3px rgba(74,122,149,.55);   /* dark-steel ring */
  color-scheme: dark;                              /* native form controls/scrollbars */
}

/* --- (A2) DARK SURFACE CORRECTIONS ------------------------------------------ *
 * A few surfaces are intentionally DARK in light mode (footer, bridge, duotone
 * tiles) and use --ink for their background. Inverting --ink would flip them to
 * light, so we pin them dark and flip only their text. */
[data-theme="dark"] .footer,
[data-theme="dark"] .bridge      { background: #100C09; }
[data-theme="dark"] .bridge h2   { color: var(--ink); }   /* was --paper (now dark) */
[data-theme="dark"] .duo-block,
[data-theme="dark"] .headshot    { background: #0E0B08; }
[data-theme="dark"] .duo-block .patent,
[data-theme="dark"] .headshot .patent { color: var(--ink); } /* keep lines light on the dark tile */

/* Comparison-table header: paper-on-steel would become dark-on-mid-blue in dark
   mode (fails AA at 13px). Pin a deep steel + light text instead. */
[data-theme="dark"] table.compare thead th { background: #15303E; color: var(--ink); }

/* Primary button inverts to a light chip on dark — keep its hover legible. */
[data-theme="dark"] .btn--primary:hover { background: var(--steel); color: #10110F; }

/* --- (A3) DARK ATMOSPHERICS (the Peaky-Blinders "smoke-lit office") ---------- *
 * Patent line-drawings auto-invert for free: they use currentColor over --card/
 * --paper surfaces, and --ink is now light — so no filter is needed. */
[data-theme="dark"] .seal { filter: drop-shadow(0 0 8px rgba(201,149,80,.18)); }   /* wax-seal glow */
[data-theme="dark"] .rule-double,
[data-theme="dark"] .stat__num,
[data-theme="dark"] .stat-callout__num { filter: drop-shadow(0 0 6px rgba(201,149,80,.15)); }
[data-theme="dark"] .methodology { box-shadow: 0 0 24px rgba(201,149,80,.06); }

/* Smoke-tone gradient wash — dark mode only, 6% peak, fixed, never interactive. */
[data-theme="dark"] body::before {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 2147483646;
  background:
    radial-gradient(120% 80% at 80% -10%, rgba(201,149,80,.06), transparent 55%),
    radial-gradient(100% 70% at 0% 110%, rgba(31,58,95,.07), transparent 55%);
}


/* =============================================================================
   PAPER GRAIN OVERLAY (signature moment 5) — both themes, static, ~2% opacity.
   Inline SVG fractal-noise data-URI → no binary asset, < 1KB, repeats. Sits above
   content with pointer-events:none so it tints without blocking or fuzzing taps.
   ============================================================================= */
body::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 2147483647;
  opacity: .022;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}
[data-theme="dark"] body::after { opacity: .03; }   /* a touch more tooth on dark */


/* =============================================================================
   THEME TOGGLE — injected into the masthead by the JS (uppercase mono link)
   ============================================================================= */
.fi-theme-toggle {
  font-family: var(--mono); font-size: 11px; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--grey); background: none; border: none;
  cursor: pointer; padding: 6px 8px; margin-left: 14px; line-height: 1; white-space: nowrap;
}
.fi-theme-toggle:hover { color: var(--brass-text); }
@media (max-width: 768px) { .fi-theme-toggle { margin-left: auto; } }


/* =============================================================================
   RED-PEN CURSOR (signature moment 8) — annotated screenshots. Not motion;
   always on. Inline SVG cursor data-URI (no binary asset). Hotspot at the nib.
   ============================================================================= */
.fi-annotated-screenshot:hover {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewport='0 0 28 28'%3E%3Cpath d='M4 24 L7 18 L20 5 a2 2 0 0 1 3 3 L10 21 Z' fill='%238B3A2F' stroke='%23F5F1E8' stroke-width='1'/%3E%3Cpath d='M4 24 L7 18 L10 21 Z' fill='%23161310'/%3E%3C/svg%3E") 4 24, crosshair;
}


/* =============================================================================
   (B) MOTION — everything below is gated behind `html.fi-cin`
   (added by the JS only when prefers-reduced-motion is NOT set).
   ============================================================================= */

/* keyframes (defined once; referenced under the gate) */
@keyframes fi-fade-up   { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes fi-page-in   { from { opacity: 0; } to { opacity: 1; } }
@keyframes fi-wipe      { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes fi-rule-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes fi-drop      { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@keyframes fi-stamp     { from { opacity: 0; transform: rotate(-14deg) scale(1.12); } to { opacity: 1; transform: rotate(-5deg) scale(1); } }
@keyframes fi-titlecard { from { opacity: 0; letter-spacing: .28em; filter: blur(3px); } to { opacity: 1; letter-spacing: .08em; filter: none; } }
@keyframes fi-pulse     { 0%,100% { opacity: 1; } 50% { opacity: .45; } }
@keyframes fi-draw      { to { stroke-dashoffset: 0; } }

/* moment 6 — page fade-in on load (reading-paced 0.4s). Also opt into native MPA
   view-transition crossfades where supported (browsers auto-disable under
   reduced-motion, and this only applies inside the .fi-cin gate). */
html.fi-cin body { animation: fi-page-in .4s ease both; }

/* moment 1 — opening dossier reveal (FIRST VISIT ONLY; JS adds .fi-cin-dossier).
   "Letter-by-letter" is approximated as a left-to-right wipe of the wordmark —
   it reads as "being written in" without per-letter DOM surgery (keeps the
   wordmark a single accessible link). */
html.fi-cin .fi-cin-dossier .masthead__wordmark { animation: fi-wipe .6s ease both; }
html.fi-cin .fi-cin-dossier + .rule-double,
html.fi-cin .fi-cin-dossier .rule-double { transform-origin: left center; animation: fi-rule-draw .4s ease .5s both; }
html.fi-cin .fi-cin-dossier .masthead__issue { animation: fi-drop .3s ease .9s both; }

/* moment 2 — patent drawings sketch in on scroll (JS adds .fi-cin-draw in view).
   stroke-dasharray larger than any child's perimeter → each line/rect/circle
   draws itself. Reads as a draftsman sketching; runs once. */
html.fi-cin .fi-cin-draw .patent :is(path, line, rect, circle, polyline, polygon) {
  stroke-dasharray: 1200; stroke-dashoffset: 1200; animation: fi-draw 1.1s ease forwards;
}
html.fi-cin .fi-cin-draw .patent text { opacity: 0; animation: fi-page-in .4s ease .9s forwards; }
/* light stagger so it doesn't all snap at once */
html.fi-cin .fi-cin-draw .patent g:nth-of-type(2) :is(line,rect,circle) { animation-delay: .15s; }
html.fi-cin .fi-cin-draw .patent g:nth-of-type(3) :is(line,rect,circle) { animation-delay: .3s; }

/* moment 3 — methodology stamp "lands" (JS adds .is-in in view) */
html.fi-cin .methodology .methodology__seal { opacity: 0; }
html.fi-cin .methodology.is-in .methodology__seal { animation: fi-stamp .45s cubic-bezier(.2,.8,.3,1.1) both; }

/* moment 4 — Field Report title card (JS adds .is-in; element optional, hooks on
   if a .fi-field-report block exists on the article hero) */
html.fi-cin .fi-field-report { opacity: 0; }
html.fi-cin .fi-field-report.is-in { animation: fi-titlecard .8s ease both; }
html.fi-cin .fi-field-report.is-in .fi-field-report__status { animation: fi-pulse 1.2s ease 2; } /* 2 cycles then stop */

/* generic section fade-up (JS tags .fi-cin-fade on summary/findings/stat blocks/
   pullquote/figure/casefile) */
html.fi-cin .fi-cin-fade { opacity: 0; }
html.fi-cin .fi-cin-fade.is-in { animation: fi-fade-up .5s ease both; }

/* moment 7 — comparison tables populate row-by-row (JS adds .fi-cin-rows in view).
   Header is visible immediately; body rows stagger in. Capped at 8 explicit
   delays (more rows simply appear with the last delay — no infinite selectors). */
html.fi-cin table.compare tbody tr { opacity: 0; }
html.fi-cin table.compare.fi-cin-rows tbody tr { animation: fi-fade-up .4s ease both; }
html.fi-cin table.compare.fi-cin-rows tbody tr:nth-child(1) { animation-delay: .05s; }
html.fi-cin table.compare.fi-cin-rows tbody tr:nth-child(2) { animation-delay: .15s; }
html.fi-cin table.compare.fi-cin-rows tbody tr:nth-child(3) { animation-delay: .25s; }
html.fi-cin table.compare.fi-cin-rows tbody tr:nth-child(4) { animation-delay: .35s; }
html.fi-cin table.compare.fi-cin-rows tbody tr:nth-child(5) { animation-delay: .45s; }
html.fi-cin table.compare.fi-cin-rows tbody tr:nth-child(6) { animation-delay: .55s; }
html.fi-cin table.compare.fi-cin-rows tbody tr:nth-child(7) { animation-delay: .65s; }
html.fi-cin table.compare.fi-cin-rows tbody tr:nth-child(n+8) { animation-delay: .75s; }


/* =============================================================================
   NATIVE PAGE TRANSITIONS (moment 6, enhanced) — MPA view transitions where
   supported. Browsers disable these automatically under reduced-motion. Cheap,
   no JS. Falls back silently to the load fade-in above.
   ============================================================================= */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: .4s; }


/* =============================================================================
   REDUCED MOTION — belt-and-suspenders. The JS already withholds `.fi-cin` when
   the user prefers reduced motion, so these rules rarely apply; they guarantee
   that even if `.fi-cin` is forced on, motion degrades to instant + visible.
   ============================================================================= */
@media (prefers-reduced-motion: reduce) {
  html.fi-cin .fi-cin-fade,
  html.fi-cin .fi-field-report,
  html.fi-cin .methodology .methodology__seal,
  html.fi-cin table.compare tbody tr { opacity: 1 !important; }
  html.fi-cin *, html.fi-cin *::before, html.fi-cin *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
  }
  html.fi-cin .patent :is(path,line,rect,circle,polyline,polygon) { stroke-dashoffset: 0 !important; }
  @view-transition { navigation: none; }
}

/* =============================================================================
   END factory-investigator-cinematic.css v1.0
   ============================================================================= */
