/* =============================================================================
   RAYASA — پایانه هوش رایاسا
   A command line and the panels its answers render into. Built on tokens.css;
   the class prefix is `console-`/`tool-`/`result-`, none of which the rest of
   the site defines.
   ========================================================================== */

.console-page {
  /*
     No bottom padding: base.css already gives the last child of a `main.page`
     its section gap, and this page's last child is a visible `.shell`. Both
     applied put 309px between the final line and the footer.
  */
}

/* -----------------------------------------------------------------------------
   The console
   -------------------------------------------------------------------------- */

.console-shell {
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--surface-1);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}

.console-bar {
  display: flex;
  gap: var(--space-4);
  align-items: center;
  padding: var(--space-3) var(--space-4);
  border-block-end: 1px solid var(--line);
  background: var(--surface-2);
}

.console-lights {
  display: flex;
  gap: var(--space-2);
}

.console-light {
  inline-size: 0.7rem;
  block-size: 0.7rem;
  border-radius: var(--r-full);
  background: var(--line-strong);
}

.console-light--close { background: #f87171; }
.console-light--min { background: #fbbf24; }
.console-light--max { background: #34d399; }

.console-bar__title {
  font-size: var(--text-2xs);
  color: var(--text-dim);
  /* A Latin title inside an RTL bar reorders without this. */
  direction: ltr;
  unicode-bidi: isolate;
}

.console-input {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  padding: var(--space-4);
}

.console-prompt {
  flex: none;
  font-size: var(--text-sm);
  color: var(--ok-400);
}

/*
  The command line is left-to-right regardless of the page: every command here
  is Latin, and in an RTL field the caret starts on the wrong side and the
  argument detaches from the verb.
*/
.console-command {
  flex: 1;
  min-inline-size: 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-size: var(--text-sm);
  color: var(--text);
  transition: border-color var(--dur-fast) var(--ease-out);
}

.console-command::placeholder { color: var(--text-dim); }

.console-command:focus {
  outline: none;
  border-color: var(--brand-400);
}

.console-hint {
  margin: 0;
  padding: 0 var(--space-4) var(--space-4);
  font-size: var(--text-2xs);
  color: var(--text-dim);
}

.console-hint code {
  padding: 0.1em 0.4em;
  border-radius: var(--r-xs);
  background: var(--surface-2);
  color: var(--accent-300);
}

/* -----------------------------------------------------------------------------
   Tool grid
   -------------------------------------------------------------------------- */

/* -----------------------------------------------------------------------------
   The tool listing

   Two named groups rather than one undifferentiated grid, because where a tool
   runs is the most interesting thing about half of them. A visitor deciding
   whether to paste a live token into a text box should not have to read a
   footnote on a card to find out.
   -------------------------------------------------------------------------- */

.tool-groups {
  display: grid;
  gap: var(--space-10);
  margin-block-start: var(--space-8);
}

.tool-group__head {
  display: grid;
  gap: var(--space-2);
}

.tool-group__note {
  max-inline-size: 62ch;
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

.tool-grid {
  display: grid;
  gap: var(--space-3);
  margin-block-start: var(--space-6);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

/*
  A fixed column count rather than `auto-fit`, which sizes its tracks from the
  number of items: five cards and three cards in the same viewport came out
  283px and 381px wide, so the two groups read as two different components.
  Counting the columns instead makes the five wrap 3 + 2 under a group of 3
  that fills its row exactly.
*/
.tool-group .tool-grid {
  margin-block-start: var(--space-5);
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) {
  .tool-group .tool-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 62rem) {
  .tool-group .tool-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* -----------------------------------------------------------------------------
   The syntax examples

   Real commands, in the order someone meets them. The point is not that the
   grammar is hard — it is that seeing four of them removes any doubt that it
   is the same grammar every time.
   -------------------------------------------------------------------------- */

.syntax {
  display: grid;
  gap: var(--space-2);
  margin-block-start: var(--space-6);
}

.syntax__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-5);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-1);
}

.syntax__cmd {
  color: var(--accent-300);
  font-size: var(--text-sm);
}

.syntax__note {
  color: var(--text-muted);
  font-size: var(--text-xs);
}

.tool-card {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-5);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface-1);
  font: inherit;
  text-align: start;
  cursor: pointer;
  transition:
    border-color var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-out);
}

