/* Nexo — brand system.
   Palette is straight from the brand pack. Gradients, glow and motion live here, in the
   runtime state layer; the canonical mark itself is flat geometry and never changes shape. */

:root {
  /* pack palette */
  --nexo-blue: #2563ff;
  --electric-blue: #3b82f6;
  --neon-cyan: #22d3ee;
  --deep-navy: #0a0f1e;
  --charcoal: #111827;
  --white: #ffffff;

  /* derived surfaces */
  --bg: var(--deep-navy);
  --surface: var(--charcoal);
  --surface-2: #172033;
  --line: #22304a;
  --text: #e9eefb;
  --muted: #8496b5;
  --accent: var(--nexo-blue);
  --accent-2: var(--electric-blue);
  /* not in the pack — chosen to sit with it for the ERROR state */
  --danger: #ff5468;

  --radius: 14px;
  --pad: 16px;

  --font: 'Segoe UI Variable Display', 'Segoe UI', -apple-system, BlinkMacSystemFont,
    'SF Pro Display', system-ui, Roboto, 'Helvetica Neue', Arial, sans-serif;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.5 var(--font);
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}

body {
  min-height: 100dvh;
  /* a single, very soft brand wash — the only gradient in the chrome */
  background-image: radial-gradient(
    120% 80% at 50% -10%,
    rgba(37, 99, 255, 0.16),
    transparent 60%
  );
  background-attachment: fixed;
}

.app {
  max-width: 720px;
  margin: 0 auto;
  padding: 0 var(--pad) calc(48px + env(safe-area-inset-bottom));
}

.hidden {
  display: none !important;
}

.sprite {
  position: absolute;
  width: 0;
  height: 0;
}

/* ============================================================== the mark */

.mark {
  --mark-size: 32px;
  --mark-color: var(--accent);
  --mark-glow: rgba(37, 99, 255, 0.55);
  position: relative;
  display: inline-grid;
  place-items: center;
  width: var(--mark-size);
  height: var(--mark-size);
  color: var(--mark-color);
  flex-shrink: 0;
}

.mark.is-sm {
  --mark-size: 26px;
}
.mark.is-lg {
  --mark-size: 92px;
}
.mark.is-xl {
  --mark-size: 116px;
}

.mark-glyph {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  transition:
    color 240ms ease,
    transform 240ms ease;
}

/* Soft light behind the mark. This is the state layer — never the mark itself. */
.mark-aura {
  position: absolute;
  inset: -38%;
  z-index: 1;
  border-radius: 50%;
  background: radial-gradient(circle, var(--mark-glow) 0%, transparent 68%);
  opacity: 0.5;
  transition: opacity 300ms ease;
}

/* A ring that orbits the mark. The mark stays upright: the pack says never rotate it. */
.mark-orbit {
  position: absolute;
  inset: -22%;
  z-index: 1;
  border-radius: 50%;
  border: 2px solid transparent;
  border-top-color: var(--mark-color);
  border-right-color: color-mix(in srgb, var(--mark-color) 35%, transparent);
  opacity: 0;
  transition: opacity 300ms ease;
}

/* The four-point spark that sits in the cut-out during work, as in the pack. */
.mark-spark {
  position: absolute;
  z-index: 3;
  width: 26%;
  height: 26%;
  background: var(--white);
  clip-path: polygon(
    50% 0%,
    58% 42%,
    100% 50%,
    58% 58%,
    50% 100%,
    42% 58%,
    0% 50%,
    42% 42%
  );
  opacity: 0;
  transform: scale(0.6);
  transition:
    opacity 240ms ease,
    transform 240ms ease;
}

/* --- states ---------------------------------------------------------- */

.mark[data-state='idle'] .mark-aura {
  opacity: 0.32;
}

.mark[data-state='thinking'] .mark-aura {
  opacity: 0.75;
  animation: aura-breathe 2.4s ease-in-out infinite;
}
.mark[data-state='thinking'] .mark-glyph {
  animation: glyph-breathe 2.4s ease-in-out infinite;
}

