/* harness.css — page styles for harness.html.
   Prefix every class with hs- so the three-pane workbench cannot collide with
   the shared component classes in base.css. */

body {
    padding-top: 80px;
    /* How tall a tool-output box opens at, read by `sizeOutput()` in
       harness.js. Lives here rather than in JS so wide mode can raise it by
       overriding one custom property. Only a box whose content overflows this
       gets a pinned height at all — short output keeps `height: auto`. */
    --hs-output-height: 320px;
}

.page-wrap {
    max-width: 1600px;
    margin: 0 auto;
    padding: 1rem 1.5rem 2rem;
    position: relative;
    z-index: 2;
}

/* ── layout ───────────────────────────────────────────────── */

.hs-layout {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr) 380px;
    gap: 1rem;
    /* Fill the viewport below the fixed header *exactly* — the default layout
       is one screen, and anything larger is the reader's own drag. Everything
       above and below the workbench, summed once here: a hand-tuned number
       drifts the moment one of them changes, and the symptom is a permanent
       18px scrollbar nobody can find the cause of. */
    --hs-chrome: calc(80px   /* body padding-top, clearing the fixed header */
                    + 1rem   /* .page-wrap padding-top */
                    + 2rem); /* .page-wrap padding-bottom */
    height: calc(100vh - var(--hs-chrome));
    min-height: 480px;
}

.hs-sidebar,
.hs-inspector {
    display: flex;
    flex-direction: column;
    min-height: 0;          /* lets an overflowing child scroll inside the grid */
    padding: 1rem;
}

/* A grid rather than a flex column, so `split-pane.js` can give the
   conversation/composer boundary a real track to drag. The head is `auto`
   (its height depends on how the title wraps), the conversation takes the
   remainder, and the composer is the one with a stored height. */
.hs-main {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    min-height: 0;
    padding: 1rem;
}

/* ── sidebar ──────────────────────────────────────────────── */

.hs-sidebar-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: .75rem;
}

.hs-search { margin-bottom: .75rem; font-size: .85rem; }

.hs-session-list { overflow-y: auto; flex: 1; }

.hs-session {
    padding: .6rem .7rem;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    cursor: pointer;
    margin-bottom: .35rem;
    transition: var(--transition);
}

.hs-session:hover { background: rgba(255, 255, 255, .05); }

.hs-session-active {
    background: rgba(108, 99, 255, .12);
    border-color: var(--accent);
}

.hs-session-title {
    font-size: .85rem;
    color: var(--text-1);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hs-session-meta {
    font-size: .7rem;
    color: var(--text-3);
    display: flex;
    align-items: center;
    gap: .4rem;
    margin-top: .25rem;
}

.hs-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--text-3);
    flex: none;
}

.hs-dot-running { background: var(--accent-2); animation: hs-pulse 1.2s infinite; }
.hs-dot-awaiting_approval { background: #ffb020; }
.hs-dot-error { background: var(--danger); }

@keyframes hs-pulse { 50% { opacity: .25; } }

/* ── main pane ────────────────────────────────────────────── */

.hs-main-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding-bottom: .75rem;
    border-bottom: 1px solid var(--border);
}

.hs-title { font-family: var(--font-display); font-size: 1.1rem; font-weight: 700; }
.hs-subtitle { font-size: .75rem; color: var(--text-2); margin-top: .2rem; }
.hs-main-actions { display: flex; gap: .5rem; flex: none; }

.hs-conversation {
    min-height: 8rem;       /* never collapse to a single line, however short
                               the viewport; the composer gives way instead */
    overflow-y: auto;
    padding: 1rem .25rem;
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

.hs-msg { max-width: 88%; padding: .7rem .9rem; border-radius: var(--radius); font-size: .875rem; }
.hs-msg pre { white-space: pre-wrap; word-break: break-word; font-family: inherit; margin: 0; }

.hs-msg-user {
    align-self: flex-end;
    background: var(--accent);
    color: #fff;
}

.hs-msg-assistant {
    align-self: flex-start;
    background: rgba(255, 255, 255, .05);
    border: 1px solid var(--border);
}

.hs-msg-error {
    align-self: flex-start;
    border: 1px solid var(--danger);
    color: var(--danger);
    background: rgba(255, 77, 109, .08);
}

/* ── tool cards ───────────────────────────────────────────── */

.hs-tool {
    align-self: flex-start;
    width: 88%;
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent-2);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    background: rgba(0, 212, 255, .05);
    font-size: .8rem;
}

