/* The terminal cognitiva — composer, thread, turn bubbles, progress line.
 *
 * M16 C-R1 (2026-09-17) rewrote this sheet onto the M16 skin's vocabulary (`docs/09-portal.md`
 * §"the component vocabulary"). The rules the lane inherits with the file are unchanged and are the whole
 * contract:
 *
 *   - LAYOUT ON THE TOKEN ALIASES ONLY (`var(--line)`, `var(--text-secondary)`, `var(--run)`, …). A literal
 *     colour here fails `ThemeTests.Literal_colours_live_only_in_the_token_file_and_only_as_bb_steps`,
 *     which walks every `.css` under `src/Burbuja.Portal` and exempts exactly one file. A rule that needs a
 *     new colour adds a `--bb-*` step to `burbuja-tokens.css` (a registry file: additions only) and an
 *     alias; it never spells the colour here. `color-mix()` over an alias has no literal in it, which is
 *     why the state tints below are allowed.
 *   - NOTHING HERE NAMES A CLASS `portal.css` ALREADY OWNS. `.btn`, `.pill`, `.tag`, `.chip`, `.card`,
 *     `.alert`, `.reason` and the inputs are the shared vocabulary; this sheet only says what the
 *     terminal's own blocks are and how they sit. Re-deriving a pill or a button here is how a page and
 *     the skin come to disagree (X42: the old `.btn.active` rule painted a border a ghost button does not
 *     have).
 */

.terminal {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
}

/* ---------- the thread ---------- */
/* The scroll lives on the thread rather than on the page: a chat opens with its newest message in view and
   the composer must not be pushed off screen by a long history. */
.terminal-thread {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-height: 60vh;
    overflow-y: auto;
    padding: 2px;
    min-width: 0;
}

/* A bubble is a HAIRLINE and nothing else (M16 K-R1's card recipe): no shadow, one radius, the raised
   surface. The `.5px` `--line` edge is the whole separation; the old 1px border plus `--shadow-panel` was
   the M12 look. */
.bubble {
    border: .5px solid var(--line);
    border-radius: var(--radius);
    background: var(--bg-raised);
    box-shadow: none;
    padding: 10px 12px;
    max-width: 78ch;
    min-width: 0;
}

/* The human's message sits at the START of the line, AKOS's at the end — the one convention every chat
   window shares, and the only cue here that is not carried by a word. The left rule is the one place a
   bubble carries an identity hue: `--accent` for the person, `--accent-mark` for AKOS. */
.bubble-human {
    border-left: 3px solid var(--accent);
    align-self: flex-start;
    background: var(--bg-sunken);
}

.bubble-akos {
    border-left: 3px solid var(--accent-mark);
    align-self: flex-end;
}

.bubble-head {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}

/* The sender is an EYEBROW, and M16's eyebrow is 13px secondary text: no caps, no tracking. The old rule
   kept `text-transform: uppercase` while `--eyebrow-spacing` went to 0, which is the half-applied version
   of the tell the milestone exists to remove (X42). The record's own spelling is what prints — `owner`,
   never `OWNER`. */
.bubble-who {
    font: 500 var(--fs-secondary)/var(--lh-secondary) var(--sans);
    letter-spacing: 0;
    text-transform: none;
    color: var(--text-secondary);
}

.bubble-text {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    margin: 6px 0 0;
}

.bubble-foot {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    margin-top: 8px;
}

/* ---------- the progress line ---------- */
/* One line, always in the same place, whether it is the first act or the last: a status that moves around
   the page is a status nobody learns to look at. It is dsh's stream bar — a hairline over the page
   surface, not a sunken box. */
.terminal-progress {
    display: flex;
    gap: 8px;
    align-items: center;
    padding: 8px 12px;
    border: .5px solid var(--line-1);
    border-radius: var(--radius);
    background: transparent;
    color: var(--text);
}

/* The progress dot IS the run dot: StateDot's 8px mark with its 10 % halo, in `--run` — the same shape and
   tone `.pill-run::before` paints, because "a turn is running" is the state it names. The breathing
   animation is the second half of the sentence; a reader who asked their system for less motion gets a
   still dot, because the line's text is the information. */
.terminal-progress-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--run);
    position: relative;
    flex: none;
    animation: terminal-breathe 1.4s ease-in-out infinite;
}

.terminal-progress-dot::before {
    content: "";
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    background: var(--run);
    opacity: .1;
}

/* X47: the class a component renders and the skin had never heard of. The sentence is the line's body
   text, so it takes the body colour and nothing else. */
.terminal-progress-text {
    color: var(--text);
}

@keyframes terminal-breathe {
    0%, 100% { opacity: .3; }
    50% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .terminal-progress-dot { animation: none; opacity: .8; }
}

/* ---------- the composer ---------- */
.terminal-composer {
    border: .5px solid var(--line);
    border-radius: var(--radius);
    background: var(--bg-raised);
    box-shadow: none;
    padding: 12px;
}

/* M16 §3.3's input recipe: the layer-1 fill, a `.5px` `--line-4` hairline, radius 8, 14/22. It is a
   textarea, so it keeps its min-height and its vertical resize; the focus ring is `portal.css`'s rule for
   every `textarea`, which is why there is no second one here. */
