/*
 * Single Emulator Mode: what is specific to this page.
 *
 * The reset, the palette, the type scale and every component both app pages share now live in
 * css/tokens.css and css/common.css, which load before this file. What is left here is the page's
 * own layout -- its grid, its parameter tree, its modals -- refining the shared components rather
 * than restating them.
 *
 * This file used to open with html { font-size: 20px } and size everything in rem, so a control
 * declared 0.85rem rendered at 17px here and the identical control on Load Test at 12px. The root
 * is now the browser's, shared with the other two pages, and every size comes from --fs-*.
 */

body {
    min-height: 100vh;
}

/* ---------------------------------------------------------------- header */

.header-left {
    display: flex;
    align-items: center;
    gap: var(--sp-5);
}

.logo {
    width: 32px;
    height: 32px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: var(--r-md);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: bold;
    font-size: var(--fs-100);
}

.header h1 {
    font-size: var(--fs-500);
}

/* At 400px width nowrap ran the indicators, the protocol field, API Docs and User Guide past the
   right edge with nothing to scroll them into view -- flex-wrap costs nothing at the widths where
   the row already fits. See css/load.css's .header-status for the same fix on the other page. */
.header-right {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-6);
}

/* Not the same object as .header-status on Load Test: there it is the whole right-hand group,
   here it is one inline run of indicators inside .header-right. */
.header-status {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    font-size: var(--fs-200);
}

/*
 * The protocol field is the one item in this row without a short, fixed word: with six devices
 * across six different protocols (COAP, DUSUN, FSH_HUB, LWM2M, MQTT, USP) it is the longest thing
 * here. Flex items default to min-width: auto, which refuses to shrink a box below its content's
 * width -- so at 400px this field alone pushed the row past the edge even after .header-right
 * above learned to wrap, because wrapping the row does not make an unshrinkable item inside it any
 * narrower. min-width: 0 lets it shrink like its neighbours.
 *
 * overflow-wrap: anywhere, not the more usual break-word: break-word only breaks a word as a last
 * resort once its box is already too narrow, and does not itself count toward how narrow the flex
 * algorithm is willing to make that box in the first place -- so the field still could not shrink
 * past its widest token ("FSH_HUB,"), which alone still ran past 400px. anywhere is the one the
 * spec lets a flex/grid sizing pass actually shrink around, at the cost of breaking a protocol
 * name mid-word in this six-different-protocols case, never in a realistic one.
 */
.protocol-field {
    min-width: 0;
}
#activeProtocol {
    overflow-wrap: anywhere;
}

.status-indicator {
    width: var(--sp-4);
    height: var(--sp-4);
    border-radius: 50%;
    background: var(--border-strong);
}

/* ---------------------------------------------------------------- layout */

.container {
    max-width: 1400px;
    margin: 0 auto;
    padding: var(--sp-8);
}

.grid {
    display: grid;
    grid-template-columns: 1fr 320px;
    gap: var(--sp-8);
}

.grid-bottom {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-8);
    margin-top: var(--sp-8);
}

/* This page stacks its panels in the document flow; Load Test lays them out with flex gaps, so
   the spacing is scoped here rather than added to the shared .panel. */
.container .panel {
    margin-bottom: var(--sp-8);
}

.panel-header .badge {
    margin-left: auto;
}

/* ---------------------------------------------------------------- forms */

/* Not the same object as .form-row on Load Test, which is a single flex line. */
.form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-5);
}

.form-group {
    margin-bottom: var(--sp-5);
}

.form-group label {
    display: block;
    font-size: var(--fs-200);
    color: var(--text-2);
    margin-bottom: var(--sp-1);
    font-weight: 500;
}

.form-group input,
.form-group select {
    width: 100%;
    /* Fields sit in a two-column grid and now render in the page font: without this their
       intrinsic width becomes the column's minimum and the row overflows its panel. */
    min-width: 0;
    padding: var(--sp-2) var(--sp-3);
    font-size: var(--fs-200);
}

/* The halo, not the focus indicator: see the same pair in css/load.css. The outline: none that
   used to sit here beat the *:focus-visible ring in css/tokens.css on specificity. */
.form-group input:focus,
.form-group select:focus {
    box-shadow: 0 0 0 2px var(--brand-100);
}

.input-with-btn {
    display: flex;
    gap: var(--sp-3);
}

.input-with-btn select,
.input-with-btn input {
    flex: 1;
}

/* ---------------------------------------------------------------- device list */

.device-list {
    max-height: 500px;
    overflow-y: auto;
}

.emulator-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--sp-3) var(--sp-5);
    background: var(--surface-0);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    margin-bottom: var(--sp-2);
}

.emulator-item:hover {
    border-color: var(--brand-800);
}

.emulator-serial {
    font-weight: 500;
    color: var(--brand-800);
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    font-size: var(--fs-300);
}

.emulator-actions {
    display: flex;
    gap: var(--sp-2);
}