.mark[data-state='routing'] .mark-orbit {
  opacity: 1;
  animation: orbit-spin 1.6s linear infinite;
}
.mark[data-state='routing'] .mark-aura {
  opacity: 0.6;
}

.mark[data-state='executing'] {
  --mark-color: var(--electric-blue);
  --mark-glow: rgba(59, 130, 246, 0.7);
}
.mark[data-state='executing'] .mark-aura {
  opacity: 0.95;
  animation: aura-breathe 1.1s ease-in-out infinite;
}
.mark[data-state='executing'] .mark-orbit {
  opacity: 0.9;
  animation: orbit-spin 1s linear infinite;
}
.mark[data-state='executing'] .mark-spark {
  opacity: 1;
  transform: scale(1);
  animation: spark-pulse 1.1s ease-in-out infinite;
}

.mark[data-state='waiting'] {
  --mark-color: var(--neon-cyan);
  --mark-glow: rgba(34, 211, 238, 0.6);
}
.mark[data-state='waiting'] .mark-aura {
  opacity: 0.8;
  animation: aura-breathe 2.8s ease-in-out infinite;
}
.mark[data-state='waiting'] .mark-spark {
  opacity: 0.9;
  transform: scale(0.9);
  animation: spark-blink 2.8s ease-in-out infinite;
}

.mark[data-state='complete'] {
  --mark-glow: rgba(37, 99, 255, 0.85);
}
.mark[data-state='complete'] .mark-aura {
  opacity: 1;
}
.mark[data-state='complete'] .mark-glyph {
  animation: settle 520ms cubic-bezier(0.2, 0.8, 0.2, 1) 1;
}

.mark[data-state='error'] {
  --mark-color: var(--danger);
  --mark-glow: rgba(255, 84, 104, 0.6);
}
.mark[data-state='error'] .mark-aura {
  opacity: 0.85;
}

@keyframes aura-breathe {
  0%,
  100% {
    opacity: 0.45;
    transform: scale(0.94);
  }
  50% {
    opacity: 1;
    transform: scale(1.06);
  }
}

@keyframes glyph-breathe {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.035);
  }
}

@keyframes orbit-spin {
  to {
    transform: rotate(360deg);
  }
}

@keyframes spark-pulse {
  0%,
  100% {
    opacity: 0.75;
    transform: scale(0.85);
  }
  50% {
    opacity: 1;
    transform: scale(1.15);
  }
}

@keyframes spark-blink {
  0%,
  100% {
    opacity: 0.25;
  }
  50% {
    opacity: 1;
  }
}

@keyframes settle {
  0% {
    transform: scale(1.12);
  }
  100% {
    transform: scale(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .mark-aura,
  .mark-glyph,
  .mark-orbit,
  .mark-spark {
    animation: none !important;
  }
}

/* ============================================================== chrome */

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: calc(10px + env(safe-area-inset-top)) 0 10px;
  background: linear-gradient(var(--bg) 72%, transparent);
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}

.wordmark {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1;
}

.badge {
  font-size: 11px;
  letter-spacing: 0.04em;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--muted);
  white-space: nowrap;
}

.badge.good {
  color: var(--accent-2);
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
}

.badge.bad {
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 45%, transparent);
}

.icon-button {
  min-width: 44px;
  min-height: 44px;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 20px;
  border-radius: 12px;
  cursor: pointer;
}

.icon-button:active {
  background: var(--surface);
}

/* ====================================================== auth (mobile-first)

   One screen, no scroll with the keyboard closed. The card is the interactive
   focus; the hero is deliberately small and gives way on short viewports. The
   silhouette is the same canonical geometry as every other mark — stroked, not
   filled, pushed off the corner so only part of it reads. */

