@import 'tailwindcss';
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';

@source '../node_modules/fumadocs-ui/dist/**/*.js';

/* Cisco brand mapping. Cisco's signature blue (#049fd9)
 * drives links, focus rings, primary buttons, and code-block accents.
 * Tokens are expressed in OKLCH so they degrade gracefully across
 * light + dark themes and stay perceptually uniform when the user
 * flips schemes. The warm orange `--brand-warn` mirrors the orange
 * "AI Security Framework" badge used in the project README and is
 * reserved for action-mode / blocked / warning surfaces so the visual
 * vocabulary lines up with the operator's mental model.
 */
:root {
  --brand-cisco: oklch(0.7 0.16 237);
  --brand-cisco-strong: oklch(0.62 0.18 240);
  --brand-warn: oklch(0.74 0.18 50);
  --brand-grain-opacity: 0.08;

  --color-fd-primary: var(--brand-cisco);
  --color-fd-accent: var(--brand-cisco);
  --color-fd-ring: var(--brand-cisco);

  /* Widen Fumadocs's docs chrome on large screens. The library default
   * of 97rem (1552px) leaves ~360px unused on a 1920px monitor, which
   * forces the capability matrix and Flow diagrams to scroll
   * horizontally inside a too-narrow article column. 108rem (1728px)
   * uses big monitors well without breaking small ones (the chrome
   * still shrinks to viewport width below this cap). Combined with
   * the per-page `full` opt-in (defaulted to `true` in page.tsx), the
   * article gets ~1168px of usable width on 1920px+ displays. */
  --fd-layout-width: 108rem;
}

/* Wide content (Flow/Sequence figures and our `<table>`s) should never
 * be horizontally clipped or scrolled inside the article column when
 * the article itself is wide enough to hold them. Fumadocs renders
 * tables inside an `overflow-x-auto` wrapper for safety on small
 * screens — that wrapper still applies, so on tablet/phone the
 * gesture-friendly horizontal scroll stays. On `xl:` breakpoints (the
 * width where the docs chrome actually grants the full 1168px), we
 * lift the wrapper and let the table breathe across the full article
 * column instead of pinning it to its `min-w-[900px]` size. */
@media (min-width: 1280px) {
  article#nd-page[data-full="true"] :where(table) {
    min-width: 0;
  }
}

.dark {
  --brand-cisco: oklch(0.78 0.14 237);
  --brand-cisco-strong: oklch(0.7 0.18 240);
  --color-fd-primary: var(--brand-cisco);
  --color-fd-accent: var(--brand-cisco);
  --color-fd-ring: var(--brand-cisco);
}

/* Hero terminal window — minimal styling, leans on the Fumadocs token
 * palette so the component re-themes for free when operators switch
 * to light mode.
 */
.terminal-window {
  background: linear-gradient(
    180deg,
    color-mix(in oklab, var(--color-fd-card) 92%, transparent) 0%,
    color-mix(in oklab, var(--color-fd-card) 70%, transparent) 100%
  );
  border: 1px solid var(--color-fd-border);
  box-shadow: 0 30px 80px -20px rgb(0 0 0 / 0.45),
    inset 0 0 0 1px color-mix(in oklab, var(--brand-cisco) 12%, transparent);
}

/* Subtle SVG grain layer for the landing-page hero. Inline data URI to
 * keep the request graph clean (no extra HTTP roundtrip) and so the
 * grain ships in the same statically-exported HTML chunk as the hero.
 */
.hero-grain {
  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='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.6 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  opacity: var(--brand-grain-opacity);
  mix-blend-mode: overlay;
}

/* Respect reduced-motion. The terminal animation, hero gradient
 * shimmer, and any decorative motion fall back to a static frame.
 */
@media (prefers-reduced-motion: reduce) {
  .terminal-cursor {
    animation: none !important;
  }
}

@keyframes terminal-blink {
  0%, 49% {
    opacity: 1;
  }
  50%, 100% {
    opacity: 0;
  }
}

.terminal-cursor {
  animation: terminal-blink 1s steps(2, end) infinite;
}

/* Rotating connector word in the hero h1. Each word remounts via a
 * React `key` change which retriggers this single-shot animation;
 * the absolute-positioned wrapper around it keeps the heading width
 * stable so the layout doesn't jiggle while the word swaps.
 */
@keyframes connector-word-in {
  0% {
    opacity: 0;
    transform: translateY(0.25em);
    filter: blur(2px);
  }
  60% {
    opacity: 1;
    filter: blur(0);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
    filter: blur(0);
  }
}

.connector-word-in {
  animation: connector-word-in 360ms cubic-bezier(0.2, 0.6, 0.2, 1) both;
}