.no-data {
    text-align: center;
    padding: 40px;
    color: var(--text-2);
}

.no-data .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);
}

/* ---------------------------------------------------------------- modal */

.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

/*
 * Closed is the hidden attribute: js/modal.js sets and clears it, and single.html serves both
 * overlays with it. The display: flex above outranks the browser's own [hidden] rule, so the
 * attribute would hide nothing without this one.
 */
.modal-overlay[hidden] {
    display: none;
}

.modal {
    background: var(--surface-0);
    border-radius: var(--r-lg);
    width: 95%;
    max-width: 1400px;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    box-shadow: var(--shadow-3);
}

.modal-header {
    padding: var(--sp-5) var(--sp-10);
    border-bottom: 1px solid var(--border);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.modal-header h2 {
    font-size: var(--fs-500);
    display: flex;
    align-items: center;
    gap: var(--sp-4);
}

.modal-close {
    background: none;
    border: none;
    font-size: var(--fs-600);
    cursor: pointer;
    color: var(--text-2);
    padding: var(--sp-1);
}

.modal-close:hover {
    color: var(--text-1);
}

.modal-body {
    flex: 1;
    overflow: hidden;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0;
}

.modal-section {
    padding: var(--sp-6);
    overflow-y: auto;
    border-right: 1px solid var(--border);
}

.modal-section:last-child {
    border-right: none;
}

.modal-section h3 {
    font-size: var(--fs-300);
    color: var(--text-2);
    margin-bottom: var(--sp-5);
    display: flex;
    align-items: center;
    gap: var(--sp-3);
}

/* ---------------------------------------------------------------- parameter tree */

.tree-search {
    margin-bottom: var(--sp-5);
}

.tree-search input {
    width: 100%;
    padding: var(--sp-2) var(--sp-3);
    font-size: var(--fs-200);
}

.tree-container {
    max-height: 400px;
    overflow-y: auto;
    background: var(--surface-0);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    padding: var(--sp-3);
    font-family: var(--font-mono);
    font-size: var(--fs-200);
}

.tree-node {
    user-select: none;
}

.tree-node-header {
    display: flex;
    align-items: center;
    padding: var(--sp-1) var(--sp-2);
    border-radius: var(--r-sm);
    cursor: pointer;
    gap: var(--sp-2);
}

.tree-node-header:hover {
    background: var(--surface-2);
}

.tree-node-header.selected {
    background: var(--brand-100);
}

.tree-toggle {
    width: var(--sp-6);
    color: var(--text-3);
    font-size: var(--fs-100);
}

.tree-icon {
    color: var(--text-2);
    font-size: var(--fs-100);
}

.tree-icon.folder {
    color: var(--warning);
}

.tree-icon.param {
    color: var(--brand-800);
}

.tree-label {
    flex: 1;
}

.tree-value {
    color: var(--success-fg);
    max-width: 150px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--fs-100);
}

.tree-children {
    margin-left: var(--sp-6);
    border-left: 1px dashed var(--border);
    padding-left: var(--sp-3);
}

.tree-children.collapsed {
    display: none;
}

/* ---------------------------------------------------------------- parameter edit */

.param-edit {
    margin-top: var(--sp-6);
}

.param-name-display {
    font-family: var(--font-mono);
    font-size: var(--fs-200);
    color: var(--brand-800);
    background: var(--brand-100);
    padding: var(--sp-3) var(--sp-5);
    border-radius: var(--r-sm);
    margin-bottom: var(--sp-4);
    word-break: break-all;
}

.param-edit-group {
    background: var(--surface-0);
    border: 1px solid var(--border);
    padding: var(--sp-5);
    border-radius: var(--r-md);
    margin-bottom: var(--sp-4);
}

.param-edit-group label {
    font-size: var(--fs-200);
    color: var(--text-2);
    display: block;
    margin-bottom: var(--sp-1);
}

.param-edit-group input,
.param-edit-group select {
    width: 100%;
    padding: var(--sp-2) var(--sp-3);
    font-size: var(--fs-200);
}

.param-meta {
    display: flex;
    gap: var(--sp-6);
    font-size: var(--fs-200);
    color: var(--text-2);
    margin-bottom: var(--sp-4);
}

/* ---------------------------------------------------------------- device info */

.device-info-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-3);
    font-size: var(--fs-200);
    background: var(--surface-0);
    border: 1px solid var(--border);
    padding: var(--sp-5);
    border-radius: var(--r-md);
    margin-bottom: var(--sp-6);
}

.device-info-grid strong {
    color: var(--text-2);
}

.action-group {
    background: var(--surface-0);
    border: 1px solid var(--border);
    padding: var(--sp-5);
    border-radius: var(--r-md);
    margin-bottom: var(--sp-5);
}

.action-group h4 {
    font-size: var(--fs-200);
    color: var(--text-2);
    margin-bottom: var(--sp-3);
}

.action-buttons {
    display: flex;
    gap: var(--sp-3);
    flex-wrap: wrap;
}

