/* Premium layer. Loaded after every other stylesheet so it can normalise the
   decisions that drifted across seven pages: one typeface, one radius scale, one
   motion vocabulary, one material recipe and one set of page metrics.

   It deliberately does NOT touch the pieces that already carry the brand:
   the traveling cyan-to-ember composer border, the Earth/lava scene, the vendor
   marks, the HUD corner brackets, or any background that owns a pointer-tracked
   spotlight. Those are overridden nowhere below except to add a material shadow
   that does not replace their background. */

/* ========================================================================== */
/* 1. Typeface                                                                */
/* ========================================================================== */

body,
button,
input,
textarea,
select {
  font-family: var(--font-sans);
}

body {
  font-feature-settings: var(--font-feature-sans);
  font-synthesis: none;
  text-rendering: optimizeLegibility;
}

/* The two select stylesheets set the family through the `font` shorthand, which
   would otherwise escape the rule above. */
.workspace-page .select-trigger,
.workspace-page .select-menu {
  font-family: var(--font-sans);
  font-feature-settings: var(--font-feature-sans);
}

p,
li,
dd,
blockquote {
  text-wrap: pretty;
}

/* Numeric readouts must not reflow as they tick. */
#soc-clock,
.recent-row time,
.h-when,
.h-history time,
.processing-track + *,
[data-numeric] {
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--font-feature-tabular);
}

/* Monospace is the "engineered instrument" voice: telemetry, identifiers,
   hashes, session ids and timecodes only. Never body copy. */
.strap-telemetry,
#soc-clock,
.recent-row time,
.h-when,
#session-id,
.tool-id,
.composer-mode,
.processing-badge,
.login-page .strap {
  font-family: var(--font-mono);
  font-feature-settings: var(--font-feature-tabular);
  letter-spacing: 0.02em;
}

/* ========================================================================== */
/* 2. Radius scale                                                            */
/* ========================================================================== */

/* Structural surfaces: panels and cards share one radius so nested content can
   be concentric (outer radius minus the padding that separates the two boxes). */
.workspace-page
  :is(.panel, .context-card, .agent-card, .platform-card, .help-bar, .agent-workspace-card),
.home-page .panel,
.login-page .login-card {
  border-radius: var(--r-xl);
}

.source,
.user-message,
.bot-message,
.table-card {
  border-radius: var(--r-lg);
}

.workspace-page :is(.action, .platform, .field, .theme, .toggle-row, .panel-content) {
  border-radius: var(--r-lg);
}

.recent-row,
.select-option,
.workspace-page .nav {
  border-radius: var(--r-sm);
}

.workspace-page :is(.select-trigger, .fld input, .fld select, .fld textarea),
#include-message,
.ask form button:not(.select-trigger) {
  border-radius: var(--r-md);
}

.workspace-page .select-menu {
  border-radius: var(--r-xl);
}

.workspace-page :is(.select-option-icon, .source) {
  border-radius: var(--r-md);
}

/* Pills are for tags, filters and tabs. Buttons - including .ghost - take the
   button radius from the secondary tier instead. */
.workspace-page :is(.env-tag, .system-status, .filter, .tab, .tabs, .agent-select),
.suggestions button {
  border-radius: var(--r-pill);
}

#menu,
.sidebar-close,
#profile-menu,
.command-search {
  border-radius: var(--r-md);
}

#profile-menu,
.command-palette-card {
  border-radius: var(--r-lg);
}

dialog,
#command-palette {
  border-radius: var(--r-2xl);
}

.ask kbd,
.agent-search kbd,
kbd {
  border-radius: var(--r-xs);
}

/* ========================================================================== */
/* 3. Page metrics                                                            */
/* ========================================================================== */

/* One header height, one content width, one gutter. The investigation page is
   exempt: it is a full-height workspace with its own rail geometry. */
:is(.workspace-page, .home-page):not(.investigation-page) .canvas > header {
  height: 72px;
  padding-inline: 32px;
}

:is(.workspace-page, .home-page):not(.investigation-page) main {
  max-width: 1560px;
  padding-inline: 32px;
}

/* ========================================================================== */
/* 4. Material: layered glass and elevation                                   */
/* ========================================================================== */

/* One light source, top-down. Every surface gets a top highlight, a hairline
   inner ring, a lower shade, then a cast shadow at its elevation. */