.auth-view {
  position: fixed;
  inset: 0;
  z-index: 20;
  /* Not hidden vertically: when the keyboard is open the viewport shrinks and the
     fields must still be reachable. Nothing scrolls with it closed.
     Horizontally clipped, because the ambient wash and the silhouette are both
     deliberately wider than the screen and must never produce a sideways scroll. */
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  background:
    radial-gradient(92% 52% at 76% 4%, rgba(37, 99, 255, 0.18), transparent 62%),
    linear-gradient(180deg, #0a0f1e 0%, #070b16 48%, #03060d 100%);
}

/* Both decorations are deliberately larger than the screen, so they live in their own
   clipped layer. Without it their overflow becomes scrollable area and the screen
   scrolls even though the content fits exactly. */
.auth-backdrop {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

/* The ambient sits behind the silhouette rather than centred, so the light and the mass
   read as the same event. Everything else on the page stays navy-black. */
/* The light sits BEHIND the silhouette and is tight rather than broad. The mark's own
   near-black fill occludes most of it, so what reaches the eye escapes around the rim —
   which is what makes the edge read as lit from somewhere behind the screen. */
.auth-ambient {
  position: absolute;
  top: -10vh;
  right: -20vw;
  width: 92vw;
  max-width: 640px;
  aspect-ratio: 1 / 1;
  background: radial-gradient(
    circle at 50% 50%,
    rgba(37, 99, 255, 0.16),
    rgba(37, 99, 255, 0.05) 38%,
    transparent 62%
  );
  pointer-events: none;
}

.auth-silhouette {
  position: absolute;
  top: 0;
  right: 0;
  width: min(145vw, 1000px);
  height: auto;
  aspect-ratio: 1 / 1;
  /* Percentage translate is a share of the element's OWN size, unlike `right: -x%`, which
     is a share of the container. That is what keeps the same fraction of the mark
     off-screen at every viewport width — roughly 60% of it, leaving a fragment of the
     outer edge and a sliver of the cut-out. */
  transform: translate(60%, -18%);
  filter: drop-shadow(0 0 18px rgba(37, 99, 255, 0.1));
  pointer-events: none;
}

.auth-inner {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  min-height: 100dvh;
  max-width: 420px;
  margin: 0 auto;
  padding: calc(18px + env(safe-area-inset-top)) 20px calc(14px + env(safe-area-inset-bottom));
}

.auth-lockup {
  display: flex;
  align-items: center;
  gap: 9px;
}

.auth-hero {
  margin-top: clamp(18px, 5vh, 38px);
}

.auth-headline {
  margin: 0;
  font-size: clamp(24px, 7.2vw, 30px);
  line-height: 1.16;
  letter-spacing: -0.02em;
  font-weight: 600;
  color: var(--white);
}

.auth-sub {
  margin: 9px 0 0;
  max-width: 32ch;
  font-size: 14px;
  line-height: 1.45;
  color: var(--muted);
}

/* ---------------------------------------------------------- auth card */

.auth-card {
  display: flex;
  flex-direction: column;
  gap: 11px;
  margin-top: clamp(16px, 3.4vh, 26px);
  padding: 18px 16px 16px;
  border: 1px solid rgba(233, 238, 251, 0.08);
  border-radius: 18px;
  background: rgba(15, 22, 38, 0.62);
  -webkit-backdrop-filter: blur(18px) saturate(120%);
  backdrop-filter: blur(18px) saturate(120%);
  box-shadow: 0 18px 44px rgba(2, 5, 12, 0.45);
}

/* Where the blur is unavailable the panel must not become a transparent smear. */
@supports not ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
  .auth-card {
    background: rgba(15, 22, 38, 0.93);
  }
}

.auth-card-title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.auth-lead,
.auth-note {
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--muted);
}

.auth-options {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.checkline {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--muted);
  cursor: pointer;
}

.checkline input {
  width: 16px;
  height: 16px;
  margin: 0;
  accent-color: var(--accent);
}

.linkish {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 13px;
  color: var(--accent-2);
  cursor: pointer;
}

.linkish:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.auth-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 12px;
  color: var(--muted);
}

.auth-divider::before,
.auth-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: rgba(233, 238, 251, 0.1);
}

.button.quiet {
  background: transparent;
  border: 1px solid rgba(233, 238, 251, 0.16);
  color: var(--text);
}

