/*
 * The look shared by the animated diagrams in `public/diagrams/core/` and
 * `public/diagrams/home/`: the panel, cards and connectors of the architecture
 * diagrams next door, with a dark palette added. `theme.js` picks the palette,
 * `lang.js` the language, `diagram.js` drives the animation; a page brings its layout
 * and only the CSS that is particular to it.
 */
* { margin: 0; padding: 0; box-sizing: border-box; }
/* The host sizes the iframe to the height `diagram.js` reports, so the document
   never needs to scroll. */
html, body { background: transparent; overflow: hidden; }
/* Authored at a fixed 720px - the width of a product page's media column - and
   scaled down to fit anything narrower. */
#frame { width: 720px; margin: 0 auto; transform-origin: top left; }

:root {
  --panel: radial-gradient(130% 85% at 50% -12%, #ffffff 0%, #eef3f8 58%, #e8eef6 100%);
  --ink: #1b2430;
  --ink-2: #5d6a78;
  --ink-3: #7e8b99;
  --card: #ffffff;
  --card-border: #e4eaf1;
  --card-shadow: 0 2px 4px rgba(20, 30, 45, .04), 0 10px 24px rgba(20, 30, 45, .07);
  --line: #cfd9e4;
  --arrow: #b3c1cf;
  --pill-bg: #eef3f8;
  --pill-border: #d7e0ea;
  --pill-ink: #3a4b5c;
  --zone-border: #bfccda;
  --zone-bg: rgba(255, 255, 255, .5);
  --num-bg: #eef1f5;
  --num-ink: #7e8b99;
  --code-bg: #f4f7fa;
  --glow-cyan: rgba(22, 198, 230, .16);
  --glow-pink: rgba(236, 45, 122, .14);
  --hot-ink: #0e8fa8;
  --accent-ink: #c8236a;
  --ok: #1a9d63;
  --bad: #e0306f;
  --bad-ink: #c81e5f;
  color-scheme: light;
}
:root[data-theme='dark'] {
  --panel: radial-gradient(130% 85% at 50% -12%, #2b2f38 0%, #21242b 58%, #1c1f25 100%);
  --ink: #eef1f5;
  --ink-2: #a6afbb;
  --ink-3: #8a94a1;
  --card: #2a2e36;
  --card-border: #3a404a;
  --card-shadow: 0 2px 4px rgba(0, 0, 0, .2), 0 10px 24px rgba(0, 0, 0, .28);
  --line: #444b57;
  --arrow: #5c6572;
  --pill-bg: #262a31;
  --pill-border: #3e4450;
  --pill-ink: #c5ccd6;
  --zone-border: #4b5361;
  --zone-bg: rgba(255, 255, 255, .025);
  --num-bg: #353a44;
  --num-ink: #9099a6;
  --code-bg: #22252c;
  --glow-cyan: rgba(22, 198, 230, .2);
  --glow-pink: rgba(236, 45, 122, .17);
  --hot-ink: #6ddcf0;
  --accent-ink: #ff7aa8;
  --ok: #3fcf8e;
  --bad: #f0528c;
  --bad-ink: #ff7aa8;
  color-scheme: dark;
}

.panel {
  position: relative;
  width: 720px;
  border-radius: 30px;
  background: var(--panel);
  overflow: hidden;
  font-family: 'Manrope', system-ui, sans-serif;
  color: var(--ink);
}
.glow { position: absolute; width: 400px; height: 400px; border-radius: 50%; pointer-events: none; }
.glow-cyan { top: -150px; left: -150px; background: radial-gradient(circle, var(--glow-cyan), transparent 70%); }
.glow-pink { bottom: -170px; right: -140px; background: radial-gradient(circle, var(--glow-pink), transparent 70%); }

.heading { font-family: 'Space Grotesk', system-ui, sans-serif; font-weight: 700; }
.mono { font-family: ui-monospace, 'JetBrains Mono', 'Cascadia Code', 'SF Mono', Menlo, monospace; }

/* A dashed boundary: what runs inside a Core, a site, a network. */
.zone {
  position: absolute;
  border: 1.5px dashed var(--zone-border);
  border-radius: 22px;
  background: var(--zone-bg);
}
.divider { position: absolute; width: 0; border-left: 1.5px dashed var(--zone-border); }

/* ---- connectors ---- */
.links { position: absolute; left: 0; top: 0; overflow: visible; }
.links path { fill: none; stroke: var(--line); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: stroke .3s, opacity .3s; }
.links path.hot { stroke: #16c6e6; }
.links path.dashed { stroke-dasharray: 2 6; }
/* A second path over a drawn link, there only to carry a labelled token along it. */
.links path.ghost { stroke: none !important; }
.links marker path { fill: var(--arrow); stroke: none; }

/* ---- nodes ---- */
.node { position: absolute; z-index: 2; transition: box-shadow .35s, transform .35s, opacity .35s; }
.card {
  display: flex; align-items: center; gap: 11px;
  height: 52px; padding: 0 12px 0 10px;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 14px;
  box-shadow: var(--card-shadow);
}
.card > :not(.fill, .badge) { position: relative; }
/* The active state is the diagrams' highlighted-card gradient, faded in. The cyan
   end sits past the edge so white text never lands on it (2:1). */
.fill {
  position: absolute; inset: -1px;
  border-radius: inherit;
  background: linear-gradient(90deg, #ec2d7a 0%, #9a54c4 58%, #16c6e6 125%);
  opacity: 0;
  transition: opacity .35s;
}
.tile {
  flex: none;
  width: 32px; height: 32px;
  border-radius: 10px;
  background: linear-gradient(135deg, #16c6e6, #ec2d7a);
  /* The active state veils the tile with an inset shadow rather than swapping its
     background: a gradient cannot transition, and the swap blanked the icon for a
     frame while the card's own fill was still fading in. */
  box-shadow: inset 0 0 0 40px rgba(255, 255, 255, 0), 0 6px 14px rgba(120, 60, 140, .22);
  transition: box-shadow .35s;
  display: flex; align-items: center; justify-content: center;
}
.tile svg, .person svg, .check svg, .icon {
  width: 18px; height: 18px;
  fill: none; stroke: #fff; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round;
}
.title { display: block; font-size: 15px; line-height: 1.15; color: var(--ink); transition: color .35s; }
.sub { display: block; margin-top: 2px; font-size: 11.5px; font-weight: 600; color: var(--ink-2); transition: color .35s; }
.num {
  margin-left: auto;
  padding: 3px 7px;
  border-radius: 999px;
  font-size: 11px;
  color: var(--num-ink);
  background: var(--num-bg);
  transition: color .35s, background .35s;
}

.chip { height: 40px; gap: 9px; padding: 0 10px 0 7px; border-radius: 12px; }
.chip .tile { width: 26px; height: 26px; border-radius: 8px; }
.chip .tile svg { width: 15px; height: 15px; }
.chip .title { font-size: 13px; }
.chip .sub { font-size: 10.5px; margin-top: 1px; }

.card.on, .person.on { transform: translateY(-1px); box-shadow: 0 14px 30px rgba(120, 60, 140, .3); }
.on .fill { opacity: 1; }
/* Scoped to cards: a lit Core keeps its label, which sits outside the disc on the
   panel's own background. */
.card.on .title { color: #fff; }
.card.on .sub { color: rgba(255, 255, 255, .9); }
.card.on .tile { box-shadow: inset 0 0 0 40px rgba(255, 255, 255, .22), 0 6px 14px rgba(120, 60, 140, 0); }
.card.on .num { color: #fff; background: rgba(255, 255, 255, .22); }

.person {
  width: 44px; height: 44px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--card);
  border: 1px solid var(--card-border);
  box-shadow: var(--card-shadow);
}
.person svg { position: relative; width: 22px; height: 22px; stroke: var(--ink-2); transition: stroke .35s; }
.person.on svg { stroke: #fff; }
.check {
  position: absolute; right: -7px; bottom: -5px;
  width: 22px; height: 22px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, #16c6e6, #ec2d7a);
  box-shadow: 0 0 0 2px var(--card), 0 4px 10px rgba(120, 60, 140, .3);
  opacity: 0;
  transform: scale(.3);
  transition: opacity .3s, transform .45s cubic-bezier(.34, 1.56, .64, 1);
}
.check svg { width: 13px; height: 13px; stroke-width: 3; }

/*
 * A Collectu Core: the round mark the original artwork used, on a disc with a soft
 * halo. Placed by its centre - `left`/`top` name the middle of the disc - so links
 * can aim at the coordinates the page already uses.
 */
.core {
  width: 72px; height: 72px;
  transform: translate(-50%, -50%);
}
.core::before {
  content: '';
  position: absolute; inset: -16px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(154, 84, 196, .34), rgba(22, 198, 230, .12) 55%, transparent 72%);
  opacity: .55;
  transition: opacity .35s, transform .35s;
}
.core .disc {
  position: absolute; inset: 0;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--card);
  border: 1px solid var(--card-border);
  box-shadow: var(--card-shadow);
  transition: transform .35s, box-shadow .35s;
}
.core img { width: 58px; height: 58px; }
.core .label {
  position: absolute; left: 50%; top: 100%;
  margin-top: 9px;
  transform: translateX(-50%);
  font-size: 13px; white-space: nowrap; text-align: center;
  color: var(--ink);
}
.core .label .sub { margin-top: 1px; font-size: 10.5px; }
/* Under the disc by default; to a side where a link leaves from below. */
.core .label.above { top: auto; bottom: 100%; margin: 0 0 9px; }
.core .label.left { left: auto; right: 100%; top: 50%; margin: 0 16px 0 0; transform: translateY(-50%); text-align: right; }
.core .label.right { left: 100%; top: 50%; margin: 0 0 0 16px; transform: translateY(-50%); text-align: left; }
.core.on::before { opacity: 1; transform: scale(1.18); }
.core.on .disc { transform: scale(1.06); box-shadow: 0 0 0 3px rgba(22, 198, 230, .45), 0 14px 30px rgba(120, 60, 140, .3); }

/* ---- labels ---- */
.pill {
  position: absolute; z-index: 2;
  transform: translate(-50%, -50%);
  padding: 4px 11px;
  border-radius: 999px;
  font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; white-space: nowrap;
  color: var(--pill-ink);
  background: var(--pill-bg);
  border: 1px solid var(--pill-border);
  transition: color .3s, border-color .3s, box-shadow .3s, opacity .3s;
}
.pill.vertical { writing-mode: vertical-rl; transform: translate(-50%, -50%) rotate(180deg); padding: 11px 4px; }
.pill.hot { color: var(--hot-ink); border-color: rgba(22, 198, 230, .65); box-shadow: 0 0 0 3px rgba(22, 198, 230, .15); }

.caption { position: absolute; display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--ink); }
.caption .tile { width: 24px; height: 24px; border-radius: 8px; box-shadow: none; }
.caption .tile svg { width: 14px; height: 14px; }
.eyebrow { position: absolute; font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); }
.legend { position: absolute; display: flex; align-items: center; justify-content: flex-end; gap: 8px; font-size: 14px; color: var(--ink); }
.legend img { width: 26px; height: 26px; }

/* A small status line - a coloured dot and a word - that pages recolour by state. */
.status {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .04em;
  color: var(--ink-3);
  transition: color .3s;
}
.status::before {
  content: '';
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
  transition: background .3s, box-shadow .3s;
}
.status.ok { color: var(--ok); }
.status.bad { color: var(--bad-ink); }

/* A status sitting on a card's top edge, like a notification badge. */
.badge {
  position: absolute; top: -11px; right: 12px; z-index: 1;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--card);
  border: 1px solid var(--card-border);
  box-shadow: 0 2px 6px rgba(20, 30, 45, .08);
  white-space: nowrap;
}

.code {
  padding: 9px 12px;
  border-radius: 10px;
  background: var(--code-bg);
  font-family: ui-monospace, 'JetBrains Mono', 'Cascadia Code', 'SF Mono', Menlo, monospace;
  font-size: 11.5px; line-height: 1.75;
  color: var(--ink-2);
  white-space: pre;
}

/* A badge that shows only once the page's CSS says so: a story's verdict on a step. */
.badge.cond { opacity: 0; transform: translateY(4px); transition: opacity .3s, transform .3s; }
.badge .status { white-space: nowrap; }

/* One summary line under a story, with the figure that changes as it plays. */
.stat { position: absolute; font-size: 12px; font-weight: 600; color: var(--ink-2); white-space: nowrap; }
.stat b { color: var(--ink); font-weight: 700; }

/* ---- data in flight ---- */
.dot, .token {
  position: absolute; left: 0; top: 0; z-index: 4;
  offset-anchor: center;
  offset-rotate: 0deg;
  opacity: 0;
  pointer-events: none;
}
.dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: #16c6e6;
  box-shadow: 0 0 10px #16c6e6, 0 0 20px rgba(37, 224, 255, .55);
}
.token {
  padding: 3px 9px;
  border-radius: 999px;
  background: linear-gradient(90deg, #ec2d7a, #9a54c4);
  color: #fff;
  font-family: 'Space Grotesk', system-ui, sans-serif;
  font-size: 11px; font-weight: 700; line-height: 1.3; white-space: nowrap;
  box-shadow: 0 6px 16px rgba(120, 60, 140, .35);
}
.dot.run, .token.run { animation: travel 1s ease-in-out both; }
@keyframes travel {
  0% { offset-distance: 0%; opacity: 0; }
  12% { opacity: 1; }
  88% { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  #frame *, #frame *::before, #frame *::after { animation: none !important; transition: none !important; }
}