.workspace-page
  :is(.panel, .context-card, .agent-card, .platform-card, .help-bar, .agent-workspace-card) {
  border: 1px solid var(--glass-edge);
  box-shadow: var(--glass-light), var(--glass-ring), var(--glass-shade), var(--el-3);
}

/* The home panels own a pointer-tracked radial spotlight, so only the material
   and the cast shadow are layered on; the background is left intact. */
.home-page .panel {
  border-color: var(--glass-edge);
  box-shadow: var(--glass-light), var(--glass-shade), var(--el-3);
}

.home-page .panel:hover {
  border-color: var(--glass-edge-strong);
  box-shadow:
    var(--glass-light),
    var(--glass-shade),
    var(--el-4),
    0 0 0 1px #ff6a0014;
}

.panel::before,
.panel::after {
  content: none !important;
  display: none !important;
}

.home-page .action {
  border-color: var(--glass-edge);
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(var(--lift, 0px));
  transform-style: preserve-3d;
  will-change: auto;
  box-shadow:
    var(--glass-light),
    0 2px 8px #00000059;
  transition:
    transform var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out),
    border-color var(--dur-2) var(--ease-out),
    background var(--dur-2) var(--ease-out);
}

/* Compositing is promoted only while the pointer is on the card. Leaving it on
   permanently costs memory across every row on the page. */
.home-page .action:hover,
.home-page .action:focus-visible {
  --lift: -3px;
  will-change: transform;
  border-color: #ff8a32aa;
  box-shadow:
    var(--glass-light),
    var(--sx, 0px) var(--sy, 0px) 22px #00000080,
    var(--el-3),
    0 0 24px #ff6a001f;
}

.home-page .action:active {
  --lift: -1px;
  transition-duration: var(--dur-1);
}

/* Controls sit one elevation below the surface that holds them. */
.workspace-page :is(.suggestions button, .ghost, .filter, .tabs, .agent-select),
.command-trigger,
.env-tag,
.system-status {
  box-shadow:
    var(--glass-light),
    0 1px 3px #0000004d;
}

.workspace-page :is(.select-trigger, .fld input, .fld select, .fld textarea) {
  box-shadow:
    inset 0 1px 0 #00000059,
    inset 0 0 0 1px #ffffff08,
    0 1px 2px #00000040;
}

.workspace-page :is(.select-trigger:focus-visible, .is-open .select-trigger) {
  box-shadow:
    inset 0 1px 0 #00000059,
    0 0 0 3px #ff6a0028,
    0 0 22px #ff6a001e;
}

.workspace-page .primary,
.home-page .ask form button:not(.select-trigger),
.workspace-page .send,
.login-page .submit {
  box-shadow:
    inset 0 1px 0 #ffe0b8a6,
    inset 0 -1px 0 #a1300059,
    0 4px 16px #ff433826;
}

.workspace-page .primary:hover,
.home-page .ask form button:not(.select-trigger):hover,
.workspace-page .send:hover {
  box-shadow:
    inset 0 1px 0 #ffe0b8b8,
    inset 0 -1px 0 #a1300059,
    0 8px 26px #ff43383d;
}

.workspace-page dialog,
#profile-menu,
.select-menu {
  box-shadow: var(--glass-light), var(--glass-ring), var(--el-4);
}

/* Rail and header read as chrome: darker, flatter, tighter edge. */
.workspace-page aside,
.home-page aside {
  box-shadow:
    1px 0 0 #ffffff0a,
    18px 0 48px -34px #000000a6;
}

.workspace-page .canvas > header,
.home-page .canvas > header {
  border-bottom: none;
  background-image: linear-gradient(180deg, #050a0e99, #050a0e00);
}

/* ========================================================================== */
/* 5. Grain                                                                   */
/* ========================================================================== */

/* Near-black gradients band on OLED and retina. A 3% fractal-noise plate hides
   the stepping and gives every surface a physical rather than digital grain.
   Generated inline so it costs no request and inherits the page's dark base. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9998;
  pointer-events: none;
  opacity: 0.032;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
}

@media (min-resolution: 2dppx) {
  body::after {
    opacity: 0.022;
  }
}

/* ========================================================================== */
/* 6. Motion vocabulary                                                       */
/* ========================================================================== */

/* Durations and curves now come from tokens.css. What follows replaces the
   scattered per-file timings with the scale, and adds the exits that were
   missing entirely: overlays, menus and dialogs previously snapped out. */

.workspace-page .nav,
.sidebar-collapse,
#menu,
.suggestions button,
.workspace-page .ghost,
.workspace-page .filter,
.home-page .action,
.home-page .recent-row,
.workspace-page :is(.select-trigger, .tab, .theme, .toggle-row) {
  transition-duration: var(--dur-2);
  transition-timing-function: var(--ease-out);
}

.workspace-page .primary,
.home-page .ask form button:not(.select-trigger),
.workspace-page .send {
  transition:
    filter var(--dur-1) var(--ease-out),
    transform var(--dur-1) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out);
}

