/*
 * The log panel and the two tables that show its entries: the docked one at the bottom of the
 * Load Test page and the fullscreen modal behind the Expand button.
 *
 * Loaded after css/load.css, which owns the rest of that page. Split out of it because the log is
 * the one part of this screen with a life of its own -- it polls, it collapses, it resizes, it has
 * a modal -- and because one sheet of everything was how the page came to be 2884 lines long.
 */

/* Log row directional accents: the third of the three ways a direction is said (see directionCell). */
.log-row .dir-in { color: var(--info-fg); font-weight: 600; }
.log-row .dir-out { color: var(--success-fg); font-weight: 600; }
.log-row .dir-ui { color: var(--text-2); font-weight: 600; }
/* The one hover, for the rows of both tables. */
.log-row:hover { background: var(--brand-050); }
/*
 * An error row: a failure event -- the page's Error, LwM2M's "... failure" and "... timeout",
 * CoAP's Timeout -- in either table. After .log-row:hover on purpose: the two have the same
 * specificity and the later one wins, so pointing at an error row leaves it red.
 */
.log-row.is-error {
    border-left: 3px solid var(--danger);
    background: var(--danger-bg);
}

/*
 * Every log row opens its entry on a click, in both tables, so every log row says so.
 *
 * One rule, unscoped, because buildLogRow gives both tables' rows this class -- the same reason
 * .log-row:hover above needs no scope. It used to be said twice: an inline row.style.cursor in
 * js/load/logs.js, which won on specificity and applied to both, and a
 * .log-fullscreen-modal tr.log-row rule here, which was outranked by it and inert. A cursor is
 * presentation and belongs in a stylesheet; setting it per row from script is also what kept it
 * out of reach of every guard in this project, which is how it was deleted once already without
 * a single test noticing.
 */
.log-row { cursor: pointer; }

/*
 * The columns that hold data read as columns: the time, the device, the options and the payload
 * are monospaced with tabular digits, so a run of timestamps lines up digit under digit. One rule,
 * unscoped, for the same reason as .log-row above. Dir and Event are words and keep the page's
 * face -- which is why neither table is monospaced as a whole any more: a table that is says it
 * for every cell, and this class would then say nothing.
 */
.log-mono {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}
/* The time carries its date -- 2026-09-14 09:05:03.123, 23 characters -- on one line in both tables. */
.log-time {
    width: 180px;
    white-space: nowrap;
}
/*
 * The other columns. Both tables lay out fixed, so the header row decides the widths -- the same
 * classes on both tables' headers -- and a cell that does not fit ends in an ellipsis instead of
 * growing its row. Payload takes what is left.
 */
.log-device { width: 140px; }
.log-dir { width: 64px; }
.log-event { width: 160px; }
.log-options { width: 30%; }
.log-raw { width: 44px; }
/*
 * One line per entry, in both tables, at a fixed height: a log is read down its columns, and a
 * payload that wrapped made every row a different height. What does not fit is read in the detail
 * dialog, one click away, where it wraps and can be copied.
 *
 * The height below is the docked table's. A fullscreen row also carries the Raw message button,
 * which keeps its 24px minimum target size, so those rows are that button plus this padding and
 * border: taller than a docked row, every one of them alike, and still one line.
 */
.log-row > td {
    height: 26px;
    padding: var(--sp-1) var(--sp-4);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    vertical-align: middle;
}