/* CTA pulse — fired once via React adding the class, then auto-removes
 * itself on `animationend` so subsequent scrolls don't re-trigger.
 * The pulse expands a ring outward and fades, mimicking the iOS
 * "tap target" feedback so the eye is drawn to the install button
 * once the CTA section enters the viewport.
 */
@keyframes cta-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in oklab, var(--brand-cisco) 70%, transparent); }
  70%  { box-shadow: 0 0 0 12px color-mix(in oklab, var(--brand-cisco) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--brand-cisco) 0%, transparent); }
}

.cta-pulse {
  animation: cta-pulse 1.6s ease-out 1;
}

/* Diagram entrance animations. <DiagramLightbox> flips
 * `data-animate="entered"` on the <figure> once the diagram scrolls
 * into view; every keyframe below is scoped to that attribute so the
 * SSR-rendered SVG paints to its final state until JS hydrates and
 * the IntersectionObserver fires.
 */
@keyframes flow-node-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes flow-edge-draw {
  from { stroke-dashoffset: 600; opacity: 0.5; }
  to   { stroke-dashoffset: 0;   opacity: 1; }
}
@keyframes flow-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

[data-animate='entered'] .fd-flow-node {
  animation: flow-node-in 380ms ease-out both;
  transform-box: fill-box;
  transform-origin: center;
}
[data-animate='entered'] .fd-flow-edge {
  stroke-dasharray: 600;
  animation: flow-edge-draw 480ms ease-in-out both;
}
[data-animate='entered'] .fd-flow-edge-label {
  animation: flow-fade-in 240ms ease-out both;
}

@keyframes seq-pill-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes seq-lifeline {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}
@keyframes seq-message-in {
  from { opacity: 0; transform: translateX(-4px); }
  to   { opacity: 1; transform: translateX(0); }
}

[data-animate='entered'] .fd-seq-pill {
  animation: seq-pill-in 320ms ease-out both;
  transform-box: fill-box;
  transform-origin: top center;
}
[data-animate='entered'] .fd-seq-lifeline {
  animation: seq-lifeline 240ms ease-out both;
  transform-box: fill-box;
  transform-origin: top;
}
[data-animate='entered'] .fd-seq-message {
  animation: seq-message-in 280ms ease-out both;
  transform-box: fill-box;
  transform-origin: left center;
}
[data-animate='entered'] .fd-seq-message-label {
  animation: flow-fade-in 200ms ease-out both;
}

/* Capability matrix row stagger. The wrapper toggles
 * `data-animate="entered"` on viewport entry so the rows fade up in
 * sequence — letting the eye scan the connector list one by one
 * instead of swallowing the whole table at once.
 */
@keyframes row-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

[data-animate='entered'] .fd-row {
  animation: row-in 280ms ease-out both;
}

/* Fumadocs Card hover-lift across the docs. Targets the upstream
 * `data-card="true"` attribute so every <Cards> block (Stories
 * landing, every connector page's "next steps", Get Started landing,
 * Setup landing, the Quickstart, etc.) gains a subtle lift on hover
 * with no MDX edits. Hover-only, so screen-readers and keyboard nav
 * are unaffected.
 */
@media (prefers-reduced-motion: no-preference) {
  a[data-card='true'] {
    transition: transform 180ms ease-out, box-shadow 180ms ease-out,
      border-color 180ms ease-out;
  }
  a[data-card='true']:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 18px -10px
      color-mix(in oklab, var(--brand-cisco) 40%, transparent);
  }
}

@media (prefers-reduced-motion: reduce) {
  .connector-word-in,
  .cta-pulse,
  [data-animate='entered'] .fd-flow-node,
  [data-animate='entered'] .fd-flow-edge,
  [data-animate='entered'] .fd-flow-edge-label,
  [data-animate='entered'] .fd-seq-pill,
  [data-animate='entered'] .fd-seq-lifeline,
  [data-animate='entered'] .fd-seq-message,
  [data-animate='entered'] .fd-seq-message-label,
  [data-animate='entered'] .fd-row {
    animation: none !important;
  }
}

/* Search dialog polish — Fumadocs's FlexSearch result list paints the
 * active row with `bg-fd-accent text-fd-accent-foreground`, but the
 * breadcrumb child still has `text-fd-muted-foreground` baked in. The
 * collision drops the path text to ~3:1 contrast on the highlight
 * band; promoting it back to the accent foreground keeps the trail
 * legible in both light and dark themes (the explicit muted class
 * still beats the cascade for non-active rows). The bottom rail adds
 * a hair of breathing room so the last result snippet doesn't visually
 * butt up against the dialog chrome at the bottom of the scroll list.
 */
[role="dialog"] button[aria-selected="true"] > div:first-child,
[role="dialog"] button[aria-selected="true"] > div:first-child * {
  color: var(--color-fd-accent-foreground);
  opacity: 0.85;
}

[role="dialog"] [data-empty="false"] > div {
  padding-bottom: 0.5rem;
}
