/* The dashboard's own layout; tokens come from app/theme.css, the shared
   look from engy/engy.css. */

/* minmax(0, 1fr), not a bare 1fr: 1fr is minmax(auto, 1fr), whose minimum is
   the column's content — a wide table would grow the column, and the page with
   it, instead of scrolling inside .viz-grid. */
.viz-files {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-lg);
    align-items: start;
}

/* The layers column is off until the sidebar's More button turns it on, so the
   grid is the detail column alone and the column itself is not laid out at
   all — one class on <body> switches both, and the detail column stays
   minmax(0, 1fr) in either state. */
body.engy-layers-visible .viz-files {
    grid-template-columns: 260px minmax(0, 1fr);
}

.viz-side {
    display: none;
    border-right: 1px solid var(--color-line);
    padding-right: var(--space-lg);
    max-height: calc(100vh - 6rem);
    overflow-y: auto;
}

body.engy-layers-visible .viz-side {
    display: block;
}

.viz-side summary {
    cursor: pointer;
    color: var(--color-accent);
    padding: var(--space-xs) 0;
}

.viz-side ul {
    list-style: none;
    margin: var(--space-xs) 0 var(--space-md);
    padding-left: var(--space-lg);
}

.viz-side a {
    color: var(--color-fg);
    text-decoration: none;
}

.viz-side a.active {
    color: var(--color-accent);
    font-weight: 600;
}

.viz-detail {
    min-width: 0;
}

/* A wide table scrolls inside its own grid, so the page body never does and the
   layer nav above it can stay sticky to the window. */
.viz-grid {
    overflow-x: auto;
}

/* The layer jump nav: the table's name and one chip per contributing layer,
   sticky at the top of the detail so it stays reachable down a long table. */
.viz-layernav {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-sm);
    padding: var(--space-sm) 0;
    margin-bottom: var(--space-sm);
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-line);
}

/* Doubled class beats .viz-layernav button's element+class specificity —
   the type name is a button now (it opens the type's object view), but
   must keep the bold accent link look, not the preset pill style below. */
.viz-layernav .viz-layernav-table {
    font-weight: 600;
    color: var(--color-accent);
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
    text-decoration: underline dotted;
}

/* The glyph beside a row's key that opens it in a dialog. */
.viz-peek {
    background: none;
    color: var(--color-fg);
    padding: 0 var(--space-xs);
    opacity: 0.35;
    font-size: var(--text-md);
}

.viz-peek:hover {
    opacity: 1;
    color: var(--color-accent);
}

.viz-layernav-count {
    opacity: 0.55;
    margin-right: var(--space-md);
    font-size: var(--text-sm);
}

.viz-layernav button {
    background: none;
    color: var(--color-fg);
    border: 1px solid var(--color-line);
    border-radius: 999px;
    padding: var(--space-xs) var(--space-md);
    cursor: pointer;
    font: inherit;
    font-size: var(--text-sm);
}

.viz-layernav button:hover {
    border-color: var(--color-accent);
    color: var(--color-accent);
}

.viz-layernav button.active {
    background: var(--color-accent);
    color: var(--color-on-accent);
    border-color: var(--color-accent);
}

/* A sidebar entry for another layer's fragment of the table now open. */
.viz-side a.sibling {
    color: var(--color-accent);
    opacity: 0.7;
}

/* A page's title-and-action header row — the gate page lays its title and Run
   again out with this. */
.viz-grid-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--space-lg);
    gap: var(--space-lg);
}

/* A cell that opens another row: users-table.js, report.js and recent.js
   each render it as a <button>, never an <a href> — the Data page keeps its
   own state in location.hash, so these reset a button back to link styling. */
.viz-fk {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: var(--color-accent);
    text-decoration: underline dotted;
    cursor: pointer;
}

tr.viz-hl td {
    background: color-mix(in srgb, var(--color-accent) 18%, transparent);
}

/* The layer dependency graph (view/desktop/list/core.layer/graph.js). The
   canvas fills the viewport below the header; the SVG paints itself, so
   these are only colours and weights. */

.viz-deps-hint {
    flex: 1;
    color: var(--color-fg);
    opacity: 0.6;
    font-size: var(--text-sm);
    padding: 0 var(--space-lg);
}

.viz-deps-canvas {
    height: calc(100vh - 8rem);
    border: 1px solid var(--color-line);
    border-radius: 6px;
    background:
        radial-gradient(circle at 1px 1px, var(--color-line) 1px, transparent 0) 0 0 / 24px 24px,
        var(--color-panel);
    overflow: hidden;
}