.home-page .action > .icon,
.home-page .action .arrow,
.workspace-page .select-trigger > .icon {
  transition-duration: var(--dur-3);
  transition-timing-function: var(--ease-spring);
}

/* Menus and popovers leave as well as arrive. */
.workspace-page #profile-menu,
.select-menu,
#command-palette {
  animation: vcz-pop-in var(--dur-2) var(--ease-out) both;
  transform-origin: var(--menu-origin, top center);
}

.workspace-page #profile-menu.is-leaving {
  animation: vcz-pop-out var(--dur-2) var(--ease-in) both;
  pointer-events: none;
}

/* Dialogs animate out as well as in, driven by the native open state instead of
   a script. The discrete `display` and `overlay` transitions keep the element
   painted until the exit finishes. Browsers without discrete transitions simply
   show and hide it, which is what happened before. */
dialog {
  opacity: 0;
  transform: translateY(14px) scale(0.975);
  transition:
    opacity var(--dur-3) var(--ease-out),
    transform var(--dur-3) var(--ease-out),
    display var(--dur-3) allow-discrete,
    overlay var(--dur-3) allow-discrete;
}

dialog[open] {
  opacity: 1;
  transform: none;
}

@starting-style {
  dialog[open] {
    opacity: 0;
    transform: translateY(14px) scale(0.975);
  }
}

dialog::backdrop {
  opacity: 0;
  transition:
    opacity var(--dur-3) var(--ease-out),
    display var(--dur-3) allow-discrete,
    overlay var(--dur-3) allow-discrete;
}

dialog[open]::backdrop {
  opacity: 1;
}

@starting-style {
  dialog[open]::backdrop {
    opacity: 0;
  }
}

.workspace-page .ai-processing-overlay:not([hidden]) {
  animation: vcz-fade-in var(--dur-4) var(--ease-out) both;
}

.workspace-page .ai-processing-overlay.is-closing {
  animation: vcz-fade-out var(--dur-3) var(--ease-in) both;
}