/* ---------------------------------------------------------------- quick guide */

.guide-item {
    display: flex;
    gap: var(--sp-4);
    padding: var(--sp-4) 0;
    border-bottom: 1px solid var(--border);
    font-size: var(--fs-200);
}

.guide-item:last-child {
    border-bottom: none;
}

.guide-step {
    width: var(--sp-10);
    height: var(--sp-10);
    background: var(--brand-800);
    color: var(--text-inverse);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-100);
    font-weight: 600;
    flex-shrink: 0;
}

.field-hint {
    font-size: var(--fs-100);
    color: var(--text-3);
    margin-top: var(--sp-1);
}

/* ---------------------------------------------------------------- upload button */

.upload-btn {
    position: relative;
    overflow: hidden;
}

.upload-btn input[type="file"] {
    position: absolute;
    left: 0;
    top: 0;
    opacity: 0;
    width: 100%;
    height: 100%;
    cursor: pointer;
}

/* ---------------------------------------------------------------- collapsible sections */

.collapsible-section {
    margin-top: var(--sp-5);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    overflow: hidden;
}

/* Negative offset for the same reason as .panel-header in css/common.css: .collapsible-section
   clips, and this header fills its top edge, so a ring drawn outside the element is drawn outside
   the section and cut off. */
.collapsible-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--sp-4) var(--sp-5);
    background: var(--surface-3);
    outline-offset: -2px;
    cursor: pointer;
    font-size: var(--fs-300);
    font-weight: 500;
    user-select: none;
}

.collapsible-header:hover {
    background: var(--surface-4);
}

.collapsible-header .icon {
    color: var(--brand-800);
    margin-right: var(--sp-2);
}

.collapse-icon {
    font-size: var(--fs-100);
    color: var(--text-2);
    transition: transform var(--dur);
}

.collapsible-content {
    padding: var(--sp-5);
    border-top: 1px solid var(--border);
}

.collapsible-content.collapsed {
    display: none;
}

/* Not the same object as .security-fields on Load Test, which is a show/hide wrapper. */
.security-fields {
    margin-top: var(--sp-3);
    padding: var(--sp-4);
    background: var(--surface-0);
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
}

/* ---------------------------------------------------------------- protocol options modal */

/*
 * Header, filter band and footer keep their height and only the list between them scrolls, so
 * Save and Cancel are on screen however long the list is. They used to sit at the bottom of the
 * scrolling body, below the fold of a long option list at the moment the window opened. The
 * dialog is bounded by .modal's max-height, and the list takes what is left of it.
 */
.protocol-options-modal {
    max-width: 600px;
}

.modal-toolbar {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-8);
    border-bottom: 1px solid var(--border);
}

.modal-toolbar-count {
    font-size: var(--fs-100);
    color: var(--text-3);
    white-space: nowrap;
}

.modal-toolbar input {
    flex: 1;
    min-width: 0;
    padding: var(--sp-1) var(--sp-3);
    font-size: var(--fs-200);
}

/* min-height: 0 is what lets the list shrink: a flex item will not go below its content without
   it, and the dialog would grow past its max-height instead, taking the footer off the screen. */
.protocol-options-modal .modal-body {
    display: block;
    overflow-y: auto;
    min-height: 0;
    padding: var(--sp-8);
}

.modal-footer {
    display: flex;
    gap: var(--sp-3);
    justify-content: flex-end;
    padding: var(--sp-5) var(--sp-8);
    border-top: 1px solid var(--border);
}

/* A row the filter does not match. The class is js/dom.js's, shared with the Load Test tab. */
.option-row.po-hidden {
    display: none;
}

.option-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--sp-4) 0;
    border-bottom: 1px solid var(--border);
    gap: var(--sp-5);
}

.option-row:last-child {
    border-bottom: none;
}

.option-label {
    font-size: var(--fs-200);
    font-weight: 500;
    min-width: 140px;
    flex-shrink: 0;
}

.option-control {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    flex: 1;
    justify-content: flex-end;
}

.option-control select,
.option-control input[type="text"] {
    padding: var(--sp-1) var(--sp-3);
    font-size: var(--fs-200);
    max-width: 220px;
    width: 100%;
}

.option-control input[type="checkbox"] {
    width: 18px;
    height: 18px;
    cursor: pointer;
}

/* The halo again, and again without the outline: none that hid the ring behind it. */
.option-control select:focus,
.option-control input[type="text"]:focus {
    box-shadow: 0 0 0 2px var(--brand-100);
}

/* ---------------------------------------------------------------- responsive */

@media (max-width: 900px) {
    .grid {
        grid-template-columns: 1fr;
    }
    .grid-bottom {
        grid-template-columns: 1fr;
    }
    .modal-body {
        grid-template-columns: 1fr;
    }
    .form-row {
        grid-template-columns: 1fr;
    }
    .option-row {
        flex-direction: column;
        align-items: flex-start;
    }
    .option-control {
        justify-content: flex-start;
        width: 100%;
    }
}