/* Log table */
.log-panel {
    /* Fixed height when expanded; collapsible (see .panel-collapsible).
       clamp() keeps it usable on small laptops and large monitors, and the drag handle
       lets whoever is actually reading the log make it taller for a while.

       The bounds are what keeps the drag safe. A resize writes an inline height, which
       outranks the rule above: without the ceiling a drag can make the log taller than
       the window and push the toolbar and the device table out of the scrollable area,
       and without the floor it can be dragged down to a title bar with no rows in it.

       The default opens at five rows under the filter bar. The chrome around the rows is 110px
       -- header 40, filter bar 32, table head 36, border 2 -- and five 26px rows make 240px, so
       the floor is 248px; the old clamp(180px, 24vh, 260px) opened at 184px on a 768px-high
       window, two rows. The middle of the page keeps its own floor (.main-content in
       css/load.css), so on a window too short for both, the scroll container takes the overflow
       -- .app-body at desktop widths, the document itself below 769px -- rather than either one
       being squeezed. */
    flex: 0 0 auto;
    height: clamp(248px, 32vh, 320px);
    min-height: 140px;
    max-height: 70vh;
    resize: vertical;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
/* Collapsed has to beat the inline height a resize leaves behind, or collapsing a log
   panel that has been dragged taller leaves the same empty box on the screen. */
.log-panel.panel-collapsible.collapsed {
    height: auto !important;
    min-height: 0;
    resize: none;
}
/* log-container also acts as panel-body but without panel-body padding */
.log-panel .panel-body.log-container {
    padding: 0;
    flex: 1;
    overflow: auto;
    /* The docked table is a focusable region -- it is how a keyboard reaches and scrolls the log
       -- and it fills a .log-panel that is overflow: hidden. A ring drawn 2px outside it is drawn
       outside the panel and clipped away; see .panel-header in css/common.css. */
    outline-offset: -2px;
}
.log-panel-actions {
    display: flex;
    gap: var(--sp-2);
    margin-left: auto;
    align-items: center;
}
.log-panel-actions .icon-btn {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--text-2);
    border-radius: var(--r-sm);
    padding: 2px var(--sp-3);
    font-size: var(--fs-100);
    cursor: pointer;
}
.log-panel-actions .icon-btn:hover {
    background: var(--surface-2);
    color: var(--brand-800);
}
/* The docked filters, between the panel's header and its table. They fold away with the table. */
.log-filters {
    display: flex;
    flex: none;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2) var(--sp-6);
    padding: var(--sp-1) var(--sp-5);
    border-bottom: 1px solid var(--border);
    font-size: var(--fs-200);
    color: var(--text-2);
}
.log-filter {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
}
.log-filters select {
    padding: 2px var(--sp-2);
    font-size: var(--fs-200);
    max-width: 200px;
}
.log-panel.panel-collapsible.collapsed .log-filters { display: none; }
/*
 * The detail dialog's Options, Payload and Raw message. They wrap between words: a token -- a URI,
 * an OID, a run of base64 -- breaks only when it is wider than the dialog on its own, where
 * break-all split any of them at whatever character happened to reach the edge.
 */
.log-detail-pre {
    background: var(--surface-1);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    padding: var(--sp-3);
    font-family: var(--font-mono);
    font-size: var(--fs-100);
    white-space: pre-wrap;
    overflow-wrap: break-word;
}
.log-detail-label {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}
/* Fullscreen log modal */
.log-fullscreen-modal {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1050;
}
.log-fullscreen-modal > .inner {
    background: var(--surface-0);
    border-radius: var(--r-md);
    width: 95vw;
    max-width: 1500px;
    height: 92vh;
    display: flex;
    flex-direction: column;
    box-shadow: var(--shadow-3);
}
.log-fullscreen-modal .head {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    padding: var(--sp-4) 14px;
    border-bottom: 1px solid var(--border);
}
.log-fullscreen-modal .body {
    flex: 1;
    overflow: auto;
    padding: 0 14px;
}
.log-fullscreen-modal table {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    font-size: var(--fs-200);
}
.log-fullscreen-modal th {
    position: sticky;
    top: 0;
    background: var(--surface-1);
    padding: var(--sp-3) var(--sp-4);
    text-align: left;
    font-weight: 600;
    color: var(--text-2);
    border-bottom: 1px solid var(--border);
    font-family: var(--font-sans);
    font-size: var(--fs-100);
    text-transform: uppercase;
    z-index: 1;
}
.log-container {
    flex: 1;
    overflow: auto;
}
.log-table {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    font-size: var(--fs-200);
}
.log-table th {
    background: var(--surface-1);
    padding: var(--sp-4) var(--sp-5);
    text-align: left;
    font-weight: 600;
    color: var(--text-2);
    position: sticky;
    top: 0;
    border-bottom: 1px solid var(--border);
    font-family: var(--font-sans);
    font-size: var(--fs-100);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.log-empty {
    text-align: center;
    padding: 30px var(--sp-8);
    color: var(--text-2);
    font-size: var(--fs-300);
}
.log-empty .icon {
    font-size: var(--fs-600);
    /* display:block puts the icon on its own line above the message. The glyph this
       replaced was text, so the block's text-align: center placed it; an <svg> is a box
       and has to centre itself. */
    display: block;
    margin: 0 auto var(--sp-4);
    color: var(--border-strong);
}