@keyframes vcz-pop-in {
  from {
    opacity: 0;
    transform: translateY(-6px) scale(0.975);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes vcz-pop-out {
  from {
    opacity: 1;
    transform: none;
  }
  to {
    opacity: 0;
    transform: translateY(-4px) scale(0.985);
  }
}
@keyframes vcz-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes vcz-fade-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

/* ========================================================================== */
/* 7. Ember rule motif                                                        */
/* ========================================================================== */

/* The short orange dash under the motto and the footer was the only place the
   brand rule appeared. It now anchors every section divider: an ember hairline
   that cools to nothing, used instead of a flat grey border. */
.workspace-page .panel-title {
  border-bottom: 0;
  padding-bottom: 14px;
  background-image: var(--rule-ember);
  background-size: 100% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
}

.workspace-page .panel:has(.panel-sub) .panel-title,
.workspace-page .settings-grid .panel-title {
  border-bottom: 0;
  background-image: none;
  padding-bottom: 0;
  margin-bottom: 8px;
}

.workspace-page .panel-sub {
  margin: 0 0 20px;
  padding-bottom: 14px;
  background-image: var(--rule-ember);
  background-size: 100% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  border-bottom: 0;
}

.workspace-page .context-card h2,
.workspace-page .session-toolbar {
  border-bottom: 0;
  padding-bottom: 12px;
  background-image: var(--rule-ember);
  background-size: 100% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
}

.workspace-page .workspace-heading {
  background-image: none !important;
  border-bottom: 0 !important;
}

.integrations-hero {
  background-image: none !important;
  min-height: auto;
  padding-bottom: 8px;
}

.sidebar-collapse:before {
  background: var(--rule-ember-soft);
}

.motto span,
.workspace-page footer > span,
footer > span:empty {
  background: var(--ember-dash);
  border-radius: var(--r-pill);
}

/* ========================================================================== */
/* 8. States: skeleton, empty, busy                                           */
/* ========================================================================== */

.skeleton-line {
  height: 9px;
  border-radius: var(--r-xs);
  background: linear-gradient(
    90deg,
    #14212b 0%,
    #1d2f3b 22%,
    #ff8a000f 50%,
    #1d2f3b 78%,
    #14212b 100%
  );
  background-size: 220% 100%;
  animation: skeleton-scan 1.7s var(--ease-in-out) infinite;
}

.recent-skeleton {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 17px 14px;
  border-top: 1px solid var(--line);
}

.recent-skeleton .skeleton-line:first-child {
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: 50%;
}

.recent-skeleton .skeleton-line:nth-child(2) {
  flex: 1;
}

.recent-skeleton .skeleton-line:last-child {
  width: 64px;
  flex: none;
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 7px;
  padding: 34px 20px;
  border-radius: var(--r-lg);
  border: 1px dashed #ffffff1f;
  background: linear-gradient(150deg, #0b121780, #070c1066);
  color: var(--ink-subtle, #9aa6b1);
}

.empty-state > .icon {
  width: 26px;
  height: 26px;
  color: var(--ember);
  opacity: 0.75;
  margin-bottom: 3px;
}

.empty-state strong {
  color: var(--text);
  font-size: 13px;
  font-weight: 550;
  letter-spacing: -0.1px;
}

.empty-state p {
  margin: 0;
  font-size: 12px;
  line-height: 1.6;
  max-width: 46ch;
}

.empty-state button {
  margin-top: 9px;
  font-size: 12px;
  padding: 8px 14px;
  border-radius: var(--r-pill);
  border: 1px solid var(--glass-edge-strong);
  background: var(--input-gradient);
  color: var(--text);
}

.empty-state button:hover {
  border-color: var(--ember);
}

/* Disabled controls always say why. A greyed-out button with no explanation is
   the most common unfinished-looking detail in a dark console. */
.workspace-page :is(button, .select-trigger)[disabled],
.workspace-page [aria-disabled="true"],
.workspace-page .select-option[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.45;
  filter: saturate(0.6);
}

.workspace-page :is(button, .select-trigger)[disabled]:hover,
.workspace-page [aria-disabled="true"]:hover {
  transform: none;
  border-color: var(--glass-edge);
}

/* Invalid fields carry the same ember language as everything else. */
.workspace-page :is(input, textarea, select)[aria-invalid="true"] {
  border-color: #ff4338aa;
  box-shadow:
    inset 0 1px 0 #00000059,
    0 0 0 3px #ff43381f;
}

.workspace-page .ask form:has(textarea[aria-invalid="true"]) {
  box-shadow:
    -8px 0 26px -10px #ff4338aa,
    8px 0 26px -10px #ff4338aa,
    0 12px 28px #0005;
}

/* ========================================================================== */
/* 9. Toasts                                                                  */
/* ========================================================================== */

.toast-stack {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 22px;
  z-index: 9990;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding-inline: 18px;
  pointer-events: none;
}

.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  width: max-content;
  max-width: min(460px, 100%);
  padding: 13px 15px;
  border-radius: var(--r-lg);
  border: 1px solid var(--glass-edge-strong);
  background: linear-gradient(148deg, #131e26f5, #070d11fa 74%);
  box-shadow: var(--glass-light), var(--glass-ring), var(--el-4);
  color: var(--text);
  font-size: 13px;
  line-height: 1.5;
  text-align: left;
  animation: vcz-toast-in var(--dur-4) var(--ease-spring) both;
}

.toast.is-leaving {
  animation: vcz-toast-out var(--dur-3) var(--ease-in) both;
}

.toast::before {
  content: "";
  flex: none;
  width: 3px;
  align-self: stretch;
  border-radius: var(--r-pill);
  background: var(--ember);
}

.toast[data-tone="warn"]::before {
  background: var(--warning);
}
.toast[data-tone="error"]::before {
  background: var(--danger);
}
.toast[data-tone="ok"]::before {
  background: var(--jade);
}

.toast-text {
  min-width: 0;
}

.toast-text b {
  display: block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.01em;
  margin-bottom: 2px;
}

.toast-text span {
  color: var(--muted);
  font-size: 12.5px;
  overflow-wrap: anywhere;
}

.toast-close {
  flex: none;
  width: 24px;
  height: 24px;
  margin: -4px -5px 0 2px;
  border: 0;
  border-radius: var(--r-xs);
  background: none;
  color: var(--ink-subtle, #9aa6b1);
  font-size: 15px;
  line-height: 1;
}

.toast-close:hover {
  color: var(--text);
  background: #ffffff0f;
}

@keyframes vcz-toast-in {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes vcz-toast-out {
  from {
    opacity: 1;
    transform: none;
  }
  to {
    opacity: 0;
    transform: translateY(8px) scale(0.98);
  }
}

/* The stack clears the collapsed rail on wide screens. */
@media (min-width: 701px) {
  :root:not(.sidebar-collapsed) .toast-stack {
    padding-left: 262px;
  }
  .sidebar-collapsed .toast-stack {
    padding-left: 80px;
  }
}

/* ========================================================================== */
/* 10. Home scene depth                                                       */
/* ========================================================================== */

/* No CSS transition on either offset. The values are rewritten every frame by a
   requestAnimationFrame loop that already eases toward the pointer, and a
   transition on top of that would low-pass the movement into invisibility.

   The offset uses `translate`, not `transform`. The hero already carries an
   `experience-enter` animation with `both` fill mode, so an animated `transform`
   would win the cascade and pin the element at translateY(0) forever. The
   independent `translate` property composes with `transform` instead of
   competing with it.

   The offsets are deliberately NOT declared as defaults here. A custom property
   declared on the element itself beats the inherited value, so defaulting them
   would shadow everything the script writes to the ancestor. Fallbacks belong in
   the var() call instead. */
.home-scene {
  background-image: none;
  background-color: #060c10;
  translate: var(--px, 0px) calc(var(--py, 0px) + var(--sy, 0px));
  transition: none;
}

.home-scene::before {
  content: "";
  position: absolute;
  inset: -3.5%;
  z-index: -3;
  background: url("../img/home-cinematic-background.jpg") 65% top / cover no-repeat;
  animation: scene-drift 52s var(--ease-in-out) infinite alternate;
  will-change: transform;
}

@media (min-width: 701px) {
  .home-scene::before {
    inset: -2.5%;
  }
}

/* The live scene covers this layer completely once it has faded in - the canvas
   is z-index -2 with alpha:false, this is -3 - so there is nothing left to see
   drifting. Dropping the promotion here also releases the compositor layer.
   Until scene-ready, and whenever WebGL is unavailable, it behaves as before. */
.home-scene.scene-ready::before {
  animation: none;
  will-change: auto;
}

@keyframes scene-drift {
  from {
    transform: scale(1.02) translate3d(0, 0, 0);
  }
  to {
    transform: scale(1.075) translate3d(-1.6%, 0.9%, 0);
  }
}

/* Title column lifts fractionally faster than the plate behind it. Every
   workspace page carries the same globe, so each page's own hero counter-moves
   against it. */
.home-page .hero,
.agents-hero,
.integrations-hero,
.history-hero,
.settings-hero,
.investigation-page .workspace-heading {
  translate: calc(var(--px, 0px) * -0.35) calc(var(--py, 0px) * -0.5);
  transition: none;
}

/* ========================================================================== */
/* Login page Earth & scene depth                                            */
/* ========================================================================== */

/* The Earth background elements (WebGL canvas, atmosphere, and cinematic plate)
   answer the pointer with smooth hardware-accelerated parallax.
   The 50px buffer ensures translation never exposes gaps or seams at any edge. */
.login-page .motion-canvas,
.login-page .atmosphere {
  translate: var(--px, 0px) var(--py, 0px);
  transition: none;
  will-change: translate;
}

.login-page .page::before {
  translate: var(--px, 0px) var(--py, 0px);
  transition: none;
  will-change: translate;
}

/* Foreground title and card counter-move slightly to produce rich 3D depth. */
.login-page .intro {
  translate: calc(var(--px, 0px) * -0.35) calc(var(--py, 0px) * -0.4);
  transition: none;
  will-change: translate;
}

.login-page .login-card {
  translate: calc(var(--px, 0px) * -0.2) calc(var(--py, 0px) * -0.25);
  transition: none;
  will-change: translate;
}

.login-page header {
  translate: calc(var(--px, 0px) * -0.15) calc(var(--py, 0px) * -0.2);
  transition: none;
  will-change: translate;
}

/* Breathing ember key light on the globe side of the hero. Disabled on the home
   page by its own stylesheet, so it is re-declared here at the same specificity
   and later in the cascade. */
.home-page .canvas:after {
  content: "";
  display: block;
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(120% 60% at 79% 24%, #ff6a0017, transparent 62%);
  animation: ember-breathe 14s var(--ease-in-out) infinite alternate;
}

@keyframes ember-breathe {
  from {
    opacity: 0.5;
  }
  to {
    opacity: 1;
  }
}

/* If WebGL is unavailable the plate is the only atmosphere left, so it carries
   a touch more colour. */
body.scene-fallback .home-scene::before {
  filter: saturate(1.08) contrast(1.02);
}

/* ========================================================================== */
/* 11. Single-choice tokens                                                   */
/* ========================================================================== */
/* Selection, focus and scrollbars had two competing definitions each. */
::selection {
  background: #ff6a0038;
  color: #fff;
}

:root {
  --focus-ring: var(--ember);
}

button:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

html {
  scrollbar-color: #46536a var(--canvas, #030609);
  scrollbar-width: thin;
}

/* Stable gutters stop lists shifting as records are added. */
.investigation-page #messages,
.investigation-page .context-rail,
.history-page main,
dialog,
.select-menu {
  scrollbar-gutter: stable;
}

/* ========================================================================== */
/* 12. Fallbacks and guards                                                   */
/* ========================================================================== */

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .toast {
    background: linear-gradient(148deg, #131e26, #070d11 74%);
  }
}

@media (prefers-reduced-transparency: reduce) {
  body::after {
    display: none;
  }
  .toast {
    background: #0c141a;
  }
}

/* Small screens restore the tighter page metrics. */
@media (max-width: 1100px) {
  :is(.workspace-page, .home-page):not(.investigation-page) .canvas > header {
    padding-inline: 24px;
  }
  :is(.workspace-page, .home-page):not(.investigation-page) main {
    padding-inline: 24px;
  }
}

@media (max-width: 700px) {
  :is(.workspace-page, .home-page):not(.investigation-page) .canvas > header {
    padding-inline: 16px;
  }
  :is(.workspace-page, .home-page):not(.investigation-page) main {
    padding-inline: 16px;
  }
  .home-scene,
  .home-page .hero,
  .login-page :is(.motion-canvas, .atmosphere, .intro, .login-card, header) {
    translate: none;
  }
  .login-page .page::before {
    translate: none !important;
  }
}

/* Motion off switch in Settings, and the OS-level preference, both stop the
   ambient layers this file introduces. */
body.motion-off .home-scene,
body.motion-off .home-page .hero,
body.motion-off .login-page :is(.motion-canvas, .atmosphere, .intro, .login-card, header) {
  translate: none;
  transition: none;
}
body.motion-off .login-page .page::before {
  translate: none !important;
  transition: none !important;
}

body.motion-off .home-scene::before,
body.motion-off .skeleton-line,
body.motion-off .toast,
body.motion-off .home-page .canvas:after {
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  body::after {
    opacity: 0.02;
  }
  .home-scene::before,
  .skeleton-line,
  .home-page .canvas:after {
    animation: none;
  }
  .home-scene,
  .home-page .hero,
  .login-page :is(.motion-canvas, .atmosphere, .intro, .login-card, header) {
    translate: none;
    transition: none;
  }
  .login-page .page::before {
    translate: none !important;
    transition: none !important;
  }
  .workspace-page #profile-menu,
  .select-menu,
  #command-palette,
  dialog[open],
  dialog[open]::backdrop,
  .toast {
    animation-duration: 1ms;
  }
  dialog.is-closing,
  dialog.is-closing::backdrop,
  .toast.is-leaving {
    animation-duration: 1ms;
  }
}

/* ======================================================================== */
/* Pointer spotlight + tilt, ported from the home page to every workspace   */
/* surface. workspace.js publishes --mouse-x/--mouse-y (and --rx/--ry/      */
/* --sx/--sy on tilting cards); everything below is the resting/hover look. */
/* Loaded after palette.css so these backgrounds win over the flat ones.    */
/* ======================================================================== */

/* Panels: a soft spotlight follows the cursor across the surface. */
.workspace-page :is(.panel, .context-card, .help-bar, .h-table, .agent-workspace-card) {
  background:
    radial-gradient(
      500px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
      rgba(255, 106, 0, 0.08),
      transparent 70%
    ),
    var(--panel-gradient);
  transition:
    border-color 0.25s ease,
    box-shadow 0.25s ease;
}
.workspace-page :is(.panel, .context-card, .help-bar, .h-table, .agent-workspace-card):hover {
  border-color: var(--edge-strong);
  box-shadow:
    inset 0 1px #e0edff0c,
    0 16px 42px #00000060;
}

/* Cards: the spotlight picks up the card's own accent, and the card tilts
   toward the cursor. --rx/--ry default to 0, so this is inert until the
   pointer moves and stays inert when motion is reduced. */
.workspace-page :is(.agent-card, .platform-card) {
  background:
    radial-gradient(
      320px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
      color-mix(in srgb, var(--accent) 16%, transparent),
      transparent 65%
    ),
    radial-gradient(
      ellipse at 5% 0%,
      color-mix(in srgb, var(--accent) var(--glow), transparent),
      transparent 65%
    ),
    var(--panel-gradient);
  transform-style: preserve-3d;
  transform: perspective(1000px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition:
    transform 0.18s cubic-bezier(0.2, 0, 0.2, 1),
    background 0.18s ease,
    border-color 0.25s ease,
    box-shadow 0.25s ease;
}
.workspace-page :is(.agent-card, .platform-card):hover {
  transform: perspective(1000px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(-4px);
  border-color: color-mix(in srgb, var(--accent) 70%, #263b45);
  box-shadow:
    var(--sx, 0px) var(--sy, 0px) 30px color-mix(in srgb, var(--accent) 18%, transparent),
    0 22px 55px #0007;
}

@media (prefers-reduced-motion: reduce) {
  .workspace-page :is(.agent-card, .platform-card),
  .workspace-page :is(.agent-card, .platform-card):hover {
    transform: none;
  }
}

/* ---- One-shot icon draw ---------------------------------------------------
   Draws a stroked sprite icon once (the approval tick). The dash is longer than
   the path, so with the animation removed - reduced motion, or the Settings
   "Reduce motion" switch - the icon simply shows, fully drawn. stroke-dash*
   inherit into the <use> shadow tree, so the sprite needs no changes. */
.icon-draw use {
  stroke-dasharray: 24;
  animation: icon-draw var(--dur-5) var(--ease-out) both;
}
@keyframes icon-draw {
  from {
    stroke-dashoffset: 24;
  }
}
@media (prefers-reduced-motion: reduce) {
  .icon-draw use {
    animation: none;
  }
}

/* ---- Edge fades -----------------------------------------------------------
   An internal scroll area fades at an edge only while there is more content
   past it. Driven by the element's own scroll position, so no JS and nothing
   moves on its own; a browser without scroll timelines shows no fade, and a
   box that doesn't overflow has an inactive timeline, so it shows none either.
   Only on a scroller with no border or background of its own: the mask fades
   those too (why the evidence dialog's framed well is not on the list). */
@property --fade-top {
  syntax: '<length>';
  inherits: false;
  initial-value: 0px;
}
@property --fade-bottom {
  syntax: '<length>';
  inherits: false;
  initial-value: 0px;
}
@supports (animation-timeline: scroll()) {
  .agent-workspace-card #messages,
  .business-services-list.is-long,
  .side-panel-body,
  #sidebar .chats-scroll {
    /* Focus and scroll-into-view land clear of the faded band: 28px of fade
       plus a 2px outline at a 4px offset. */
    scroll-padding-block: 34px;
    mask-image: linear-gradient(
      to bottom,
      transparent,
      black var(--fade-top),
      black calc(100% - var(--fade-bottom)),
      transparent
    );
    animation: edge-fade linear both;
    animation-timeline: scroll(self);
  }
}
@keyframes edge-fade {
  0% {
    --fade-top: 0px;
    --fade-bottom: 28px;
  }
  8%,
  92% {
    --fade-top: 28px;
    --fade-bottom: 28px;
  }
  100% {
    --fade-top: 28px;
    --fade-bottom: 0px;
  }
}