.button.quiet:active {
  background: rgba(233, 238, 251, 0.06);
}

.auth-legal {
  margin: auto 0 0;
  padding-top: 16px;
  text-align: center;
  font-size: 11px;
  line-height: 1.5;
  color: rgba(132, 150, 181, 0.9);
}

/* --------------------------------------------- fitting the short viewport */

/* The supporting line is the first thing to go: the headline and the card
   carry the screen on their own. */
.auth-view[data-mode='register'] .auth-sub,
.auth-view[data-mode='reset'] .auth-sub {
  display: none;
}

@media (max-height: 730px) {
  .auth-sub {
    display: none;
  }
}

/* The register card is one field taller than sign-in. On a phone in Safari — where the
   toolbars take roughly 160px off the nominal height — that extra row is what would push
   the screen into scrolling, so the hero stands down first. */
@media (max-height: 780px) {
  .auth-view[data-mode='register'] .auth-hero {
    display: none;
  }
}

@media (max-height: 640px) {
  .auth-hero {
    display: none;
  }
  .auth-card {
    margin-top: clamp(14px, 3vh, 20px);
  }
}

/* ------------------------------------------------------- wider viewports */

@media (min-width: 720px) and (min-height: 700px) {
  .auth-inner {
    max-width: 448px;
    padding-top: 44px;
  }
  .auth-headline {
    font-size: 32px;
  }
}

/* ---------------------------------------------------------- lockup */

.lockup {
  display: grid;
  justify-items: center;
  gap: 14px;
  padding: 26px 0 30px;
  text-align: center;
}

.lockup-word {
  margin: 0;
  font-size: 46px;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
}

.lockup-tagline {
  margin: 0;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.34em;
  color: var(--accent-2);
}

.footnote {
  margin: 22px 0 0;
  text-align: center;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.3em;
  color: var(--muted);
  opacity: 0.7;
}

/* ------------------------------------------------------ state hero */

.state-hero {
  display: grid;
  justify-items: center;
  gap: 10px;
  padding: 20px 0 16px;
}

.state-label {
  margin: 0;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.26em;
  color: var(--muted);
}

/* ------------------------------------------------------ typography */

.headline {
  font-size: 26px;
  line-height: 1.25;
  margin: 18px 0 14px;
  letter-spacing: -0.02em;
}

.section {
  margin-top: 26px;
}

.section-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--muted);
  margin: 0 0 10px;
}

.muted {
  color: var(--muted);
  font-size: 14px;
}

.error {
  color: var(--danger);
  font-size: 14px;
  margin: 4px 0 0;
}

.request {
  font-size: 18px;
  margin: 4px 0 18px;
  line-height: 1.4;
}

/* ---------------------------------------------------------- inputs */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--pad);
}

.card.small {
  padding: 12px 14px;
}

.card-title {
  font-size: 15px;
  margin: 0 0 8px;
}

.form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* A label + input pair. Wrapping them lets a whole field be hidden as one unit while the
   spacing stays identical to fields sitting directly in the form. */
.field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.label {
  font-size: 12px;
  color: var(--muted);
}

.input,
.textarea {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--text);
  border-radius: 10px;
  padding: 12px;
  font: inherit;
  font-size: 16px; /* keeps iOS Safari from zooming on focus */
}

.textarea {
  resize: vertical;
  min-height: 110px;
}

.input:focus,
.textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: transparent;
}

.composer {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.composer-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.attach {
  flex: 1;
  font-size: 14px;
  color: var(--muted);
  border: 1px dashed var(--line);
  border-radius: 10px;
  padding: 11px 12px;
  cursor: pointer;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.file-input {
  display: none;
}

.button {
  min-height: 46px;
  padding: 0 18px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.button:active {
  transform: translateY(1px);
}

.button[disabled] {
  opacity: 0.5;
  cursor: default;
}

.button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--white);
  box-shadow: 0 6px 20px -8px rgba(37, 99, 255, 0.9);
}

.button.ghost {
  background: transparent;
  color: var(--muted);
}

.button.danger {
  background: transparent;
  border-color: color-mix(in srgb, var(--danger) 45%, transparent);
  color: var(--danger);
}

.button-row {
  display: flex;
  gap: 10px;
  margin-top: 12px;
  flex-wrap: wrap;
}

/* -------------------------------------------------------- pipeline */

.pipeline {
  list-style: none;
  display: flex;
  gap: 6px;
  padding: 0 0 4px;
  margin: 0 0 18px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.stage {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
}

.stage .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--line);
}