.tool-card:hover {
  border-color: var(--line-brand);
  transform: translateY(-2px);
}

.tool-card:focus-visible {
  outline: 2px solid var(--brand-400);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .tool-card:hover { transform: none; }
}

.tool-card__name {
  font-size: var(--text-2xs);
  color: var(--accent-300);
  direction: ltr;
  unicode-bidi: isolate;
}

.tool-card__title {
  font-size: var(--text-base);
  font-weight: 700;
  color: var(--text);
}

.tool-card__blurb {
  font-size: var(--text-2xs);
  line-height: var(--leading-normal);
  color: var(--text-muted);
}

/* -----------------------------------------------------------------------------
   Output

   Newest first, so the answer to the command just typed is at the top and the
   page does not have to be scrolled to find it.
   -------------------------------------------------------------------------- */

.console-out {
  display: grid;
  gap: var(--space-4);
  margin-block-start: var(--space-8);
}

.result {
  padding: var(--space-6);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface-1);
}

.result--error { border-color: rgb(248 113 113 / 30%); }
.result--pending { border-style: dashed; }

.result__command {
  margin: 0 0 var(--space-2);
  font-size: var(--text-2xs);
  color: var(--text-dim);
}

.result__title {
  margin: 0 0 var(--space-5);
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--text);
}

.result__error {
  margin: 0;
  font-size: var(--text-sm);
  color: #fecaca;
}

.result__section {
  margin: var(--space-6) 0 var(--space-3);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide);
  color: var(--text-dim);
}

.result__section:first-of-type { margin-block-start: 0; }

/* --- Findings ------------------------------------------------------------ */

.findings {
  display: grid;
  gap: var(--space-2) var(--space-5);
  margin: 0;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  font-size: var(--text-sm);
}

.findings__label {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  color: var(--text-muted);
}

/*
  Colour is never the only signal: each verdict carries a glyph, so a grade
  survives a monochrome print and a colour-blind reader alike.
*/
.findings__glyph {
  flex: none;
  inline-size: 1.1rem;
  text-align: center;
}

.findings__glyph--good { color: var(--ok-400); }
.findings__glyph--warn { color: var(--warn-400); }
.findings__glyph--bad { color: var(--danger-400); }
.findings__glyph--info { color: var(--text-dim); }

.findings__value {
  display: grid;
  gap: var(--space-1);
  margin: 0;
  min-inline-size: 0;
}

.findings__text {
  color: var(--text);
  overflow-wrap: anywhere;
}

.findings__note {
  font-size: var(--text-2xs);
  color: var(--text-dim);
}

/* --- Tables -------------------------------------------------------------- */

.result__scroll {
  overflow-x: auto;
  margin-block-start: var(--space-3);
}

.result__table {
  inline-size: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.result__table td {
  padding: var(--space-2) var(--space-3);
  border-block-end: 1px solid var(--line);
  color: var(--text-soft);
  vertical-align: top;
}

.result__table tr:last-child td { border-block-end: 0; }

/*
  The payload column carries someone else's data — a hostname, a header value,
  a JSON blob. Pre-wrapped so a formatted body keeps its shape, and left-to-right
  so nothing in it is reordered by the surrounding Persian.
*/
.result__payload {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--text);
}

.result__where {
  white-space: nowrap;
  font-size: var(--text-2xs);
  color: var(--text-dim);
}

