/* GENESIS — app styles on top of ui.css */
:root {
  --accent: #a78bfa;
  --accent-2: #8b5cf6;
  --accent-fg: #0b0715;
  --bg: #08070d;
  --bg-1: #0d0b15;
  --bg-2: #12101c;
  --bg-3: #191626;
  --line: #221e33;
  --line-2: #2e2842;
}

.hero { padding: 46px 0 26px; }
.hero h1 { font-size: 42px; letter-spacing: -.035em; margin-bottom: 12px; line-height: 1.08; }
.hero p { font-size: 16.5px; color: var(--text-dim); max-width: 660px; }
@media (max-width: 560px) { .hero h1 { font-size: 28px; } .hero { padding: 26px 0 18px; } }

/* agent card */
.agent-card {
  border: 1px solid var(--line); border-radius: 15px; background: var(--bg-1);
  padding: 16px; cursor: pointer; transition: border-color .12s, background .12s, transform .12s;
  display: flex; flex-direction: column; gap: 12px;
}
.agent-card:hover { border-color: var(--accent); background: var(--bg-2); transform: translateY(-1px); }
.agent-card .top { display: flex; gap: 12px; align-items: flex-start; }
.agent-card .nm { font-weight: 660; letter-spacing: -.012em; line-height: 1.25; }
.agent-card .sym { color: var(--accent); font-size: 12.5px; font-weight: 700; }
.agent-card .tag {
  font-size: 12.5px; color: var(--text-faint); line-height: 1.5; min-height: 38px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.agent-card .nums { display: grid; grid-template-columns: repeat(4, 1fr); gap: 7px; }
.agent-card .nums .c { text-align: center; padding: 7px 3px; background: var(--bg); border-radius: 8px; }
.agent-card .nums .c .v { font: 700 13px var(--mono); }
.agent-card .nums .c .k { font-size: 9px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-faint); margin-top: 2px; }

.ident { border-radius: 12px; flex: none; }

/* autonomy badge */
.auto { font-size: 10.5px; padding: 2px 8px; border-radius: 99px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; }
.auto.cautious { background: color-mix(in srgb, var(--text-dim) 18%, transparent); color: var(--text-dim); }
.auto.normal { background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent); }
.auto.bold { background: color-mix(in srgb, var(--amber) 18%, transparent); color: var(--amber); }

/* activity feed */
.act { display: flex; gap: 11px; padding: 11px 0; border-bottom: 1px solid var(--line); align-items: flex-start; }
.act:last-child { border-bottom: none; }
.act .ic {
  width: 28px; height: 28px; border-radius: 8px; flex: none; display: grid; place-items: center;
  font-size: 13px; background: var(--bg-3);
}
.act.executed .ic { background: color-mix(in srgb, var(--green) 16%, transparent); }
.act.denied .ic { background: color-mix(in srgb, var(--red) 16%, transparent); }
.act.pending .ic { background: color-mix(in srgb, var(--amber) 16%, transparent); }
.act.vetoed .ic { background: color-mix(in srgb, var(--red) 22%, transparent); }
.act .t { font-size: 13.5px; font-weight: 580; }
.act .d { font-size: 12.5px; color: var(--text-faint); margin-top: 2px; line-height: 1.5; }

/* permission row */
.perm { padding: 13px 0; border-bottom: 1px solid var(--line); }
.perm:last-child { border-bottom: none; }
.perm .hd { display: flex; align-items: center; gap: 10px; }
.perm .nm { font-weight: 610; font-size: 14px; flex: 1; }
.perm .caps { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 7px; }
.perm .cap { font-size: 11.5px; color: var(--text-faint); }
.perm .cap b { color: var(--text-dim); font-family: var(--mono); }
.perm.off { opacity: .48; }