.terminal-input {
    display: block;
    width: 100%;
    min-height: 4.5em;
    resize: vertical;
    padding: 6px 8px;
    border: .5px solid var(--line-4);
    border-radius: var(--radius-control);
    background: var(--input-bg);
    color: var(--text);
    font: 400 var(--fs-body)/var(--lh-body) var(--sans);
    margin: 4px 0 8px;
}

/* The reason a control is disabled. It is a real element and not only a `title`, because a title is a
   mouse-only affordance: a keyboard user, a screen reader and a screenshot need the sentence too. */
.reason {
    color: var(--warn);
    font-size: var(--fs-caption);
    line-height: var(--lh-caption);
    margin: 6px 0 0;
}

/* ---------- the command list ---------- */
.terminal-slash {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 6px 14px;
}

.terminal-slash li {
    display: flex;
    gap: 8px;
    align-items: baseline;
    min-width: 0;
}

.terminal-slash code {
    color: var(--accent);
    white-space: nowrap;
}

/* ---------- narrow screens ---------- */
/* A bubble that is 78ch wide on a phone is a bubble with a horizontal scrollbar, and lane M's contract
   fails a page that scrolls sideways at 390px. */
@media (max-width: 620px) {
    .bubble { max-width: 100%; }
    .terminal-thread { max-height: 52vh; }
}

/* ---------- M15 C-R3: the in-flight bubble, the `/` menu and the docked decision ---------- */

/* The message a send is carrying. Dimmmed and dashed so it reads as "not yet the record": the reload
   replaces it with the turn the kernel stored, and a bubble that looked identical would make a failed
   PUT look like a sent message. */
.bubble-pending {
    opacity: .6;
    border-style: dashed;
}

.bubble-pending .bubble-head .muted {
    font-style: italic;
}

/* The `/` menu follows dsh's `specific-menu` recipe — the menu-panel's LAYER-3 surface, a `.5px`
   `--line-3` edge, radius 12 and the lift shadow (the one place a shadow belongs) — with the item radius
   and hover `portal.css` uses. It sits above the textarea (the composer renders it before the control),
   so the list a keyboard user is choosing from stays visible while they type. */
.slash-menu {
    list-style: none;
    margin: 0 0 6px;
    padding: 6px;
    background: var(--bg-layer-3);
    border: .5px solid var(--line-3);
    border-radius: 12px;
    box-shadow: var(--shadow-lift);
    max-height: 40vh;
    overflow-y: auto;
}

.slash-menu li {
    display: flex;
    gap: 8px;
    align-items: baseline;
    padding: 7px 10px;
    border-radius: var(--radius-control);
    cursor: pointer;
}

.slash-menu li.active,
.slash-menu li:hover {
    background: var(--hover);
}

.slash-menu code {
    color: var(--accent);
    white-space: nowrap;
}

/* The decision docked under the composer: a warn TINT STRIP (the 3px `--warn` rule over the `--tag-wait`
   tint) so it reads as "this turn is blocked on you", not as another paragraph of the conversation. The
   inner card gives up its own hairline and fill so the strip is the only edge. */
.terminal-approval {
    margin-top: 10px;
    border-left: 3px solid var(--warn);
    border-radius: var(--radius);
    background: var(--tag-wait);
}

.terminal-approval .card {
    background: transparent;
    border: 0;
    border-radius: 0;
    margin: 0;
}

/* The two local command panels (`/estado`, `/contrato`) share one list shape. */
.terminal-panel {
    margin: 0;
    padding-left: 18px;
}

.terminal-panel li {
    margin: 2px 0;
}

/* ---------- M15 C-R3e: the composer is the first tab stop, the log is what scrolls ---------- */

/* DOM order is `.terminal-dock` (composer + decision) then `.terminal-log` (thread, progress, panels), so a
   keyboard user reaches the primary action before the history's depth links; these two rules put the log back
   on top visually. A chat whose input sank below N turns' worth of links failed G43's 12-Tab contract. */
.terminal-stack {
    display: flex;
    flex-direction: column;
}

.terminal-log {
    order: 1;
    min-width: 0;
}

.terminal-dock {
    order: 2;
}

/* ---------- M15 C-R4: /memoria ---------- */

/* One record per row, with the act id (`mem_…`) the forget/correct commands take. The id is monospace so a
   human can copy it; the lifecycle pill is the kernel's status through the console's ONE tone source. */
.terminal-memories {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.terminal-memories li {
    border-bottom: .5px solid var(--line-1);
    padding-bottom: 6px;
}

.terminal-memories li:last-child {
    border-bottom: 0;
    padding-bottom: 0;
}

/* ---------- M15 C-R4: the thread list ---------- */

/* The principal's conversations (K-R4), above the thread they switch. The active one is marked, and
   "Nueva conversación" is always last so the list can grow without moving the control. */
.terminal-threads {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: 8px;
}

.terminal-threads .row {
    flex-wrap: wrap;
}

/* X42: the old rule set `border-color` and `color` on a `.btn` that has NO border (M16's ghost default),
   so the selected thread was marked by blue text alone. The vocabulary's selected affordance is a filled
   row, so this paints `--active` — the same fill a pressed button uses. */
.terminal-threads .btn.active {
    background: var(--active);
    color: var(--text);
}