.hs-tool-error { border-left-color: var(--danger); background: rgba(255, 77, 109, .07); }
.hs-tool-approval { border-left-color: #ffb020; background: rgba(255, 176, 32, .08); width: 88%; }

.hs-tool-head {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .7rem;
    cursor: pointer;
    user-select: none;
}

.hs-tool-name { font-family: var(--font-mono); color: var(--accent-2); }
.hs-tool-error .hs-tool-name { color: var(--danger); }
.hs-tool-summary { color: var(--text-2); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hs-caret { color: var(--text-3); font-size: .7rem; flex: none; }

.hs-tool-body { padding: 0 .7rem .6rem; border-top: 1px solid var(--border); }

.hs-tool-body pre {
    font-family: var(--font-mono);
    font-size: .72rem;
    white-space: pre-wrap;
    word-break: break-all;
    color: var(--text-2);
    margin: .5rem 0 0;
    /* A long search result used to be a 320px porthole with no way out.
       No `max-height` here: it would clamp the inline height `resize` writes, so the
       box could be dragged smaller but never larger. The starting height is set
       per box by `sizeOutput()` in harness.js, which only pins one when the
       content actually overflows — short output keeps `height: auto` and takes
       just the room it needs. */
    min-height: 4.5rem;
    overflow: auto;
    resize: vertical;
}

.hs-approval-actions { display: flex; gap: .5rem; padding: 0 .7rem .7rem; }
.hs-approval-reason { padding: 0 .7rem .5rem; color: #ffb020; font-size: .75rem; }

/* ── todo list rendering ──────────────────────────────────── */

.hs-todo { font-family: var(--font-mono); font-size: .78rem; line-height: 1.8; }

/* ── composer ─────────────────────────────────────────────── */

/* The composer's row is `auto` (see the `content` track in harness.js), so the
   pane is exactly as tall as this textarea plus the buttons — which is what
   makes the textarea's own resize corner work: the height it writes has
   somewhere to go, and the conversation's `1fr` gives up the difference. */
.hs-composer { border-top: 1px solid var(--border); padding-top: .75rem; }
.hs-input {
    min-height: 60px;
    font-size: .85rem;
    /* `.textarea` in base.css transitions `all`, and `all` includes `height`.
       On a box you can drag, that is fatal: the browser writes a new height on
       every pointer move and each one eases over 300ms, so the box trails the
       cursor and never catches up — which reads as "the resize handle does
       nothing". Keep the focus animation, drop the geometry. */
    transition: border-color var(--transition),
                background var(--transition),
                box-shadow var(--transition);
    /* A cap is needed *here* because the native corner does not go through
       JS and so cannot be told what the conversation can spare. Without it a
       long drag drives the `1fr` row to zero and the conversation's own floor
       then overflows the workbench. The divider computes an exact ceiling. */
    max-height: 50vh;
}

.hs-composer-actions {
    display: flex;
    justify-content: flex-end;
    gap: .5rem;
    margin-top: .5rem;
    align-items: center;
}

/* ── inspector ────────────────────────────────────────────── */

.hs-usage {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem 1rem;
    font-size: .72rem;
    color: var(--text-2);
    padding-bottom: .75rem;
    border-bottom: 1px solid var(--border);
}

.hs-usage b { color: var(--text-1); font-weight: 500; }

.hs-tabs { display: flex; gap: .25rem; padding: .6rem 0; }

.hs-tab {
    flex: 1;
    padding: .35rem .2rem;
    font-size: .7rem;
    color: var(--text-2);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: var(--transition);
}

.hs-tab:hover { color: var(--text-1); }
.hs-tab-active { color: var(--accent-2); border-color: var(--accent-2); background: rgba(0, 212, 255, .08); }

.hs-tab-body { flex: 1; overflow-y: auto; font-size: .74rem; }

.hs-event {
    display: grid;
    grid-template-columns: 2.2rem 1fr;
    gap: .4rem;
    padding: .3rem .35rem;
    border-radius: 4px;
    cursor: pointer;
    font-family: var(--font-mono);
    line-height: 1.5;
}

.hs-event:hover { background: rgba(255, 255, 255, .04); }
.hs-event-seq { color: var(--text-3); text-align: right; }
.hs-event-type { color: var(--accent); }
.hs-event-surface .hs-event-type { color: var(--accent-2); }
.hs-event-detail { color: var(--text-2); word-break: break-all; }

.hs-event-json {
    grid-column: 2;
    color: var(--text-3);
    font-size: .68rem;
    white-space: pre-wrap;
    word-break: break-all;
    margin-top: .25rem;
    min-height: 3rem;
    overflow: auto;
    resize: vertical;
}

.hs-fork {
    grid-column: 2;
    margin-top: .3rem;
    font-size: .68rem;
    color: var(--text-3);
    background: none;
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: .1rem .4rem;
    cursor: pointer;
}

.hs-fork:hover { color: var(--accent-2); border-color: var(--accent-2); }

.hs-derived { padding: .4rem .35rem; border-bottom: 1px solid var(--border); }
.hs-derived-role { color: var(--accent-2); font-family: var(--font-mono); font-size: .7rem; }
.hs-derived-body { color: var(--text-2); white-space: pre-wrap; word-break: break-word; margin-top: .2rem; }

.hs-plugin { padding: .5rem .35rem; border-bottom: 1px solid var(--border); }
.hs-plugin-name { font-family: var(--font-mono); color: var(--text-1); }
.hs-plugin-desc { color: var(--text-3); margin-top: .2rem; line-height: 1.5; }

.hs-badge {
    font-size: .62rem;
    padding: .05rem .35rem;
    border-radius: 3px;
    margin-left: .35rem;
    border: 1px solid var(--border);
    color: var(--text-2);
}

.hs-badge-read { border-color: var(--success); color: var(--success); }
.hs-badge-write { border-color: var(--accent-2); color: var(--accent-2); }
.hs-badge-exec { border-color: #ffb020; color: #ffb020; }

/* ── shared bits ──────────────────────────────────────────── */

.hs-empty { text-align: center; color: var(--text-2); padding: 3rem 1rem; font-size: .85rem; }
.hs-hidden { display: none !important; }
.hs-typing { color: var(--text-3); font-size: .8rem; align-self: flex-start; }

/* ── responsive ───────────────────────────────────────────── */

@media (max-width: 1200px) {
    .hs-layout { grid-template-columns: 220px minmax(0, 1fr); height: auto; }
    .hs-inspector { grid-column: 1 / -1; height: 420px; }
    .hs-main { height: 70vh; }
}

@media (max-width: 768px) {
    .hs-layout { grid-template-columns: 1fr; }
    .hs-sidebar { height: 240px; }
    .hs-msg, .hs-tool, .hs-tool-approval { max-width: 100%; width: auto; }
}

/* ── files tab ───────────────────────────────────────────────── */
.hs-file-actions {
    padding: 0 .35rem .5rem;
}

.hs-file {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .5rem .55rem;
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, .06);
    background: rgba(255, 255, 255, .02);
    margin-bottom: .35rem;
}

.hs-file-main {
    flex: 1;
    min-width: 0;
}

.hs-file-name {
    display: block;
    font-family: var(--font-mono);
    font-size: .74rem;
    color: #d6dcff;
    /* A long generated path must not push the download button off the panel. */
    overflow-wrap: anywhere;
}

.hs-file-meta {
    display: block;
    margin-top: .15rem;
    font-size: .66rem;
    color: #8b95c4;
}

/* ── wide mode ───────────────────────────────────────────────── */
/* Toggled by the 宽屏 button; `harness.js` puts `hs-wide` on <body> and
   remembers it. Three separate caps squeeze the trajectory, and widening the
   column alone does not lift any of them:
     1. the page is centred inside 1600px
     2. message bubbles stop at 88% of the column
     3. tool output opens 320px tall
   Wide mode addresses all three at once, so it is one button rather than
   three sliders. */
body.hs-wide .page-wrap { max-width: none; padding-left: 1rem; padding-right: 1rem; }
body.hs-wide .hs-msg,
body.hs-wide .hs-tool-approval { max-width: 100%; width: auto; }
body.hs-wide { --hs-output-height: 60vh; }

/* Make the grab affordance visible: a corner handle is easy to miss on a dark
   panel, and an output box that looks fixed will not be dragged. */
.hs-tool-body pre,
.hs-event-json { border-bottom: 1px dashed var(--border); }
.hs-tool-body pre:hover,
.hs-event-json:hover { border-bottom-color: var(--accent, #6ea8ff); }

/* ── resizable columns ───────────────────────────────────────── */
/* `js/widgets/split-pane.js` inserts one `.split-handle` between each pair of
   panes and rewrites `grid-template-columns` to include a track for each. The
   widths above stay as the defaults the handle double-click resets to, and as
   the layout for anyone with JS disabled. */
.split-handle {
    align-self: stretch;
    border-radius: 3px;
    cursor: col-resize;
    position: relative;
    background: transparent;
    transition: background .15s ease;
    /* The grid track is only 6px, but a 6px grab target is unpleasant to hit.
       The pseudo-element widens the *hit area* without widening the column. */
}
.split-handle::after {
    content: '';
    position: absolute;
    inset: 0 -4px;
}
.split-handle:hover,
.hs-layout.split-dragging .split-handle {
    background: var(--accent, #6ea8ff);
    opacity: .55;
}
/* While dragging, stop the panes from selecting text or swallowing the pointer
   — without this a drag across the conversation highlights every message. */
.hs-layout.split-dragging {
    user-select: none;
    cursor: col-resize;
}
.hs-layout.split-dragging .hs-sidebar,
.hs-layout.split-dragging .hs-main,
.hs-layout.split-dragging .hs-inspector {
    pointer-events: none;
}

@media (max-width: 1200px) {
    /* The grid is stacked here; a vertical divider would be meaningless.
       split-pane.js also hides them, this is the no-JS belt. */
    .split-handle { display: none; }
}

/* ── horizontal splitter (conversation / composer) ───────────── */
.split-handle-row {
    justify-self: stretch;
    cursor: row-resize;
    position: relative;
    /* Always visible, like the textarea's native resize corner below it. The
       previous version was transparent until hover, which meant the one pane
       people actually wanted to enlarge gave no hint it could be. */
    background: transparent;
}
.split-handle-row::after {
    content: '';
    position: absolute;
    inset: -5px 0;          /* widen the grab target, not the track */
}
/* The grip itself: three diagonal strokes at the right end, echoing the
   browser's own resize handle on the composer directly beneath. Drawn rather
   than borrowed — `resize: vertical` cannot be used here, because an inline
   height set by the browser would fight the grid track this pane lives in. */
.split-handle-row::before {
    content: '';
    position: absolute;
    right: .35rem;
    top: 50%;
    width: 14px;
    height: 10px;
    transform: translateY(-50%);
    opacity: .5;
    transition: opacity .15s ease;
    background-image: repeating-linear-gradient(
        135deg,
        var(--text-2) 0 1px,
        transparent 1px 4px
    );
}
.split-handle-row:hover::before,
.hs-main.split-dragging .split-handle-row::before {
    opacity: 1;
}
/* Tint on hover with a translucent colour rather than `opacity`: opacity on
   the handle would multiply into the grip drawn by ::before, dimming the very
   thing the hover is supposed to emphasise. */
.split-handle-row:hover,
.hs-main.split-dragging .split-handle-row {
    background: linear-gradient(
        to right,
        transparent,
        color-mix(in srgb, var(--accent, #6ea8ff) 45%, transparent) 40%,
        color-mix(in srgb, var(--accent, #6ea8ff) 45%, transparent) 100%
    );
    border-radius: 3px;
}
.hs-main.split-dragging {
    user-select: none;
    cursor: row-resize;
}
.hs-main.split-dragging .hs-conversation,
.hs-main.split-dragging .hs-composer {
    pointer-events: none;
}

/* ── short viewports (landscape phones, split windows) ───────── */
/* Measured on a 960x441 CSS viewport: `min-height: 480px` exceeded the
   viewport, the head and composer took ~280px between them, and the
   conversation was left showing a single line. Below this height the chrome
   gives way instead of the content. */
@media (max-height: 620px) {
    /* Drop the 480px floor, but keep the layout inside the viewport. Letting it
       grow instead turned a short *wide* window (1600x620, a split screen) into
       a three-screen page — the stacked narrow layout above already sets
       `height: auto`, which is where growing is the right answer. */
    .hs-layout { min-height: 0; }
    /* Release the conversation's floor too. Below ~500px the track it sits in
       is smaller than 8rem, and a floor larger than its own track does not
       win room — it overflows downward across the divider and the composer.
       Nothing is lost by dropping it: the composer's own `min: 64` in
       split-pane.js is what actually stops the conversation being squeezed,
       and the grid hands it everything the other three rows do not take. */
    .hs-conversation { min-height: 0; }
    .hs-main-head { padding-bottom: .4rem; }
    .hs-subtitle { display: none; }
    .hs-input { min-height: 40px; }
    .hs-composer { padding-top: .4rem; }
    .hs-composer-actions { margin-top: .3rem; }
}

/* Running-task controls must remain tappable on narrow screens. */
@media (max-width: 600px) {
  #sprite-container, #sprite-clock { display: none !important; }
}