.toggle {
  width: 36px; height: 20px; border-radius: 99px; background: var(--bg-3); position: relative;
  cursor: pointer; border: 1px solid var(--line-2); flex: none; transition: background .15s;
}
.toggle::after {
  content: ''; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px;
  border-radius: 50%; background: var(--text-faint); transition: transform .15s, background .15s;
}
.toggle.on { background: color-mix(in srgb, var(--accent) 40%, transparent); border-color: var(--accent); }
.toggle.on::after { transform: translateX(16px); background: var(--accent); }

/* budget bar */
.budget { display: flex; height: 10px; border-radius: 99px; overflow: hidden; background: var(--bg-3); }
.budget .seg { transition: width .5s ease; }
.budget .seg.art { background: #f472b6; }
.budget .seg.dev { background: #60a5fa; }
.budget .seg.bounty { background: #fbbf24; }
.budget .seg.ops { background: #94a3b8; }
.budget .seg.free { background: var(--bg-3); }
.legend { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 10px; font-size: 12px; }
.legend .i { display: flex; align-items: center; gap: 6px; color: var(--text-dim); }
.legend .sw { width: 9px; height: 9px; border-radius: 3px; }

/* pending action */
.pending-card {
  border: 1px solid var(--amber); border-radius: 12px; padding: 14px;
  background: color-mix(in srgb, var(--amber) 7%, transparent);
}

.tl { border-left: 2px solid var(--line); padding-left: 15px; }
.post-box { padding: 12px 0; border-bottom: 1px solid var(--line); }
.post-box:last-child { border-bottom: none; }
.post-box .b { font-size: 14px; line-height: 1.6; white-space: pre-wrap; }
.post-box .m { font-size: 11.5px; color: var(--text-faint); margin-top: 6px; display: flex; gap: 13px; }

.filters { display: flex; gap: 5px; flex-wrap: wrap; }
.filters button {
  background: transparent; border: 1px solid var(--line); color: var(--text-dim);
  padding: 6px 11px; border-radius: 8px; font: 500 12.5px var(--sans); cursor: pointer;
}
.filters button:hover { background: var(--bg-2); color: var(--text); }
.filters button.on { background: var(--bg-3); color: var(--text); border-color: var(--accent); }

.market-item { border: 1px solid var(--line); border-radius: 12px; padding: 14px; background: var(--bg-1); }
.market-item:hover { border-color: var(--line-2); }
.mono-sm { font-family: var(--mono); font-size: 12px; }

/* ---- brand mark ----
   The art is white-on-black, so it sits on its own dark chip rather than the
   page background — that keeps the halftone edge from dissolving into the
   surrounding surface wherever the header sits over a lighter panel. */
.brand-mark {
  width: 26px; height: 26px; border-radius: 7px; flex: none;
  background: #000; object-fit: cover;
  box-shadow: 0 0 0 1px var(--line-2), 0 0 14px rgba(255,255,255,.08);
}

/* ---- hero banner ---- */
.hero-banner {
  margin: 0 0 26px; border-radius: 16px; overflow: hidden;
  border: 1px solid var(--line-2); background: #000;
  box-shadow: 0 18px 50px rgba(0,0,0,.55);
  aspect-ratio: 2000 / 668;
}
.hero-banner img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 700px) {
  /* Crop tighter on a phone so the figure and wordmark stay legible. */
  .hero-banner { aspect-ratio: 16 / 9; }
  .hero-banner img { object-position: 28% center; }
}

/* ═══════════════════════════════════════════════════════════════════
   GENESIS — monochrome + glitch
   ═══════════════════════════════════════════════════════════════════
   Overrides the shared design system's tokens. These live here, not in
   ui.css, because ui.css is copied from _core by sync-core.mjs and any
   edit there would be overwritten (and would repaint REVIVE and Thread
   too). Everything below is scoped to this app on purpose.
   ─────────────────────────────────────────────────────────────────── */

:root {
  /* Surfaces have to separate from the page by value alone here — there is
     no hue to lean on. An earlier pass put cards at #060606 on a #000 page
     with #1e1e1e borders and they were invisible. */
  --bg: #000000;
  --bg-1: #0d0d0d;
  --bg-2: #151515;
  --bg-3: #1f1f1f;
  --line: #2b2b2b;
  --line-2: #3d3d3d;
  --text: #f4f4f4;
  --text-dim: #9a9a9a;
  /* #5e5e5e measured 3.0:1 against the card surface — below the 4.5:1 floor,
     and it is used on 11px uppercase labels where legibility is already tight. */
  --text-faint: #858585;

  /* White is the accent. A filled button becomes an inverted block, which
     is the strongest mark this palette can make. */
  --accent: #ffffff;
  --accent-2: #cfcfcf;
  --accent-fg: #000000;

  /* Status still has to be legible at a glance — "denied" and "executed"
     look identical in pure greyscale. These are desaturated hard so the
     page still reads black-and-white, while keeping the distinction. */
  --green: #b9ccbe;
  --red: #d8a9a9;
  --amber: #cfc6ab;

  --shadow: 0 1px 2px rgba(0,0,0,.8), 0 10px 34px rgba(0,0,0,.65);
}

/* ---- screen texture -------------------------------------------------
   Two fixed overlays: scanlines and grain. Both are pointer-events:none
   and sit above the page but below any dialog. */
body::before {
  content: ''; position: fixed; inset: 0; z-index: 9998; pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255,255,255,.028) 0px,
    rgba(255,255,255,.028) 1px,
    transparent 1px,
    transparent 3px
  );
  mix-blend-mode: overlay;
}
body::after {
  content: ''; position: fixed; inset: -50%; z-index: 9997; pointer-events: none;
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: grain 900ms steps(3) infinite;
}
@keyframes grain {
  0%   { transform: translate(0, 0); }
  33%  { transform: translate(-3%, 2%); }
  66%  { transform: translate(2%, -2%); }
  100% { transform: translate(0, 0); }
}

/* ---- the headline tears occasionally --------------------------------
   Mostly still. The animation sits at rest for ~92% of its cycle and
   tears briefly, because a headline that jitters constantly is unreadable
   and stops reading as a glitch at all. */
.hero h1 {
  position: relative;
  letter-spacing: -.02em;
  animation: tear 7s infinite steps(1);
}
@keyframes tear {
  0%, 90%, 100% { transform: none; text-shadow: none; clip-path: none; }
  91% { transform: translateX(-2px); text-shadow: 3px 0 rgba(255,255,255,.55), -2px 0 rgba(255,255,255,.2); }
  92% { transform: translateX(3px); clip-path: inset(18% 0 62% 0); }
  93% { transform: none; clip-path: none; text-shadow: -3px 0 rgba(255,255,255,.4); }
  94% { transform: translateX(-1px); clip-path: inset(66% 0 18% 0); }
  95% { transform: none; text-shadow: none; }
}

/* ---- technical typography ------------------------------------------
   Echoes the lockup on the banner: wide caps for labels, mono for data. */
.stat .k, .stat-label, .lbl, .card-title, th {
  text-transform: uppercase;
  letter-spacing: .14em;
  font-size: 11px;
  color: var(--text-faint);
}
.stat .v, .num, .mono { font-family: var(--mono); letter-spacing: -.02em; }

/* ---- controls --------------------------------------------------------
   Square edges. The rounded corners of the shared system read as friendly,
   which is the wrong register for this. */
.btn, .card, .panel, input, textarea, select, .pill {
  border-radius: 2px;
}
.btn { text-transform: uppercase; letter-spacing: .1em; font-size: 12px; font-weight: 600; }
.btn.primary, .btn.accent { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
.btn.primary:hover, .btn.accent:hover { background: var(--accent-2); border-color: var(--accent-2); }

/* Buttons and links flicker on hover — the one place constant motion is
   welcome, because the user asked for it by pointing at the element. */
.btn:hover, a.brand:hover, nav.main a:hover { animation: flicker 260ms steps(2) 1; }
@keyframes flicker {
  0%, 100% { opacity: 1; }
  25% { opacity: .45; transform: translateX(1px); }
  50% { opacity: 1; transform: translateX(-1px); }
  75% { opacity: .7; }
}

/* ---- brand ----------------------------------------------------------- */
.brand { text-transform: uppercase; letter-spacing: .22em; font-weight: 600; }
.brand-mark { border-radius: 2px; box-shadow: 0 0 0 1px var(--line-2); }
.hero-banner { border-radius: 2px; }

/* ---- a hairline above the fold, like a signal edge ------------------- */
header.top { border-bottom: 1px solid var(--line-2); background: rgba(0,0,0,.86); backdrop-filter: blur(10px); }

/* ---- accessibility ---------------------------------------------------
   Anyone who has asked the OS to stop moving things gets a still page.
   The texture stays; only the motion goes. */
@media (prefers-reduced-motion: reduce) {
  body::after { animation: none; }
  .hero h1 { animation: none; }
  .btn:hover, a.brand:hover, nav.main a:hover { animation: none; }
}

/* ---- glitch: interaction + arrival --------------------------------------
   Paired with glitch.js. Everything here is decoration only — nothing
   depends on it to be legible, and it all stops under reduced motion. */

/* A card tears very slightly under the cursor. Small enough to feel like
   interference rather than movement. */
.card:hover, .rowitem:hover {
  animation: card-tear 420ms steps(2) 1;
}
@keyframes card-tear {
  0%, 100% { transform: none; clip-path: none; }
  20% { transform: translateX(-1px); clip-path: inset(0 0 72% 0); }
  40% { transform: translateX(2px); clip-path: inset(48% 0 24% 0); }
  60% { transform: translateX(-1px); clip-path: inset(80% 0 0 0); }
  80% { transform: none; clip-path: none; }
}

/* New arrivals in the live feed displace as they land. */
.glitch-in { animation: arrive 360ms steps(3) 1; }
@keyframes arrive {
  0%   { opacity: 0; transform: translateX(-6px) skewX(-6deg); filter: blur(.4px); }
  40%  { opacity: 1; transform: translateX(3px) skewX(3deg); }
  70%  { transform: translateX(-1px) skewX(-1deg); }
  100% { opacity: 1; transform: none; filter: none; }
}

/* A CRT never sits perfectly still. Amplitude is deliberately tiny — enough
   to register at the edge of vision, not enough to notice directly or to
   bother anyone reading. */
body { animation: crt 6.5s ease-in-out infinite; }
@keyframes crt {
  0%, 100% { filter: none; }
  47% { filter: brightness(1.008); }
  48% { filter: brightness(.975); }
  49% { filter: brightness(1.012); }
  50% { filter: none; }
}

/* The mark catches a highlight on hover, like a head turning to a light. */
.brand:hover .brand-mark { animation: mark-flash 420ms steps(2) 1; }
@keyframes mark-flash {
  0%, 100% { filter: none; }
  30% { filter: brightness(1.7) contrast(1.2); transform: translateX(-1px); }
  60% { filter: brightness(.7); transform: translateX(1px); }
}

/* Inputs read as a terminal field rather than a form control. */
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), 0 0 18px rgba(255,255,255,.09);
}

