/* Crypto Intel — shared design system for cryptointel.pro.
   Extends the Mini App's mint-on-deep-teal language and pushes it to a
   full-desktop, premium register: layered glass, gradient hairlines, a single
   brand gradient reserved for moments that matter, and motion that is always
   opt-out via prefers-reduced-motion.

   Load order: core.css -> site.css (landing) or app.css (workspace). */

/* ---------------------------------------------------------------- tokens */
:root {
  color-scheme: dark;

  /* Surfaces, darkest to lightest. The page is near-black so the mint reads
     as light rather than paint. */
  --ink-900: #040f11;
  --ink-850: #071518;
  --ink-800: #0a1c1f;
  --ink-750: #0e2428;
  --ink-700: #123036;
  --ink-650: #17393f;

  --text: #eef6f3;
  --muted: #93aeaa;
  --faint: #6b8783;

  --mint: #68d6bd;
  --mint-hi: #9ef0d2;
  --mint-dim: rgba(104, 214, 189, .16);
  --cyan: #5ec9e8;
  --violet: #9b8cf7;     /* reserved for AI surfaces only */
  --amber: #e6b86b;
  --danger: #f47772;
  --ok: #55d6a0;

  --line: rgba(154, 180, 173, .14);
  --line-strong: rgba(154, 180, 173, .26);
  --glass: rgba(12, 32, 36, .66);
  --glass-hi: rgba(18, 48, 54, .72);

  --grad-brand: linear-gradient(115deg, #9ef0d2 0%, #68d6bd 34%, #5ec9e8 68%, #9b8cf7 100%);
  --grad-ai: linear-gradient(120deg, #9b8cf7, #5ec9e8);
  --grad-hair: linear-gradient(120deg, rgba(158,240,210,.55), rgba(94,201,232,.22) 45%, rgba(155,140,247,.35));

  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-xl: 28px;
  --r-pill: 999px;

  --sh-1: 0 1px 0 rgba(255,255,255,.05) inset, 0 8px 24px rgba(0,0,0,.28);
  --sh-2: 0 24px 70px rgba(0,0,0,.42);
  --sh-glow: 0 0 0 1px rgba(104,214,189,.28), 0 12px 40px rgba(104,214,189,.16);

  --ease: cubic-bezier(.22,.7,.2,1);
  --ease-back: cubic-bezier(.34,1.4,.5,1);
  --dur: .34s;

  --shell: min(1240px, 100% - 40px);
  --nav-h: 68px;

  --font-display: "Syne", "Segoe UI", system-ui, sans-serif;
  --font-body: "DM Sans", system-ui, -apple-system, sans-serif;
  --font-mono: "SFMono-Regular", ui-monospace, "JetBrains Mono", Menlo, monospace;
}

/* --------------------------------------------------------------- reset */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  color: var(--text);
  background: var(--ink-900);
  min-height: 100vh;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 { font-family: var(--font-display); margin: 0; line-height: 1.1; letter-spacing: -.03em; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
img, svg, canvas { max-width: 100%; display: block; }
button, input, select, textarea { font: inherit; color: inherit; }
::selection { background: rgba(104,214,189,.28); color: #fff; }

/* Ambient background: two slow aurora fields plus fixed film grain. Both are
   pointer-events:none so they never eat a click. */
body::before {
  content: "";
  position: fixed; inset: -20vh -10vw;
  z-index: -2; pointer-events: none;
  background:
    radial-gradient(48vw 40vw at 12% -6%, rgba(104,214,189,.16), transparent 62%),
    radial-gradient(42vw 36vw at 92% 8%, rgba(94,201,232,.11), transparent 60%),
    radial-gradient(50vw 44vw at 62% 96%, rgba(155,140,247,.09), transparent 62%),
    linear-gradient(160deg, #040f11, #071a1d 46%, #050f14);
  animation: aurora 26s var(--ease) infinite alternate;
}
body::after {
  content: "";
  position: fixed; inset: 0; z-index: -1; pointer-events: none; opacity: .16;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.4'/%3E%3C/svg%3E");
}
@keyframes aurora {
  0%   { transform: translate3d(0,0,0) scale(1); }
  100% { transform: translate3d(-2%, 1.5%, 0) scale(1.06); }
}

/* --------------------------------------------------------------- layout */
.shell { width: var(--shell); margin-inline: auto; }
.stack { display: grid; gap: 14px; }
.row { display: flex; align-items: center; gap: 12px; }
.row.wrap { flex-wrap: wrap; }
.spread { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.grow { flex: 1 1 auto; min-width: 0; }
.hidden { display: none !important; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ------------------------------------------------------------ typography */
.eyebrow {
  font-size: 11.5px; letter-spacing: .18em; text-transform: uppercase;
  font-weight: 700; color: var(--mint);
}
.display { font-size: clamp(34px, 6.2vw, 74px); letter-spacing: -.045em; }
.h2 { font-size: clamp(26px, 3.4vw, 42px); }
.h3 { font-size: clamp(19px, 2vw, 24px); }
.lead { color: var(--muted); font-size: clamp(15px, 1.35vw, 18.5px); line-height: 1.65; }
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.mono { font-family: var(--font-mono); font-size: .92em; letter-spacing: -.01em; }
.gradient-text {
  background: var(--grad-brand);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.balance { text-wrap: balance; }

/* --------------------------------------------------------------- buttons */
.btn {
  --btn-bg: rgba(255,255,255,.06);
  --btn-fg: var(--text);
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 12px 20px; border-radius: var(--r-md);
  border: 1px solid var(--line-strong);
  background: var(--btn-bg); color: var(--btn-fg);
  font-weight: 600; font-size: 14.5px; cursor: pointer; white-space: nowrap;
  transition: transform .16s var(--ease), box-shadow .22s var(--ease),
              border-color .22s var(--ease), background .22s var(--ease), filter .2s var(--ease);
}
/* Grow, never move.
   A hover transform that SHIFTS the element is self-cancelling: a pointer
   resting in the bottom 2px of the button is inside it, so :hover applies, so
   the button rises out from under the pointer, so :hover is lost, so it drops
   back — an oscillation that reads as the shine sweep strobing whenever the
   cursor sits near the button's edge. Scaling up cannot do this: every point
   that was inside stays inside. */
.btn:hover:not(:disabled) { transform: scale(1.025); border-color: rgba(104,214,189,.45); background: rgba(104,214,189,.12); }
.btn:active:not(:disabled) { transform: scale(.985); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn:focus-visible { outline: 2px solid var(--mint); outline-offset: 3px; }

.btn-primary {
  border: 0; color: #04181a; font-weight: 800;
  /* Clips the shine sweep below. Without it the sweep is painted (and
     hit-tested) outside the button. */
  overflow: hidden;
  background: var(--grad-brand); background-size: 180% 180%;
  box-shadow: var(--sh-glow);
  animation: brand-drift 9s ease-in-out infinite alternate;
}
.btn-primary:hover:not(:disabled) {
  background: var(--grad-brand); background-size: 180% 180%;
  filter: brightness(1.06); box-shadow: 0 0 0 1px rgba(158,240,210,.5), 0 16px 46px rgba(104,214,189,.3);
}
@keyframes brand-drift { 0% { background-position: 0% 50%; } 100% { background-position: 100% 50%; } }

/* Light sweep on hover — the one gimmick allowed on primary CTAs.
   The sweep is parked outside the button at translateX(-130%), so the button
   needs `overflow: hidden` (above) to keep a white streak from painting beside
   it; `pointer-events: none` keeps the generated box out of hit-testing. */
.btn-primary::after {
  content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 30%, rgba(255,255,255,.55) 48%, transparent 62%);
  transform: translateX(-130%); transition: transform .7s var(--ease);
}
.btn-primary:hover::after { transform: translateX(130%); }

.btn-ghost { background: transparent; border-color: var(--line); }
.btn-ai { border-color: rgba(155,140,247,.42); background: rgba(155,140,247,.13); color: #d9d2ff; }
.btn-ai:hover:not(:disabled) { background: rgba(155,140,247,.2); border-color: rgba(155,140,247,.6); }
.btn-sm { padding: 8px 13px; font-size: 13px; border-radius: var(--r-sm); }
.btn-lg { padding: 15px 26px; font-size: 16px; border-radius: var(--r-lg); }
.btn-block { width: 100%; }
.btn-icon { padding: 10px; width: 40px; height: 40px; }

/* ----------------------------------------------------------------- cards */
.card {
  position: relative;
  background: var(--glass);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 22px;
  backdrop-filter: blur(14px);
  box-shadow: var(--sh-1);
}
/* Gradient hairline that only lights up on hover — cheaper and calmer than a
   permanent glowing border on every card. */
.card-lift { transition: transform .3s var(--ease), border-color .3s var(--ease), box-shadow .3s var(--ease); }
.card-lift::before {
  content: ""; position: absolute; inset: -1px; border-radius: inherit; padding: 1px;
  background: var(--grad-hair); opacity: 0; transition: opacity .3s var(--ease);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none;
}
/* Same trap as .btn, and worse here: the unstable band is 4px tall. Elevation
   is carried by the shadow and the gradient hairline instead of by motion —
   a scale would be stable but softens the body copy inside the card. */
.card-lift:hover { box-shadow: var(--sh-2); border-color: var(--line-strong); }
.card-lift:hover::before { opacity: 1; }

.pill {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 13px; border-radius: var(--r-pill);
  background: rgba(255,255,255,.05); border: 1px solid var(--line);
  font-size: 12.5px; color: var(--muted);
}
.pill-mint { background: var(--mint-dim); border-color: rgba(104,214,189,.3); color: var(--mint-hi); }
.pill-ai { background: rgba(155,140,247,.14); border-color: rgba(155,140,247,.32); color: #cfc6ff; }
.pill-amber { background: rgba(230,184,107,.13); border-color: rgba(230,184,107,.3); color: var(--amber); }

.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--mint); flex: 0 0 auto; }
.dot-live { box-shadow: 0 0 0 0 rgba(104,214,189,.6); animation: ping 2.2s var(--ease) infinite; }
@keyframes ping {
  0%   { box-shadow: 0 0 0 0 rgba(104,214,189,.5); }
  70%  { box-shadow: 0 0 0 9px rgba(104,214,189,0); }
  100% { box-shadow: 0 0 0 0 rgba(104,214,189,0); }
}

/* ---------------------------------------------------------------- fields */
.field { display: grid; gap: 7px; }
.field > span { font-size: 12px; color: var(--muted); letter-spacing: .02em; }
.input, .select, .textarea {
  width: 100%; padding: 12px 14px;
  background: rgba(4,15,17,.72); color: var(--text);
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  outline: none; transition: border-color .2s var(--ease), box-shadow .2s var(--ease), background .2s var(--ease);
}
.input:focus, .select:focus, .textarea:focus {
  border-color: rgba(104,214,189,.55);
  box-shadow: 0 0 0 4px rgba(104,214,189,.12);
  background: rgba(4,15,17,.9);
}
.input::placeholder, .textarea::placeholder { color: var(--faint); }
.textarea { resize: vertical; min-height: 88px; }
.select {
  -webkit-appearance: none; appearance: none; padding-right: 34px;
  background-image:
    linear-gradient(45deg, transparent 50%, #7dcfb8 50%),
    linear-gradient(135deg, #7dcfb8 50%, transparent 50%);
  background-position: calc(100% - 18px) calc(50% - 2px), calc(100% - 12px) calc(50% - 2px);
  background-size: 6px 6px, 6px 6px; background-repeat: no-repeat;
}
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* A field the assistant has just filled, so the user's eye follows the change. */
@keyframes field-flash {
  0%   { box-shadow: 0 0 0 0 rgba(155,140,247,.5); border-color: rgba(155,140,247,.85); }
  100% { box-shadow: 0 0 0 14px rgba(155,140,247,0); border-color: var(--line-strong); }
}
.field-flash { animation: field-flash 1.1s var(--ease) 2; }

/* -------------------------------------------------------------- segmented */
.seg {
  display: inline-flex; padding: 4px; gap: 3px;
  background: rgba(255,255,255,.05); border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.seg button {
  border: 0; background: transparent; color: var(--muted); cursor: pointer;
  padding: 8px 15px; border-radius: 10px; font-size: 13.5px; font-weight: 600;
  transition: color .2s var(--ease), background .2s var(--ease);
}
.seg button.on { background: var(--mint-dim); color: var(--mint-hi); }
.seg button:hover:not(.on) { color: var(--text); }

/* ----------------------------------------------------- language switcher */
/* Lived in site.css, which the workspace does not load — so /app rendered
   three unstyled browser buttons and gave no sign of which language was on.
   It is a shared control, so it belongs to the shared sheet. */
.lang {
  display: inline-flex; gap: 2px; padding: 3px; border-radius: var(--r-sm);
  background: rgba(255,255,255,.05); border: 1px solid var(--line);
}
.lang button {
  border: 0; background: transparent; color: var(--faint);
  padding: 5px 9px; border-radius: 7px; font-size: 12px; font-weight: 700;
  cursor: pointer; font-family: inherit;
  transition: color .2s var(--ease), background .2s var(--ease);
}
.lang button:hover:not(.on) { color: var(--text); }
.lang button.on { background: var(--mint-dim); color: var(--mint-hi); }

/* Переключатель-select: пять языков в ряд кнопок не влезали в шапку телефона.
   .select растягивается на всю ширину — этому даём ширину по содержимому. */
.lang-select {
  width: auto; min-width: 66px; padding: 7px 26px 7px 10px;
  font-size: 12px; font-weight: 700;
}

/* -------------------------------------------------------------- tooltips */
/* Any element with data-tip gets a hover/focus popover from core.js.
   Written as a real element (not ::after) so it can escape overflow clipping
   and be read by the assistant's spotlight. */
.tip-pop {
  position: fixed; z-index: 9000; max-width: 268px;
  padding: 10px 13px; border-radius: 12px;
  background: rgba(8,26,29,.97); border: 1px solid rgba(104,214,189,.28);
  color: var(--text); font-size: 13px; line-height: 1.5;
  box-shadow: var(--sh-2); pointer-events: none;
  opacity: 0; transform: translateY(5px) scale(.97);
  transition: opacity .16s var(--ease), transform .16s var(--ease);
  /* A 34-character TRON address is one unbreakable token and this box is
     268px wide, so without this the address ran straight out through the
     rounded border — the tooltip looked torn in half. Every tip that carries
     an address, a hash or a URL has the same shape. */
  overflow-wrap: anywhere;
}
.tip-pop.on { opacity: 1; transform: translateY(0) scale(1); }
.tip-pop b { color: var(--mint-hi); }
.has-tip { border-bottom: 1px dashed rgba(104,214,189,.4); cursor: help; }

/* ---------------------------------------------------------------- toasts */
.toasts {
  /* Sits above the AI dock, which owns the bottom-right corner. */
  position: fixed; z-index: 9500; right: 18px; bottom: 88px;
  display: grid; gap: 10px; width: min(360px, calc(100vw - 36px));
}
.toast {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 13px 15px; border-radius: var(--r-md);
  background: rgba(8,26,29,.96); border: 1px solid var(--line-strong);
  box-shadow: var(--sh-2); font-size: 14px;
  animation: toast-in .3s var(--ease-back) both;
  /* The host is 360px anchored right, but a grid item's min-width is its
     content, and a public link is one unbroken 70-character token: the box
     grew past its host and off the phone's right edge, wearing none of its
     own styling by the time it was screenshotted. Cap the box, let the text
     break, and let the flex child shrink. */
  max-width: 100%;
}
.toast .grow { min-width: 0; overflow-wrap: anywhere; }
.toast.err { border-color: rgba(244,119,114,.45); }
.toast.ok { border-color: rgba(104,214,189,.45); }
.toast .toast-x { margin-left: auto; cursor: pointer; color: var(--faint); background: none; border: 0; }
@keyframes toast-in { from { opacity: 0; transform: translateX(24px) scale(.96); } }

/* ---------------------------------------------------------------- modals */
.modal-back {
  position: fixed; inset: 0; z-index: 9200;
  background: rgba(2,8,9,.72); backdrop-filter: blur(8px);
  display: grid; place-items: center; padding: 22px;
  animation: fade-in .2s var(--ease) both;
}
.modal {
  width: min(660px, 100%); max-height: 86vh; overflow: auto;
  background: linear-gradient(160deg, rgba(14,36,40,.98), rgba(8,24,27,.98));
  border: 1px solid var(--line-strong); border-radius: var(--r-xl);
  padding: 26px; box-shadow: var(--sh-2);
  animation: modal-in .34s var(--ease-back) both;
}
@keyframes fade-in { from { opacity: 0; } }
@keyframes modal-in { from { opacity: 0; transform: translateY(18px) scale(.97); } }

/* ------------------------------------------------------- scroll reveals */
/* Hidden only once the observer is actually running: if the module fails to
   load or the browser is ancient, the page must still show its content. */
html.reveal-ready .reveal { opacity: 0; transform: translateY(26px); }
.reveal { transition: opacity .7s var(--ease), transform .7s var(--ease); }
html.reveal-ready .reveal.in { opacity: 1; transform: none; }
.reveal-d1 { transition-delay: .07s; }
.reveal-d2 { transition-delay: .14s; }
.reveal-d3 { transition-delay: .21s; }
.reveal-d4 { transition-delay: .28s; }

/* --------------------------------------------------- spotlight (AI/tour) */
/* Four panels around the target instead of one big box-shadow: this keeps the
   hole crisp at any border-radius and lets the target stay interactive. */
.spot-layer { position: fixed; inset: 0; z-index: 9300; pointer-events: none; }
.spot-layer .spot-mask {
  position: absolute; background: rgba(2,8,9,.66); pointer-events: auto;
  transition: all .3s var(--ease);
}
.spot-ring {
  position: fixed; z-index: 9310; border-radius: 14px; pointer-events: none;
  border: 2px solid var(--mint); box-shadow: 0 0 0 6px rgba(104,214,189,.16), 0 0 40px rgba(104,214,189,.35);
  transition: all .34s var(--ease-back);
  animation: ring-pulse 1.8s var(--ease) infinite;
}
.spot-ring.ai { border-color: var(--violet); box-shadow: 0 0 0 6px rgba(155,140,247,.18), 0 0 40px rgba(155,140,247,.4); }
@keyframes ring-pulse { 50% { box-shadow: 0 0 0 11px rgba(104,214,189,.05), 0 0 46px rgba(104,214,189,.28); } }
.spot-note {
  position: fixed; z-index: 9320; max-width: 320px;
  padding: 14px 16px; border-radius: var(--r-md);
  background: rgba(10,30,34,.98); border: 1px solid rgba(104,214,189,.35);
  box-shadow: var(--sh-2); font-size: 13.5px; line-height: 1.55;
  animation: modal-in .3s var(--ease-back) both;
}
.spot-note.ai { border-color: rgba(155,140,247,.45); }
.spot-note .spot-actions { display: flex; gap: 8px; margin-top: 12px; }
.spot-note .spot-step { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--faint); margin-bottom: 6px; }

/* --------------------------------------------------------- skeleton/load */
.skel {
  background: linear-gradient(100deg, rgba(255,255,255,.04) 30%, rgba(255,255,255,.10) 50%, rgba(255,255,255,.04) 70%);
  background-size: 220% 100%; border-radius: 10px;
  animation: skel 1.3s linear infinite;
}
@keyframes skel { to { background-position: -220% 0; } }

.spinner {
  width: 15px; height: 15px; border-radius: 50%; flex: 0 0 auto;
  border: 2px solid rgba(255,255,255,.18); border-top-color: var(--mint);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ------------------------------------------------------------ scrollbars */
* { scrollbar-width: thin; scrollbar-color: rgba(104,214,189,.3) transparent; }
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(104,214,189,.22); border-radius: 9px; border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: rgba(104,214,189,.4); background-clip: content-box; }

/* ---------------------------------------------------------- AI dock */
/* The guide is the only place violet appears in the product, so "AI is
   talking" is legible at a glance and never confused with a risk colour. */
.ai-dock { position: fixed; right: 20px; bottom: 20px; z-index: 9100; }

.ai-fab {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 11px 18px 11px 12px; border-radius: var(--r-pill);
  background: rgba(10,28,32,.92); color: var(--text);
  border: 1px solid rgba(155,140,247,.4); cursor: pointer;
  box-shadow: 0 14px 44px rgba(0,0,0,.42), 0 0 0 1px rgba(155,140,247,.12);
  backdrop-filter: blur(12px);
  transition: transform .24s var(--ease-back), box-shadow .24s var(--ease);
}
/* Scale only — same hover-oscillation trap as .btn above. */
.ai-fab:hover { transform: scale(1.05); box-shadow: 0 20px 54px rgba(155,140,247,.3); }
.ai-fab-label { font-size: 14px; font-weight: 600; }
.ai-dock.open .ai-fab { opacity: 0; pointer-events: none; transform: scale(.9); }

/* Breathing orb — the one element allowed to loop forever. */
.ai-fab-orb, .ai-orb-sm {
  width: 22px; height: 22px; border-radius: 50%; flex: 0 0 auto;
  background: var(--grad-ai); background-size: 200% 200%;
  box-shadow: 0 0 18px rgba(155,140,247,.6);
  animation: orb 4.5s var(--ease) infinite alternate;
}
.ai-orb-sm { width: 30px; height: 30px; }
@keyframes orb {
  0%   { background-position: 0% 50%; transform: scale(1); }
  100% { background-position: 100% 50%; transform: scale(1.12); }
}

.ai-panel {
  position: fixed; right: 20px; bottom: 20px;
  width: min(392px, calc(100vw - 32px)); max-height: min(660px, calc(100vh - 40px));
  display: flex; flex-direction: column;
  background: linear-gradient(165deg, rgba(16,34,44,.985), rgba(8,22,26,.985));
  border: 1px solid rgba(155,140,247,.28); border-radius: var(--r-xl);
  box-shadow: 0 30px 90px rgba(0,0,0,.55);
  backdrop-filter: blur(18px);
  animation: modal-in .3s var(--ease-back) both;
  overflow: hidden;
}
/* `display:flex` above would otherwise beat the [hidden] attribute. */
.ai-panel[hidden] { display: none; }
.ai-head { display: flex; align-items: center; gap: 11px; padding: 16px 16px 12px; border-bottom: 1px solid var(--line); }
.ai-head .ai-title { font-family: var(--font-display); font-size: 16px; display: block; }
.ai-head .ai-sub { font-size: 12px; }
.ai-log { flex: 1 1 auto; overflow-y: auto; padding: 16px; display: grid; gap: 11px; align-content: start; }

.ai-msg {
  max-width: 88%; padding: 11px 14px; border-radius: 15px;
  font-size: 14px; line-height: 1.58; white-space: pre-wrap; overflow-wrap: anywhere;
  animation: msg-in .26s var(--ease) both;
}
.ai-assistant { background: rgba(155,140,247,.11); border: 1px solid rgba(155,140,247,.22); justify-self: start; border-bottom-left-radius: 5px; }
.ai-user { background: var(--mint-dim); border: 1px solid rgba(104,214,189,.26); justify-self: end; border-bottom-right-radius: 5px; }
@keyframes msg-in { from { opacity: 0; transform: translateY(7px); } }

.ai-typing { display: inline-flex; gap: 4px; padding: 2px 0; }
.ai-typing i { width: 6px; height: 6px; border-radius: 50%; background: var(--violet); animation: typing 1.1s var(--ease) infinite; }
.ai-typing i:nth-child(2) { animation-delay: .16s; }
.ai-typing i:nth-child(3) { animation-delay: .32s; }
@keyframes typing { 0%,60%,100% { opacity: .28; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-4px); } }

.ai-proposal {
  justify-self: start; max-width: 92%;
  display: grid; gap: 8px; padding: 13px;
  border-radius: 15px; border: 1px dashed rgba(155,140,247,.42);
  background: rgba(155,140,247,.07);
}
.ai-proposal-title { font-weight: 700; font-size: 13.5px; }
.ai-proposal-meta { font-size: 11.5px; color: var(--muted); overflow-wrap: anywhere; }

.ai-receipt, .ai-contact {
  justify-self: start; max-width: 92%; display: grid; gap: 9px; padding: 12px 13px;
  border-radius: 13px; border: 1px solid rgba(104,214,189,.28);
  background: rgba(104,214,189,.07); font-size: 12.5px;
}
.ai-receipt { grid-template-columns: 1fr auto; align-items: center; }
.ai-receipt .btn, .ai-receipt-detail { grid-column: 1 / -1; justify-self: start; }
.ai-receipt-detail { font-size: 11.5px; }
.ai-contact .input { min-width: 0; width: 100%; }
.ai-contact p { margin: 0; font-size: 11.5px; line-height: 1.45; }
.ai-contact-error { color: var(--risk-high); }
.ai-support { border-color: rgba(246, 190, 92, .34); background: rgba(246, 190, 92, .08); }

/* Wrap rather than scroll sideways. A single row was 937px wide inside a 390px
   dock with the scrollbar hidden, so two of the four starter prompts were cut
   off mid-word with nothing to show they continued. */
.ai-chips { display: flex; flex-wrap: wrap; gap: 7px; padding: 0 16px 10px; }
/* An author `display` beats the user-agent rule for [hidden], so hiding the
   strip from JS needs this line or the attribute does nothing. */
.ai-chips[hidden] { display: none; }
.ai-chip {
  flex: 0 1 auto; max-width: 100%; padding: 7px 12px; border-radius: var(--r-pill);
  background: rgba(255,255,255,.05); border: 1px solid var(--line);
  color: var(--muted); font-size: 12.5px; cursor: pointer;
  /* A long prompt (a whole address) may be clipped, but with an ellipsis that
     says so, and the full text stays in the title attribute. */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: border-color .2s var(--ease), color .2s var(--ease);
}
.ai-chip:hover { border-color: rgba(155,140,247,.5); color: var(--text); }

.ai-form { display: flex; gap: 8px; padding: 0 16px 10px; }
.ai-form .ai-send { padding: 12px 16px; }
.ai-foot { padding: 0 16px 14px; font-size: 11.5px; }

@media (max-width: 520px) {
  .ai-panel { right: 8px; left: 8px; bottom: 8px; width: auto; max-height: 78vh; }
  .ai-dock { right: 14px; bottom: 14px; }
  .ai-fab-label { display: none; }
  .ai-fab { padding: 12px; }
}

/* -------------------------------------------------- command palette */
.cmdk-back {
  position: fixed; inset: 0; z-index: 9400;
  background: rgba(2,8,9,.7); backdrop-filter: blur(10px);
  display: grid; align-items: start; justify-items: center; padding: 12vh 20px 20px;
  animation: fade-in .16s var(--ease) both;
}
.cmdk {
  width: min(620px, 100%);
  background: linear-gradient(165deg, rgba(16,38,42,.99), rgba(8,22,26,.99));
  border: 1px solid var(--line-strong); border-radius: var(--r-lg);
  box-shadow: var(--sh-2); overflow: hidden;
  animation: modal-in .26s var(--ease-back) both;
}
.cmdk input {
  width: 100%; padding: 18px 20px; border: 0; background: transparent;
  font-size: 16.5px; outline: none; border-bottom: 1px solid var(--line);
}
.cmdk-list { max-height: 46vh; overflow-y: auto; padding: 8px; display: grid; gap: 2px; }
.cmdk-item {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 13px; border-radius: 11px; cursor: pointer;
  border: 1px solid transparent; text-align: left; background: transparent; width: 100%;
}
.cmdk-item.on, .cmdk-item:hover { background: var(--mint-dim); border-color: rgba(104,214,189,.24); }
.cmdk-item .k { font-size: 14px; }
.cmdk-item .d { font-size: 12px; color: var(--muted); margin-left: auto; }
.cmdk-foot { padding: 9px 16px; border-top: 1px solid var(--line); font-size: 11.5px; color: var(--faint); display: flex; gap: 14px; }
kbd {
  font-family: var(--font-mono); font-size: 11px; padding: 2px 6px;
  border-radius: 6px; background: rgba(255,255,255,.07); border: 1px solid var(--line);
}

/* --------------------------------------------------------------- a11y */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; scroll-behavior: auto !important;
  }
  /* Specificity, not intent, decided this before: the hiding rule is
     `html.reveal-ready .reveal` (0-2-1) and a bare `.reveal` (0-1-0) loses to
     it inside a media query, because media queries do not add weight. So a
     visitor with Reduce Motion on still got every section held at opacity 0,
     waiting for a scroll observer whose transition had just been shortened to
     nothing. The opt-out has to outrank the thing it opts out of. */
  html.reveal-ready .reveal,
  html.reveal-ready .reveal.in { opacity: 1; transform: none; transition: none; }
}

/* An address is a control, not a label: one click copies it, two open the
   explorer. It has to look pressable, and the confirmation has to appear ON
   it — a toast in the corner is not an answer to "did that work?". Scoped to
   .addr-gestures so a page that never installed the handler renders plain
   text instead of a control that does nothing. */
.addr-gestures .addr-copy {
  position: relative;
  cursor: pointer;
  border-radius: 6px;
  padding: 1px 4px;
  margin: 0 -4px;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  border-bottom: 1px dashed rgba(120, 200, 180, .38);
  transition: background-color .18s ease, color .18s ease;
}
.addr-gestures .addr-copy:hover,
.addr-gestures .addr-copy:focus-visible { background: rgba(120, 200, 180, .12); outline: none; }
.addr-gestures .addr-copy:focus-visible { box-shadow: 0 0 0 2px rgba(120, 200, 180, .45); }
.addr-gestures .addr-copy.addr-copied { background: rgba(120, 200, 180, .20); }
.addr-gestures .addr-copy.addr-copied::after {
  content: attr(data-copied-label) " ✓";
  position: absolute; left: 50%; bottom: calc(100% + 6px); transform: translateX(-50%);
  white-space: nowrap; pointer-events: none; z-index: 60;
  font-size: 12px; font-weight: 600;
  color: #06231f; background: #78c8b4;
  padding: 3px 9px; border-radius: 999px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .35);
  animation: addr-copied-pop .22s ease-out;
}
@keyframes addr-copied-pop {
  from { opacity: 0; transform: translate(-50%, 4px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* The embedded trace player: a whole page of its own, so it gets room and a
   frame rather than being squeezed into the chat column. */
.trace-frame {
  width: 100%; height: min(78vh, 900px); min-height: 560px;
  border: 1px solid var(--line-strong); border-radius: var(--r-lg);
  background: #0d1a1b; display: block;
}
#invPlayer { margin-top: 16px; }