/* -----------------------------------------------------------------------------
   Execution feedback

   Three states a visitor can tell apart at a glance: queued (still, dashed),
   running (a scan bar moving and a counter climbing), done (solid, with the
   time it took). Before this, a queued command and a running one looked
   identical — and both looked like nothing had happened.
   -------------------------------------------------------------------------- */

.result__status {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  margin: 0;
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.result__timer {
  font-size: var(--text-2xs);
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.result__took {
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

.result__spinner {
  flex: none;
  inline-size: 0.85rem;
  block-size: 0.85rem;
  border: 2px solid var(--line-strong);
  border-block-start-color: var(--brand-400);
  border-radius: var(--r-full);
}

.result--running .result__spinner {
  animation: console-spin 700ms linear infinite;
}

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

/*
  The scan bar exists only while something is actually in flight, so its
  presence is information rather than decoration. A queued card shows the track
  and nothing travelling along it.
*/
.result__scan {
  display: block;
  block-size: 2px;
  margin-block-start: var(--space-4);
  border-radius: var(--r-full);
  background: var(--line);
  overflow: hidden;
  position: relative;
}

.result--running .result__scan::after {
  content: '';
  position: absolute;
  inset-block: 0;
  inline-size: 40%;
  border-radius: inherit;
  background: linear-gradient(to left, transparent, var(--brand-400), transparent);
  animation: console-scan 1.1s var(--ease-in-out) infinite;
}

@keyframes console-scan {
  from { transform: translateX(120%); }
  to { transform: translateX(-160%); }
}

.result--pending { border-style: dashed; }

.result--running {
  border-style: solid;
  border-color: var(--line-brand);
}

.console-input.is-busy .console-prompt { color: var(--warn-400); }

@media (prefers-reduced-motion: reduce) {
  .result--running .result__spinner,
  .result--running .result__scan::after {
    animation: none;
  }

  /* Movement was the signal, so give it back as a visible fill. */
  .result--running .result__scan::after {
    content: '';
    position: absolute;
    inset: 0;
    inline-size: 100%;
    background: var(--brand-600);
  }
}

.tool-card__where {
  font-size: 0.625rem;
  letter-spacing: var(--tracking-wide);
  color: var(--text-dim);
}

/* -----------------------------------------------------------------------------
   The assistant panel

   Shares the result renderer with the terminal, so an answer read here looks
   like the same answer read there.
   -------------------------------------------------------------------------- */

.agent-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-block: var(--space-4);
}

.agent-chip {
  padding: var(--space-1) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  background: transparent;
  font: inherit;
  font-size: var(--text-2xs);
  color: var(--text-muted);
  cursor: pointer;
  transition:
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.agent-chip:hover {
  border-color: var(--line-brand);
  color: var(--text);
}

.agent-thread {
  display: grid;
  gap: var(--space-3);
  max-block-size: 22rem;
  overflow-y: auto;
  margin-block-end: var(--space-4);
}

.agent-thread:empty { display: none; }

.agent-msg {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--r-md);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

.agent-msg--you {
  justify-self: start;
  border: 1px solid var(--line-brand);
  background: rgb(30 133 230 / 10%);
  color: var(--text);
}

.agent-msg--bot {
  justify-self: end;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text-soft);
}

.agent-msg__spinner {
  display: inline-block;
  inline-size: 0.7rem;
  block-size: 0.7rem;
  margin-inline-start: var(--space-2);
  border: 2px solid var(--line-strong);
  border-block-start-color: var(--brand-400);
  border-radius: var(--r-full);
  animation: console-spin 700ms linear infinite;
  vertical-align: -1px;
}

@media (prefers-reduced-motion: reduce) {
  .agent-msg__spinner { animation: none; }
}

.agent-msg__link {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--brand-300);
  text-decoration: underline;
  text-underline-offset: 0.25em;
  cursor: pointer;
}

.agent-form {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

.agent-form .input { flex: 1; min-inline-size: 0; }

.agent-note {
  margin: var(--space-3) 0 0;
  font-size: var(--text-2xs);
  color: var(--text-dim);
}

.agent-divider {
  margin-block: var(--space-6);
  border: 0;
  border-block-start: 1px solid var(--line);
}

/* A result inside the panel is tighter than one on the terminal page. */
.result--compact {
  padding: var(--space-4);
  font-size: var(--text-sm);
}

.result--compact .result__title { font-size: var(--text-base); margin-block-end: var(--space-3); }
.result--compact .result__scroll { max-block-size: 14rem; overflow-y: auto; }

/* -----------------------------------------------------------------------------
   Maximising

   The page opens as a page and becomes a workspace on first use. The stage
   holds the command line and its output together, because those are the two
   things that have to fill the screen; the tool grid stays behind on the page.
   -------------------------------------------------------------------------- */

.console-stage {
  display: grid;
  gap: var(--space-8);
}

/*
  Reparented to <body> while maximised — see console-window.js for why a
  z-index alone cannot work here — so this rule has to stand on its own rather
  than inheriting anything from the page.
*/
.console-stage--maximized {
  position: fixed;
  inset: var(--space-4);
  z-index: 130;
  gap: var(--space-4);
  grid-template-rows: auto 1fr;
  min-block-size: 0;
}

@media (min-width: 48rem) {
  .console-stage--maximized { inset: var(--space-8); }
}

/* The output takes whatever is left, and scrolls inside itself. */
.console-stage--maximized .console-out {
  margin-block-start: 0;
  min-block-size: 0;
  overflow-y: auto;
  padding-inline-end: var(--space-2);
}

.console-stage--maximized .console-shell {
  box-shadow: var(--shadow-lg), var(--glow-brand);
}

/* Dim the page behind. On <html>, so there is one class to toggle and nothing
   injected to clean up — the same approach the hero's terminal uses. */
.is-console-maximized::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 125;
  background: rgb(2 4 8 / 82%);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

/* --- The controls -------------------------------------------------------- */

.console-lights {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

/* The green light is a button; a light that looks like one and is not is
   decoration with extra steps. */
button.console-light {
  padding: 0;
  border: 0;
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease-out);
}

button.console-light:hover { transform: scale(1.18); }

button.console-light:focus-visible {
  outline: 2px solid var(--brand-400);
  outline-offset: 2px;
}

.console-expand {
  margin-inline-start: auto;
  padding: var(--space-1) var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--r-full);
  background: transparent;
  font: inherit;
  font-size: var(--text-2xs);
  color: var(--text-muted);
  cursor: pointer;
  transition:
    color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.console-expand:hover {
  border-color: var(--line-brand);
  color: var(--text);
}

@media (prefers-reduced-motion: reduce) {
  button.console-light:hover { transform: none; }
}

/* -----------------------------------------------------------------------------
   The assistant panel, grown

   The dialog opens at the size of a menu, which is what it is until somebody
   asks it something. A DNS answer set is a table, and a table in a 42rem column
   under an 85svh ceiling is a table read through a letterbox.

   Growing it is a chain, not one rule, because the height has to travel: the
   panel takes a definite height, the body claims what is left of it, and the
   thread claims what is left of the body and scrolls inside that. Hand the
   height straight to the thread and it simply grows past the panel — a flex
   item's minimum size is its content until it is told otherwise, which is what
   `min-block-size: 0` is doing at each link.
   -------------------------------------------------------------------------- */

.dialog__panel--wide {
  inline-size: min(72rem, 100%);
  block-size: min(94svh, 60rem);
  max-block-size: min(94svh, 60rem);
  display: flex;
  flex-direction: column;

  /* The body scrolls now, so the panel must not — two nested scrollers put the
     visitor's wheel on whichever one the pointer happens to be over. */
  overflow: hidden;
}

.dialog__panel--wide .dialog__body {
  flex: 1;
  min-block-size: 0;
  overflow-y: auto;
}

/*
  The two wrappers exist only for the grown panel. Everywhere else they are
  `display: contents`, so the markup lays out exactly as it did before they were
  added — including on a phone, where the panel grows in height alone.
*/
.agent-main,
.agent-aside { display: contents; }

/* -----------------------------------------------------------------------------
   Two columns — only where there is width to spend

   A 70rem-wide column of chat is a worse line length than the 42rem one it
   replaced, so the width goes to a second column: the conversation on one side,
   the project shortcuts on the other, both visible at once instead of one
   pushing the other off the bottom.

   Below this width there is no second column to give, and the same rules would
   cut a 375px phone into two 160px slivers. That is the whole reason for the
   floor.
   -------------------------------------------------------------------------- */

@media (min-width: 60rem) {
  .dialog__panel--wide .dialog__body {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
    gap: var(--space-6);
    overflow: hidden;
  }

  .dialog__panel--wide .agent-main,
  .dialog__panel--wide .agent-aside {
    display: flex;
    flex-direction: column;
    min-block-size: 0;
  }

  /* The aside is the shorter column and scrolls on its own if the viewport is
     short; it must not drag the conversation's height around. */
  .dialog__panel--wide .agent-aside {
    overflow-y: auto;

    /* The rule goes on the aside's inline-START edge: this is an RTL document,
       so the second column sits to the left and the edge facing the
       conversation is its start. Logical properties only help if the right one
       is chosen. */
    border-inline-start: 1px solid var(--line);
    padding-inline-start: var(--space-6);
  }

  /* The rule between them is now the column edge. */
  .dialog__panel--wide .agent-divider { display: none; }

  /* The conversation takes every pixel its column has left, so the command line
     stays pinned beneath it rather than drifting down the page. */
  .dialog__panel--wide .agent-thread {
    flex: 1;
    min-block-size: 8rem;
    max-block-size: none;
  }

  /*
    An empty conversation still holds its space here, overriding the
    `:empty { display: none }` that suits the small panel. Without this the
    panel opens at full height with its composer floating in the middle and a
    void beneath — the shape every chat panel has before the first message is
    the composer at the bottom, and that is only true if the empty thread is
    still the thing filling the column.
  */
  .dialog__panel--wide .agent-thread:empty {
    display: grid;
  }

  /* A wider panel can afford a taller table; the compact cap is for the small
     one. The thread scrolls too, so this only decides which of the two moves. */
  .dialog__panel--wide .result--compact .result__scroll {
    max-block-size: 26rem;
  }
}

/* Between the phone and the two-column floor: one column, more height. */
@media (max-width: 59.99rem) {
  .dialog__panel--wide .agent-thread { max-block-size: 34rem; }
}

/* -----------------------------------------------------------------------------
   The control
   -------------------------------------------------------------------------- */

/*
  Beside the close button, sharing its row. Both offsets derive from `--space-5`
  because that is what `.dialog__close` uses — `--space-6` here put the two
  controls on rows four pixels apart, which reads as sloppy without anyone being
  able to say why.
*/
.dialog__expand {
  position: absolute;
  inset-block-start: var(--space-5);
  inset-inline-end: calc(var(--space-5) + 2.75rem + var(--space-2));
  z-index: 2;
}

.dialog__expand svg {
  inline-size: 1.05rem;
  block-size: 1.05rem;
}

/* Pressed reads as "this is on", matching the terminal's own control. */
.dialog__expand[aria-pressed='true'] {
  border-color: var(--line-brand);
  color: var(--brand);
}

@media (max-width: 47.99rem) {
  /* On a phone the panel is already the width of the screen, so growing it buys
     height and nothing else — and it buys that by itself. The control would
     only crowd the header with a choice that has one useful answer. */
  .dialog__expand { display: none; }

  .dialog__panel--wide {
    inline-size: 100%;
    block-size: min(94svh, 60rem);
  }
}