@media (prefers-reduced-motion: reduce) {
  .card:hover, .rowitem:hover, .glitch-in, body, .brand:hover .brand-mark { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════════
   Glitch, the version that matches the art
   ═══════════════════════════════════════════════════════════════════
   The banner's language is torn horizontal slices, displaced bars, a
   blown light streak and heavy dither. The earlier pass was too polite
   to read as any of that. This is the same vocabulary applied to type
   and surfaces. ─────────────────────────────────────────────────── */

/* ---- headings tear into offset slices ------------------------------
   Two clones sit exactly behind the text and are clipped to horizontal
   bands, then shoved sideways. The real text stays put and stays
   selectable; only the clones move, and they are aria-hidden by virtue
   of being generated content. */
.gl { position: relative; display: inline-block; white-space: pre-line; }
.gl::before, .gl::after {
  content: attr(data-text);
  position: absolute; inset: 0;
  white-space: pre-line;
  pointer-events: none;
  background: var(--bg);
}
.gl::before { animation: slice-a 4.2s infinite steps(1); }
.gl::after  { animation: slice-b 3.1s infinite steps(1); }

/* Each keyframe exposes a different horizontal band and displaces it.
   Long neutral stretches keep the headline readable between tears. */
@keyframes slice-a {
  0%, 62%, 100% { clip-path: inset(50% 0 50% 0); transform: none; opacity: 0; }
  64% { clip-path: inset(12% 0 74% 0); transform: translateX(-9px); opacity: .9; }
  66% { clip-path: inset(38% 0 46% 0); transform: translateX(7px);  opacity: .9; }
  68% { clip-path: inset(66% 0 20% 0); transform: translateX(-5px); opacity: .9; }
  70% { clip-path: inset(22% 0 62% 0); transform: translateX(11px); opacity: .8; }
  72% { clip-path: inset(50% 0 50% 0); opacity: 0; }
}
@keyframes slice-b {
  0%, 80%, 100% { clip-path: inset(50% 0 50% 0); transform: none; opacity: 0; }
  82% { clip-path: inset(78% 0 8% 0);  transform: translateX(13px); opacity: .75; }
  84% { clip-path: inset(30% 0 58% 0); transform: translateX(-11px); opacity: .75; }
  86% { clip-path: inset(56% 0 32% 0); transform: translateX(6px);  opacity: .6; }
  88% { clip-path: inset(50% 0 50% 0); opacity: 0; }
}

/* ---- halftone dither ------------------------------------------------
   The art is dot-screened rather than smooth. A fine dot lattice over
   everything picks that up; it is faint on flat black and only really
   shows where the page is bright. */
body::before {
  background-image:
    radial-gradient(circle at 50% 50%, rgba(255,255,255,.055) .5px, transparent .6px),
    repeating-linear-gradient(to bottom,
      rgba(255,255,255,.03) 0 1px, transparent 1px 3px);
  background-size: 3px 3px, 100% 3px;
  mix-blend-mode: normal;
}

/* ---- light streaks --------------------------------------------------
   The blown horizontal flare across the visor, borrowed as a section
   divider. Drawn, not animated, so it costs nothing. */
.shead, .card-title {
  position: relative;
}
.shead::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -7px; height: 1px;
  background: linear-gradient(90deg,
    transparent, rgba(255,255,255,.65) 12%, rgba(255,255,255,.15) 30%,
    transparent 46%, rgba(255,255,255,.35) 62%, transparent 88%);
  filter: blur(.3px);
}

/* A bar that sweeps the hero banner every so often, like a tracking
   error crossing the frame. */
.hero-banner { position: relative; }
.hero-banner::after {
  content: ''; position: absolute; left: 0; right: 0; height: 14%;
  background: linear-gradient(180deg,
    transparent, rgba(255,255,255,.10) 40%, rgba(255,255,255,.16) 52%, transparent);
  mix-blend-mode: screen; pointer-events: none;
  animation: sweep 9s cubic-bezier(.9,.02,.2,1) infinite;
}
@keyframes sweep {
  0%, 74% { top: -16%; opacity: 0; }
  76% { opacity: 1; }
  84% { top: 102%; opacity: 1; }
  86%, 100% { top: 102%; opacity: 0; }
}

/* ---- blown highlights ----------------------------------------------- */
.stat .v, .hero h1 { text-shadow: 0 0 22px rgba(255,255,255,.14); }
.btn.primary, .btn.accent { box-shadow: 0 0 22px rgba(255,255,255,.16); }

@media (prefers-reduced-motion: reduce) {
  .gl::before, .gl::after, .hero-banner::after { animation: none; opacity: 0; }
}