.viz-deps-svg {
    width: 100%;
    height: 100%;
    cursor: grab;
}

.viz-deps-svg:active {
    cursor: grabbing;
}

.viz-deps-link {
    fill: none;
    stroke: color-mix(in srgb, var(--color-fg) 55%, transparent);
    stroke-width: 1.4px;
    transition: stroke 0.15s;
}

.viz-deps-link.lit {
    stroke: var(--color-accent);
    stroke-width: 2px;
}

.viz-deps-link.faded {
    stroke: color-mix(in srgb, var(--color-fg) 10%, transparent);
}

/* The two arrowheads graph.js swaps between. Opaque fills (mixed toward the
   panel, not transparent) so a marker never renders as the fallback black the
   way context-stroke does in Safari. */
.viz-deps-arrow {
    fill: color-mix(in srgb, var(--color-fg) 55%, var(--color-panel));
}

.viz-deps-arrow-lit {
    fill: var(--color-accent);
}

.viz-deps-node {
    cursor: pointer;
    transition: opacity 0.15s;
}

.viz-deps-node circle {
    fill: var(--color-accent);
    stroke: var(--color-bg);
    stroke-width: 1.5px;
    transition: fill 0.15s;
}

.viz-deps-node.focus circle {
    fill: var(--color-ok, #3fb950);
}

.viz-deps-node.faded {
    opacity: 0.15;
}

.viz-deps-label {
    fill: var(--color-fg);
    font-size: 12px;
    pointer-events: none;
    paint-order: stroke;
    stroke: var(--color-bg);
    stroke-width: 3px;
    transition: opacity 0.15s;
}

/* Drawn in its own group above the circles, a label fades on its own when
   its node does. */
.viz-deps-label.faded {
    opacity: 0.15;
}

/* The layer dependency tree (view/desktop/list/core.layer/tree.js): one row
   per level, a fixed layout with no simulation — plain SVG, scaled by its
   viewBox. */

.viz-tree-hint {
    flex: 1;
    color: var(--color-fg);
    opacity: 0.6;
    font-size: var(--text-sm);
    padding: 0 var(--space-lg);
}

.viz-tree-canvas {
    height: calc(100vh - 8rem);
    border: 1px solid var(--color-line);
    border-radius: 6px;
    background: var(--color-panel);
    overflow: auto;
}

.viz-tree-svg {
    width: 100%;
    display: block;
}

.viz-tree-link {
    fill: none;
    stroke: color-mix(in srgb, var(--color-fg) 40%, transparent);
    stroke-width: 1.4px;
}

.viz-tree-node rect {
    fill: var(--color-panel);
    stroke: var(--color-accent);
    stroke-width: 1.5px;
}

.viz-tree-node text {
    fill: var(--color-fg);
    font-size: 12px;
}

/* A Data page tree entry is two lines: the name, and the badges under it.
   Side by side they were each squeezing the other — the badges are a fixed
   width, so every character they took came off the name, and the names in
   one layer differ in their last few characters. Stacked, the name gets the
   whole column. */
.viz-data-entry {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    min-width: 0;
    margin-bottom: var(--space-xs);
}

.viz-data-entry a {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.viz-data-sources {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    max-width: 100%;
}

/* The Data page's per-type source badge: sot, or db · <store>, greyed and
   dashed when this build has no active integration for that store. */
.viz-data-source {
    flex: none;
    white-space: nowrap;
    font-size: var(--text-xs);
    opacity: 0.6;
    border: 1px dotted var(--color-line);
    border-radius: 3px;
    padding: 0 var(--space-xs);
}

.viz-data-source.unreachable {
    opacity: 0.35;
    border-style: dashed;
}

/* A data cell long enough to carry a view button: the text truncates with an
   ellipsis, and the button sits over its top-right corner, hidden until the
   row is hovered so it never crowds a short value in a neighboring column. */
.viz-data-cell {
    position: relative;
    max-width: 24rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.viz-text-peek {
    display: none;
    position: absolute;
    top: 0;
    right: 0;
    background: var(--color-bg);
    color: var(--color-fg);
    padding: 0 var(--space-xs);
    opacity: 0.55;
    font-size: var(--text-md);
}

tr:hover .viz-text-peek {
    display: inline;
}

.viz-text-peek:hover {
    opacity: 1;
    color: var(--color-accent);
}

.viz-data-paging {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin-top: var(--space-md);
    font-size: var(--text-sm);
    opacity: 0.85;
}

.viz-data-paging select {
    margin-left: auto;
    background: none;
    color: var(--color-fg);
    border: 1px solid var(--color-line);
    border-radius: 999px;
    padding: var(--space-xs) var(--space-sm);
    cursor: pointer;
    font: inherit;
    font-size: var(--text-md);
}

/* The Data page's view host, shared by a type's list views and a layer's
   data views: a bar above it — a picker when there is more than one view of
   that kind, an add-task icon at the right edge for a list view only — then
   whichever view the page has mounted. */
.viz-view-host {
    min-width: 0;
}

.viz-view-bar {
    display: flex;
    align-items: center;
    margin-bottom: var(--space-md);
}

.viz-view-picker {
    display: flex;
    gap: var(--space-xs);
    margin-left: auto;
    align-self: center;
}

.viz-layernav .viz-view-picker button {
    background: none;
    border: 1px solid var(--color-line);
    color: var(--color-fg);
    border-radius: 999px;
    padding: 0 var(--space-sm);
    line-height: 1.6;
    cursor: pointer;
    font: inherit;
    font-size: var(--text-xs);
}

/* The mounted view: outlined in the accent, not filled like the nav's own
   pills — a picker reads quieter than the thing it sits beside. */
.viz-layernav .viz-view-picker button.active {
    background: none;
    border-color: var(--color-accent);
    color: var(--color-accent);
}

/* An icon-only "add task" button, right-aligned in its bar whether or not a
   view picker sits beside it — the host page's own control, shared by every
   type since it lives beside the picker rather than inside any one view. */
.viz-add-task {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-left: auto;
    padding: 0;
    flex: none;
    box-sizing: border-box;
    background: none;
    border: 1px solid var(--color-line);
    color: var(--color-fg);
    border-radius: 999px;
    width: 1.8em;
    height: 1.8em;
    cursor: pointer;
    font: inherit;
}

.viz-add-task .engy-icon-mask {
    width: 60%;
    height: 60%;
}

.viz-add-task:hover {
    border-color: var(--color-accent);
    color: var(--color-accent);
}

/* A layer's README, rendered — the Data page's detail pane in place of a
   type's rows. */
.viz-readme {
    line-height: 1.55;
    max-width: 60rem;
}

.viz-readme h1, .viz-readme h2, .viz-readme h3 {
    color: var(--color-accent);
}

.viz-readme a {
    color: var(--color-accent);
}

.viz-readme pre {
    background: var(--color-panel);
    border: 1px solid var(--color-line);
    border-radius: 6px;
    padding: var(--space-lg);
    overflow-x: auto;
}

.viz-readme code {
    background: var(--color-panel);
    border-radius: 3px;
    padding: var(--space-xs) var(--space-xs);
}

/* The Recent actions view's toolbar: the presets as the same pill picker
   the Data page uses for views, Refresh at its right. */
.actions-toolbar {
    display: flex;
    align-items: center;
    gap: var(--space-lg);
    margin-left: auto;
}

.actions-when {
    white-space: nowrap;
}

/* core.type's Thumbnail view: one fold per layer, a card grid inside; a
   card's own folds are the field list and the referrers. */
.type-thumb-layer {
    border: 1px solid var(--color-line);
    border-radius: 6px;
    margin-bottom: var(--space-md);
}

.type-thumb-layer > summary {
    cursor: pointer;
    padding: var(--space-sm) var(--space-lg);
    display: flex;
    gap: var(--space-lg);
    align-items: baseline;
}

.type-thumb-layer-name {
    font-weight: 600;
}

.type-thumb-layer-description {
    font-size: var(--text-md);
}

.type-thumb-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
    gap: var(--space-lg);
    padding: var(--space-lg);
}

.type-thumb {
    border: 1px solid var(--color-line);
    border-radius: 6px;
    padding: var(--space-md) var(--space-lg);
    background: var(--color-panel);
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.type-thumb-head {
    display: flex;
    align-items: baseline;
    gap: var(--space-md);
}

.type-thumb-name {
    font-weight: 600;
}

.type-thumb-data {
    margin-left: auto;
    font-size: var(--text-sm);
    color: var(--color-accent);
}

.type-thumb-description {
    margin: 0;
    font-size: var(--text-md);
}

.type-thumb-fold > summary,
.type-thumb-none {
    cursor: pointer;
    font-size: var(--text-md);
}

.type-thumb-none {
    cursor: default;
}

.type-thumb-fold table {
    margin-top: var(--space-sm);
    font-size: var(--text-sm);
}

/* pipeline.transition's Graph: the Mermaid stateDiagram drawn from the rows,
   scrolling sideways when a pipeline is wider than the pane, and the source it
   was drawn from folded underneath. */

.viz-mermaid {
    overflow-x: auto;
    padding: var(--space-lg);
    border: 1px solid var(--color-line);
    border-radius: 6px;
    background: var(--color-panel);
    color: var(--color-fg);
}

.viz-mermaid svg {
    display: block;
    margin: 0 auto;
}

.viz-mermaid-source {
    margin-top: var(--space-md);
}

.viz-mermaid-source pre {
    overflow-x: auto;
    padding: var(--space-md);
    border: 1px solid var(--color-line);
    border-radius: 6px;
    background: var(--color-bg);
    font-size: 12px;
}

/* workspace.status's chip (its cell view draws it). The sheet lives here
   rather than in the workspace layer because the app links only its own
   layer's static/, and the chip is a cell of the Data page either way: ready
   is clean, busy is moving, error is what a person came to find, and a
   workspace that is finished or removed is history. */
.workspace-status {
    display: inline-block;
    padding: 0 var(--space-sm);
    border-radius: 999px;
    font-size: var(--text-xs);
    border: 1px solid var(--color-line);
    color: var(--color-fg);
    white-space: nowrap;
}

.workspace-status-ready {
    border-color: var(--color-ok);
    color: var(--color-ok);
}

.workspace-status-busy {
    border-color: var(--color-accent);
    color: var(--color-accent);
}

.workspace-status-error {
    border-color: var(--color-error);
    color: var(--color-error);
}

.workspace-status-finished,
.workspace-status-removed {
    border-color: var(--color-muted);
    color: var(--color-muted);
}

/* deployment.project's Status list view: a panel per project, its head
   carrying what the whole of it adds up to and a pill per service status. */
.deploy-status-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);
}

.deploy-status {
    border: 1px solid var(--color-line);
    border-radius: 6px;
    background: var(--color-panel);
    padding: var(--space-md) var(--space-lg);
}

.deploy-status-head {
    margin: 0 0 var(--space-md);
    display: flex;
    align-items: baseline;
    gap: var(--space-md);
}

.deploy-status-name {
    font-weight: 600;
}

.deploy-status-summary {
    margin-left: auto;
    font-size: var(--text-sm);
    font-weight: normal;
}

.deploy-status-tone-ok {
    color: var(--color-ok);
}

.deploy-status-tone-error {
    color: var(--color-error);
}

.deploy-status-tone-muted {
    color: var(--color-muted);
}

.deploy-status-pill {
    display: inline-block;
    padding: 0 var(--space-sm);
    border-radius: 999px;
    font-size: var(--text-xs);
    border: 1px solid var(--color-line);
    color: var(--color-fg);
    white-space: nowrap;
}

.deploy-status-running {
    border-color: var(--color-ok);
    color: var(--color-ok);
}

.deploy-status-failed {
    border-color: var(--color-error);
    color: var(--color-error);
}

.deploy-status-starting {
    border-color: var(--color-accent);
    color: var(--color-accent);
}

.deploy-status-stopped,
.deploy-status-absent {
    border-color: var(--color-muted);
    color: var(--color-muted);
}

/* agent.agent's Logs view (the workspace layer's): one line per event of the
   agent's turn — the time it was written, then what it was — in a box that
   scrolls, since a turn runs to hundreds of lines. */
.agent-log-lines {
    max-height: 60vh;
    overflow: auto;
    font-family: monospace;
    font-size: var(--text-xs);
}

.agent-log-line {
    display: flex;
    gap: var(--space-md);
    padding: 1px 0;
}

.agent-log-time {
    flex: none;
    color: var(--color-muted);
}

.agent-log-text {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.deploy-status-hosts {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 6px 0 10px;
}

.deploy-status-host {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    font-size: 13px;
}

.deploy-status-host-name {
    font-weight: 600;
}

/* A record route: the way back to the type's list in the nav, and the
   view's own buttons in a footer under it, drawn like a dialog's. */
.viz-layernav-back {
    font-weight: 600;
    color: var(--color-accent);
    text-decoration: none;
}

.viz-layernav-back:hover {
    text-decoration: underline;
}

.viz-record-foot {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-sm);
    padding: var(--space-md) 0;
    margin-top: var(--space-md);
    border-top: 1px solid var(--color-line);
}