.stage.done {
  color: var(--text);
}

.stage.done .dot {
  background: var(--accent);
}

.stage.active {
  color: var(--accent-2);
  border-color: color-mix(in srgb, var(--accent) 60%, transparent);
  background: rgba(37, 99, 255, 0.08);
}

.stage.active .dot {
  background: var(--accent-2);
  animation: pulse 1.2s ease-in-out infinite;
}

.stage.failed {
  color: var(--danger);
  border-color: color-mix(in srgb, var(--danger) 45%, transparent);
}

.stage.failed .dot {
  background: var(--danger);
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.25;
  }
}

@media (prefers-reduced-motion: reduce) {
  .stage.active .dot {
    animation: none;
  }
}

/* ----------------------------------------------------------- lists */

.task-list,
.step-list,
.event-log,
.plain-list,
.caveats {
  list-style: none;
  margin: 0;
  padding: 0;
}

.task-list li {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
  margin-bottom: 8px;
  background: var(--surface);
  cursor: pointer;
}

.task-list li:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}

.task-list .row {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  align-items: center;
}

.task-list .title {
  font-size: 15px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.step-list li {
  border: 1px solid var(--line);
  border-left-width: 3px;
  border-radius: 10px;
  padding: 10px 12px;
  margin-bottom: 8px;
  background: var(--surface);
}

.step-list li.succeeded {
  border-left-color: var(--accent);
}
.step-list li.failed,
.step-list li.rejected {
  border-left-color: var(--danger);
}
.step-list li.running {
  border-left-color: var(--accent-2);
}
.step-list li.awaiting_approval {
  border-left-color: var(--neon-cyan);
}
.step-list li.skipped {
  border-left-color: var(--muted);
}

.step-head {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  align-items: baseline;
}

.step-tool {
  font-size: 11px;
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.code {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  line-height: 1.45;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-x: auto;
  margin: 8px 0 0;
  max-height: 260px;
}

.event-log li {
  display: flex;
  gap: 8px;
  font-size: 13px;
  color: var(--muted);
  padding: 5px 0;
  border-bottom: 1px solid var(--line);
}

.event-log .time {
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  opacity: 0.7;
  flex-shrink: 0;
}

.plain-list li {
  border-bottom: 1px solid var(--line);
  padding: 10px 0;
  font-size: 14px;
}

.plain-list li strong {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  color: var(--accent-2);
}

.caveats li {
  font-size: 13px;
  color: var(--neon-cyan);
  padding: 3px 0 3px 14px;
  position: relative;
}

.caveats li::before {
  content: '!';
  position: absolute;
  left: 0;
  opacity: 0.8;
}

/* -------------------------------------------------------- specials */

.approval {
  border-color: color-mix(in srgb, var(--neon-cyan) 45%, transparent);
  box-shadow: 0 10px 40px -24px var(--neon-cyan);
}

.approval-reason {
  margin: 0;
  font-size: 14px;
}

.result {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: 0 10px 40px -24px var(--accent);
}

.result-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.answer {
  white-space: pre-wrap;
  margin: 6px 0 0;
}

.crit {
  display: flex;
  gap: 8px;
  font-size: 13px;
  padding: 4px 0;
}

.crit .mark-ok {
  flex-shrink: 0;
}

.crit.met .mark-ok {
  color: var(--accent-2);
}

.crit.unmet .mark-ok {
  color: var(--danger);
}

/* ------------------------------------------------------ wide screens */

@media (min-width: 640px) {
  .app {
    padding-inline: 24px;
  }
  .headline {
    font-size: 30px;
  }
}
