/*
   pfodCommon.css
 * (c)2025 Forward Computing and Control Pty. Ltd.
 * NSW Australia, www.forward.com.au
 * This code is not warranted to be fit for any purpose. You may only use it at your own risk.
 * This generated code may be freely used for both private and commercial use
 * provided this copyright is maintained.
 */

/* Shared styles inlined into pfodWeb.html at build time */

        /* ============================================================
         * Roboto webfont — Apache 2.0
         * https://fonts.google.com/specimen/Roboto
         *
         * Embedded so canvas-drawn label/value text and HTML menu/button
         * text render in the same font Android pfodApp uses (Typeface.DEFAULT
         * = Roboto on Android 4.0+).  Without this, desktop Chrome / iOS
         * Safari fall back to Arial / Helvetica which differ from Roboto in
         * x-height, kerning, and the shapes of `a`, `g`, `I`, `l`.
         *
         * Subsets embedded here: latin, latin-ext — covers all European
         * Latin-script languages.  Hebrew/Arabic/CJK/Thai are NOT embedded —
         * browser falls through to Arial and finally the OS system font
         * (Noto Sans on Android), exactly matching how Android pfodApp's
         * Roboto also lacks those scripts and falls back to Noto.
         *
         * cyrillic, cyrillic-ext, greek, greek-ext are NOT
         * inlined here — they're external, on-demand @font-face rules in
         * extraFonts/pfodweb-extra-fonts.css (next to pfodWeb.html /
         * pfodProxy.exe), loaded via unicode-range so the browser only
         * fetches a subset's woff2 file when that script actually appears
         * on screen.  Adding further scripts (e.g. Thai) follows the same
         * pattern — drop a woff2 + @font-face rule into that file with no
         * rebuild of pfodWeb.html required.
         *
         * Google serves one variable-font woff2 per (style, subset) covering
         * both regular and bold weights for the 2 standard Latin/LatinExt
         * subsets, so those need only 4 @font-face rules (2 subsets × 2
         * styles) with a `font-weight: 100 900` range.
         *
         * Placeholder tokens __ROBOTO_<STYLE>_<SUBSET>__ are substituted with
         * base64-encoded woff2 contents at build time by build-bundle.js and
         * build_data.bat / build_data.sh.  The matching files live in
         * pfodWeb_src/fonts/Roboto-<Style>-<Subset>.woff2 and are produced by
         * pfodWeb_src/fonts/fetch-roboto.js.
         * ============================================================ */
        @font-face {
            font-family: 'Roboto';
            font-style: normal;
            font-weight: 100 900;
            font-display: swap;
            src: url('data:font/woff2;base64,__ROBOTO_NORMAL_LATIN__') format('woff2');
            unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
        }
        @font-face {
            font-family: 'Roboto';
            font-style: normal;
            font-weight: 100 900;
            font-display: swap;
            src: url('data:font/woff2;base64,__ROBOTO_NORMAL_LATINEXT__') format('woff2');
            unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
        }
        @font-face {
            font-family: 'Roboto';
            font-style: italic;
            font-weight: 100 900;
            font-display: swap;
            src: url('data:font/woff2;base64,__ROBOTO_ITALIC_LATIN__') format('woff2');
            unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
        }
        @font-face {
            font-family: 'Roboto';
            font-style: italic;
            font-weight: 100 900;
            font-display: swap;
            src: url('data:font/woff2;base64,__ROBOTO_ITALIC_LATINEXT__') format('woff2');
            unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
        }

        :root {
            --pfod-font-size: 4vw;
            --pfod-line-height: 0.9;
        }

        body {
            margin: 0;
            padding: 0;
            overflow: hidden;
            font-family: 'Roboto', Arial, sans-serif;
            background-color: white;
        }
        #layout-container {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            display: flex;
            overflow: hidden;
        }
        /* Resize divider - applies to both modes */
        #resize-divider {
            width: 6px;
            background-color: #ccc;
            cursor: col-resize;
            flex-shrink: 0;
            border-left: 1px solid #999;
            border-right: 1px solid #999;
            transition: background-color 0.2s;
            /* Without touch-action:none the browser interprets a touch-drag
               on this strip as a page scroll, so the pointermove handler
               never gets to update the split ratio on Android / iOS. */
            touch-action: none;
        }
        #resize-divider:hover {
            background-color: #999;
        }
        #resize-divider.dragging {
            background-color: #0066cc;
        }
        /* Bigger hit target on coarse-pointer devices (phones / tablets) —
           a 6 px strip is hard to grab with a fingertip.  Visual width stays
           the same; the wider feel comes from the negative-margin trick that
           extends the touch area outward without affecting layout. */
        @media (pointer: coarse) {
            #resize-divider {
                width: 18px;
            }
        }
        .toolbar-button {
            height: 40px;
            flex: 1;
            background-color: black;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            margin: 0;
        }
        .toolbar-button:hover {
            background-color: #333;
        }
        .toolbar-button:active {
            background-color: #555;
        }
        .toolbar-button:disabled {
            cursor: not-allowed;
            background-color: #222;
        }
        .toolbar-button:disabled svg {
            opacity: 0.35;
        }
        /* Freeze button: highlight red when active (frozen) */
        #btn-freeze.freeze-active {
            background-color: #cc0000;
        }
        #btn-freeze.freeze-active:hover {
            background-color: #ee0000;
        }
        /* Show/hide canvas-only vs chart-only toolbar buttons by body mode.
           !important overrides the body.chart-mode .toolbar-button { display:flex } rule. */
        body.chart-mode .canvas-only   { display: none !important; }
        body.message-mode .chart-only  { display: none !important; }
        body.rawdata-mode .chart-only  { display: none !important; }
        body.menu-mode .chart-only     { display: none !important; }
        body.input-mode .chart-only         { display: none !important; }
        body.numeric-input-mode .chart-only { display: none !important; }
        body.selection-mode .chart-only     { display: none !important; }
        body.input-mode #btn-reload,
        body.input-mode #btn-menu,
        body.numeric-input-mode #btn-reload,
        body.numeric-input-mode #btn-menu,
        body.selection-mode #btn-reload,
        body.selection-mode #btn-menu,
        body.streaming-mode #btn-reload,
        body.streaming-mode #btn-menu       { visibility: hidden; }

        /* MESSAGE DISPLAY MODE - default layout (blue "Requesting..." screen) */
        body.message-mode #canvas-pane {
            flex: 1;
            display: flex;
            justify-content: center;
            align-items: flex-start;
            background-color: white;
            overflow: auto;
        }
        body.message-mode #canvas-container {
            position: relative;
            width: 100%;
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: flex-start;
        }
        body.message-mode #white-border {
            background-color: white;
            border-radius: 20px;
            padding: 3px;
            border-width: 2px;
        }
        body.message-mode #black-border {
            background-color: black;
            border-radius: 18px;
            padding: 3px;
            border-width: 2px;
        }
        body.message-mode #border-inner {
            background-color: white;
            border-radius: 16px;
            padding: 5px;
            border-width: 3px;
            display: flex;
            flex-direction: column;
            height: 100%;
        }
        body.message-mode #canvas-wrapper {
            flex: 1;
            display: flex;
            justify-content: center;
            align-items: center;
            overflow: hidden;
        }
        body.message-mode #canvas-message {
            display: flex;
            background-color: #0000ff;
            width: 480px;
            height: 320px;
            align-items: center;
            justify-content: center;
            color: white;
            font: 16px 'Roboto', Arial, sans-serif;
        }
        /* Hide canvas-message in all modes except message-mode */
        body:not(.message-mode) #canvas-message {
            display: none;
        }
        body.message-mode #button-bar {
            height: 40px;
            background-color: black;
            display: flex;
            align-items: center;
            gap: 0;
            padding: 0;
            border: none;
            flex-shrink: 0;
            width: 100%;
        }
        body.message-mode .toolbar-button {
            height: 40px;
            flex: 1;
            background-color: black;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            margin: 0;
        }

        /* RAW DATA DISPLAY MODE - special layout for raw data */
        body.rawdata-mode #canvas-pane {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: stretch;
            background-color: white;
            overflow: hidden;
            min-height: 0;
        }
        body.rawdata-mode #canvas-container {
            position: relative;
            width: 100%;
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: stretch;
            min-height: 0;
        }
        body.rawdata-mode #white-border {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
        }
        body.rawdata-mode #black-border {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
        }
        body.rawdata-mode #border-inner {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            display: flex;
            flex-direction: column;
            flex: 1;
            min-height: 0;
        }
        body.rawdata-mode #canvas-wrapper {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: stretch;
            overflow: hidden;
            min-height: 0;
        }
        body.rawdata-mode canvas {
            display: none;
        }
        body.rawdata-mode #button-bar {
            height: 40px;
            background-color: black;
            display: flex;
            align-items: center;
            gap: 0;
            padding: 0;
            border: none;
            flex-shrink: 0;
            width: 100%;
        }
        body.rawdata-mode .toolbar-button {
            height: 40px;
            flex: 1;
            background-color: black;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            margin: 0;
        }

        /* STREAMING RAW DATA MODE - Section 9: {=[title]} response */
        body.streaming-mode .chart-only  { display: none !important; }
        body.streaming-mode #canvas-pane {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: stretch;
            background-color: white;
            overflow: hidden;
            min-height: 0;
        }
        body.streaming-mode #canvas-container {
            position: relative;
            width: 100%;
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: stretch;
            min-height: 0;
        }
        body.streaming-mode #white-border {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
        }
        body.streaming-mode #black-border {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
        }
        body.streaming-mode #border-inner {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            display: flex;
            flex-direction: column;
            flex: 1;
            min-height: 0;
        }
        body.streaming-mode #canvas-wrapper {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: stretch;
            overflow: hidden;
            min-height: 0;
        }
        body.streaming-mode canvas { display: none; }
        body.streaming-mode #button-bar {
            height: 40px;
            background-color: black;
            display: flex;
            align-items: center;
            gap: 0;
            padding: 0;
            border: none;
            flex-shrink: 0;
            width: 100%;
        }
        body.streaming-mode .toolbar-button {
            height: 40px;
            flex: 1;
            background-color: black;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            margin: 0;
        }
        /* Streaming prompt bar — matches #menu-prompt sizing */
        #streaming-data-prompt {
            flex-shrink: 0;
            padding: 6px 10px;
            text-align: center;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
        }
        /* Limit streaming panel to menu width, centred — raw-data msgs use menu layout */
        #streaming-data-display {
            max-width: 500px;
            align-self: center;
            width: 100%;
            container-type: inline-size;
            --pfod-font-size: 4cqi;
        }
        /* Streaming content area — uses same base font size as menu items */
        #streaming-data-content {
            flex: 1;
            overflow-y: auto;
            overflow-x: auto;
            padding: 10px;
            font-family: monospace;
            white-space: pre;
            box-sizing: border-box;
            min-height: 0;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
        }

        /* CHART DISPLAY MODE - special layout for chart rendering */
        body.chart-mode #canvas-pane {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: stretch;
            background-color: white;
            overflow: hidden;
            min-height: 0;
        }
        body.chart-mode #canvas-container {
            position: relative;
            width: 100%;
            height: 100%;
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: stretch;
            min-height: 0;
        }
        body.chart-mode #white-border {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
        }
        body.chart-mode #black-border {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
        }
        body.chart-mode #border-inner {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            display: flex;
            flex-direction: column;
            flex: 1;
            min-height: 0;
        }
        body.chart-mode #canvas-wrapper {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: stretch;
            overflow: hidden;
            min-height: 0;
        }
        body.chart-mode canvas {
            display: block;
            width: 100%;
            height: 100%;
            background-color: white;
        }
        body.chart-mode #chart-crosshair-overlay {
            background-color: transparent;
        }
        body.chart-mode #button-bar {
            height: 40px;
            background-color: black;
            display: flex;
            align-items: center;
            gap: 0;
            padding: 0;
            border: none;
            flex-shrink: 0;
            width: 100%;
        }
        body.chart-mode .toolbar-button {
            height: 40px;
            flex: 1;
            background-color: black;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            margin: 0;
        }
        #message-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(255, 255, 255, 0.9);
            z-index: 1000;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            padding: 20px;
            box-sizing: border-box;
            text-align: center;
        }
        #message-overlay h1 {
            font-size: 24px;
            margin-bottom: 20px;
            color: #333;
        }
        #message-overlay p {
            font-size: 16px;
            margin-bottom: 15px;
            color: #666;
            max-width: 600px;
        }
        #connection-prompt {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(255, 255, 255, 0.95);
            z-index: 2000;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            padding: 20px;
            box-sizing: border-box;
        }
        .prompt-container {
            background-color: white;
            padding: 14px 40px 24px;
            border-radius: 10px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            max-width: 600px;
            width: 90%;
            text-align: center;
            /* Cap the panel to the viewport so a tall connection setup
               (HTTP + Serial + proxy notice + chart-only + debug + buttons)
               doesn't get clipped off-screen on small windows.  Inner
               content scrolls vertically; the centering on #connection-
               prompt still positions the panel itself. */
            max-height: calc(100vh - 40px);
            overflow-y: auto;
            box-sizing: border-box;
        }
        .prompt-container h2 {
            color: blue;
            margin-top: 0;
            margin-bottom: 10px;
        }
        .protocol-selector {
            width: 75%;
            margin: 20px auto 10px auto;
            padding: 8px 4px;
        }
        .protocol-selector legend {
            margin: 0 auto;
        }
        .protocol-options {
            display: flex;
            justify-content: center;
            gap: 30px;
            margin: 15px 0;
        }
        .protocol-option {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        /* Protocol-selector radios only: name above the button.  The shared
           .protocol-option class is also used by the Chart-Only / Debug
           checkboxes, which must keep the tick box to the LEFT of the label. */
        .protocol-options .protocol-option {
            flex-direction: column-reverse;
            gap: 4px;
        }
        .protocol-option input[type="radio"] {
            cursor: pointer;
        }
        .protocol-option label {
            cursor: pointer;
            font-size: 16px;
        }
        .protocol-option input[type="radio"]:disabled + label {
            color: #888;
            cursor: not-allowed;
        }
        .connection-details {
            margin: 5px 0;
        }
        .connection-details input[type="text"],
        .connection-details select {
            width: 100%;
            max-width: 300px;
            padding: 6px;
            font-size: 16px;
            border: 2px solid #ddd;
            border-radius: 5px;
            margin: 6px 0;
            /* Force white field on Firefox (which otherwise uses OS Field
               colour and renders <select> gray) so it matches Chrome. */
            background-color: white;
            color: black;
        }
        .connection-details button {
            background-color: #4CAF50;
            color: white;
            padding: 10px 30px;
            border-radius: 8px;
            font-weight: bold;
            font-size: 16px;
            border: none;
            cursor: pointer;
            margin: 6px 5px;
        }
        .connection-details button:hover {
            background-color: #45a049;
        }
        .connection-details button:disabled {
            background-color: #cccccc;
            color: #666666;
            cursor: not-allowed;
        }
        .connection-details button:disabled:hover {
            background-color: #cccccc;
        }
        /* TCP/IP address input — remove the 6px top/bottom margin from the
           base input rule so the row matches the height of Baud Rate / Timeout. */
        #prompt-tcp-ip {
            margin-top: 0;
            margin-bottom: 0;
        }
        /* Disabled styling for text inputs and selects — the base rule above
           forces background:white / color:black, which overrides the browser's
           native disabled grey.  These rules restore a visually-disabled look. */
        .connection-details input[type="text"]:disabled,
        .connection-details select:disabled {
            background-color: #f0f0f0;
            color: #999;
            cursor: not-allowed;
        }
        .connection-details .help-text {
            color: #666;
            font-size: 14px;
            margin: 5px 0 10px 0;
        }
        .protocol-section {
            display: none;
        }
        .protocol-section.visible {
            display: block;
        }
        .hidden {
            display: none;
        }
        .button-container {
            width: 100%;
            display: flex;
            flex-direction: column;
            align-items: center;
        }
        #connect-button {
            margin-bottom: 0;
        }
        #load-csv-button {
            background-color: white;
            color: black;
            padding: 10px 20px;
            border-radius: 8px;
            font-weight: bold;
            font-size: 10.6px;
            border: 2px solid black;
            cursor: pointer;
            margin: 10px 5px;
            margin-top: 20px;
        }
        #load-csv-button:hover {
            background-color: #f5f5f5;
            border-color: #999;
        }
        #clear-cache-button {
            background-color: white;
            color: black;
            padding: 10px 20px;
            border-radius: 8px;
            font-weight: bold;
            font-size: 10.6px;
            border: 2px solid black;
            cursor: pointer;
            margin: 10px 5px;
            margin-top: 20px;
        }
        #clear-cache-button:hover {
            background-color: #f5f5f5;
            border-color: #999;
        }
        #clear-cache-button:disabled {
            background-color: #f0f0f0;
            color: #999;
            cursor: not-allowed;
            border-color: #ddd;
        }

        /* MENU DISPLAY MODE - vertically scrollable pfod menu */
        body.menu-mode #canvas-pane {
            flex: 1;
            display: flex;
            flex-direction: column;
            background-color: white;
            overflow: hidden;
            min-height: 0;
        }
        body.menu-mode #canvas-container {
            flex: 1;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            min-height: 0;
        }
        body.menu-mode #white-border,
        body.menu-mode #black-border {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
        }
        body.menu-mode #border-inner {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            display: flex;
            flex-direction: column;
            flex: 1;
            min-height: 0;
        }
        body.menu-mode #canvas-wrapper {
            flex: 1;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            min-height: 0;
        }
        /* The drawing-canvas is moved inside the menu scroll area in menu-mode */
        body.menu-mode #canvas-wrapper > canvas {
            display: none;
        }
        body.menu-mode #button-bar {
            height: 40px;
            background-color: black;
            display: flex;
            align-items: center;
            gap: 0;
            padding: 0;
            border: none;
            flex-shrink: 0;
            width: 100%;
            /* Match the menu's 500 px width cap + centring so the
               toolbar reads as one panel with the menu above.  Parent
               #border-inner is a column flex container, so
               align-self:center centres on the horizontal cross-axis.
               Below the cap (narrow windows) width:100% takes over. */
            max-width: 500px;
            align-self: center;
        }
        body.menu-mode .toolbar-button {
            height: 40px;
            flex: 1;
            background-color: black;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            margin: 0;
        }

        /* Menu container (hidden unless in menu-mode).
           Capped at a phone-screen-ish width so menus stay readable
           and look like a panel on wide windows, rather than stretching
           edge-to-edge.  Chart / text-input / numeric-input screens
           use their own containers and keep full window width — only
           menus are constrained. */
        #menu-container {
            display: none;
            flex-direction: column;
            flex: 1;
            overflow: hidden;
            min-height: 0;
            width: 100%;
            max-width: 500px;
            align-self: center;
            /* Make this an inline-size query container so descendants
               can scale font-size against the menu's own width (capped
               at 500px) instead of the viewport.  At the cap, 4cqi
               equals 20px — the same value 4vw produced on a 500px
               viewport, so narrow-window behaviour is unchanged while
               wider windows no longer enlarge the menu text. */
            container-type: inline-size;
            --pfod-font-size: 4cqi;
        }
        body.menu-mode #menu-container {
            display: flex;
        }
        /* Scrollable area containing menu items */
        #menu-scroll-area {
            flex: 1;
            overflow-y: auto;
            overflow-x: hidden;
            -webkit-overflow-scrolling: touch;
            background-color: black;
            padding: 4px 8px;
        }
        /* Prompt text fixed at the bottom of the menu.
           Capped at 50% of the menu height with internal scrolling so a
           long device-set prompt never collapses the items' scroll area
           to 0.  Items get at least the other 50%; on a tall window
           with a short prompt the prompt sits at its natural height and
           the items take the remainder.  The 50% cap is OVERRIDDEN by
           the .no-items rule below when the menu carries zero items —
           help-only screens then get the full container height. */
        #menu-prompt {
            flex-shrink: 1;
            min-height: 0;
            max-height: 50%;
            overflow-y: auto;
            padding: 6px 10px;
            text-align: center;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            /* Bottom-align the prompt text within its area: when the
               area is taller than the text (short prompt, or the
               no-items case where it fills the whole container), the
               text sits at the bottom rather than the top.  Items in
               #menu-scroll-area stay top-aligned by default block
               flow, so the two areas mirror each other.
               IMPORTANT: bottom-alignment is done via a ::before
               pseudo-element that absorbs the empty vertical space,
               NOT via `justify-content: flex-end` (overflow gets
               clipped above the visible area) and NOT via
               `margin-top: auto` on direct children (a previous
               approach — it silently DISTRIBUTED space between
               siblings when the renderer happened to append more
               than one direct child, producing visible blank lines
               around each <i><y>…</i> span on the help screens).
               The pseudo-element approach has neither failure mode:
               ::before absorbs the slack as a flex item, real
               children stack tight below it whether there's one or
               many, and on overflow ::before shrinks to 0 (flex
               grow/shrink) so overflow scrolling behaves normally. */
            display: flex;
            flex-direction: column;
        }
        /* Slack-absorbing pseudo-element: takes whatever vertical
           space the real prompt content doesn't need, pushing the
           content to the bottom of the prompt area.  flex:1 1 0 +
           min-height:0 lets it shrink to zero when content overflows
           — at which point overflow-y:auto on the container handles
           the rest.  Replaces the older `> * { margin-top: auto }`
           which had the distribution-across-siblings bug. */
        #menu-prompt::before {
            content: '';
            flex: 1 1 0;
            min-height: 0;
        }
        /* No-items menu (help / about / pure-text screens):  hide the
           empty scroll-area and let the prompt expand to fill.  The
           class is toggled in pfodMenuDisplay.js based on
           menuData.items.length === 0. */
        #menu-container.no-items #menu-scroll-area {
            display: none;
        }
        #menu-container.no-items #menu-prompt {
            max-height: none;
            flex: 1;
        }
        /* No-prompt menu (items only — device sent no header title).
           Hide the empty prompt strip so the items area gets the full
           menu-container height.  Class toggled in pfodMenuDisplay.js
           when header.title is empty. */
        #menu-container.no-prompt #menu-prompt {
            display: none;
        }

        /* pfod menu item styles */
        .pfod-menu-button {
            display: block;
            width: 100%;
            padding: 10px 12px;
            margin: 0 0 4px 0;
            border: 2px solid black;
            border-radius: 8px;
            background-color: inherit;
            color: #000;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            font-family: 'Roboto', Arial, sans-serif;
            text-align: center;
            cursor: pointer;
            box-sizing: border-box;
        }
        .pfod-menu-button:active {
            filter: brightness(0.85);
        }
        .pfod-menu-button:disabled {
            border: 2px dashed black;
            border-radius: 8px;
            color: #888;
            cursor: not-allowed;
            opacity: 1;
        }
        .pfod-menu-button:disabled:active {
            filter: none;
        }
        /* Flash animation for pfod buttons carrying the '+' non-sticky flag.
           Targets only the text span so the button border and background stay visible. */
        @keyframes pfod-flash-anim {
            0%, 83% { visibility: visible; }
            83.1%, 100% { visibility: hidden; }
        }
        .pfod-flash .pfod-button-text {
            animation: pfod-flash-anim 1.2s step-start infinite;
        }
        /* Same animation when the prompt format carries `+`.  Targets
           the inner block pfodSetFormattedText creates inside the
           flex container — the only direct child of #menu-prompt — so
           only the prompt text flashes, leaving padding/background
           steady.  Falls back to the prompt element itself if no
           wrapper was added (e.g. simpler future renders). */
        #menu-prompt.pfod-flash > * {
            animation: pfod-flash-anim 1.2s step-start infinite;
        }
        .pfod-menu-label {
            /* Plain block display.  An earlier `display:flex` +
               `display:contents` on the inner span tried to make
               the label tightly hug its inner text when the
               text used inline `<-N>` size tags, but that combo
               turned the inner styled spans into flex-row items
               and broke multi-line headers that mix bold/coloured
               spans separated by `\n` — e.g. the editor's
               "Editing Menu Item from\n<l><name>" header laid out
               horizontally instead of stacking on two lines.
               Block flow lets pre-wrap line breaks render
               naturally, multiple styled spans flow inline within
               the block, and line-height (set below) handles
               vertical centring of single-line text. */
            display: block;
            width: 100%;
            /* Padding kept minimal so the label hugs its text
               vertically (matches pfodApp's tight-label look — the
               label's own background fills only what the text
               needs).  Horizontal padding stays generous so coloured
               backgrounds don't visually clip the text at the edges.
               Margin gives the visible above/below gap that
               separates one label from the next — both top and
               bottom so adjacent labels of the same colour still
               read as distinct rows, and the gap doesn't depend on
               which side the previous element put its margin on.
               All values in `em` so spacing scales with the label's
               own font-size (matches the unitless line-height —
               <-12>-sized labels collapse proportionally as
               designer spacers expect). */
            padding: 0.1em 0.6em;
            margin: 0.3em 0;
            background-color: inherit;
            font-size: var(--pfod-font-size);
            /* Labels use line-height: 1.2 (natural) rather than the
               --pfod-line-height (0.9) that the menu uses globally.
               At 0.9 the line box is smaller than the glyph's
               natural em-height, so the baseline sits low in the
               line box and single-line text appeared to have extra
               space above it.  1.2 gives the line box room for the
               glyph and vertically centres the text naturally. */
            line-height: 1.2;
            font-family: 'Roboto', Arial, sans-serif;
            text-align: center;
            box-sizing: border-box;
        }
        /* Empty-text label: collapses to a thin separator line
           regardless of font-size.  pfodButtonRenderer.js adds the
           .pfod-empty-label class when item.text is the empty
           string.  Padding is removed entirely and line-height
           shrunk so the label's vertical footprint reads as a
           ~few-px tap-able gap rather than a full label row.  Keeps
           the bottom margin so a stack of empty labels still has
           inter-item separation. */
        .pfod-menu-label.pfod-empty-label {
            padding: 0;
            line-height: 0.3;
        }
        /* pfod Toggle Button (interactive, has text and/or switch) */
        .pfod-toggle-button {
            display: block;
            width: 100%;
            padding: 10px 12px;
            margin: 0 0 4px 0;
            border: 2px solid black;
            border-radius: 8px;
            background-color: inherit;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            font-family: 'Roboto', Arial, sans-serif;
            text-align: center;
            cursor: pointer;
            box-sizing: border-box;
        }
        .pfod-toggle-button:active {
            filter: brightness(0.85);
        }
        /* pfod Toggle Label (non-interactive, no border — like plain labels) */
        .pfod-toggle-label {
            display: block;
            width: 100%;
            padding: 10px 12px;
            margin: 0 0 4px 0;
            background-color: inherit;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            font-family: 'Roboto', Arial, sans-serif;
            text-align: center;
            box-sizing: border-box;
        }
        /* Text span above the switch row; inherits item font/colour formatting */
        .pfod-toggle-text {
            display: block;
            margin-bottom: 6px;
        }
        /* Row containing opt-label / track / opt-label.
           All inherited item formats are stripped: size reset to pfod default (font 0),
           style/weight/decoration cleared. Colour is set to <bw> in JS. */
        .pfod-toggle-slider-row {
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
            margin-top: 16px;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            font-style: normal;
            font-weight: normal;
            text-decoration: none;
            white-space: nowrap;
        }
        .pfod-toggle-opt-label {
            flex-shrink: 0;
        }
        /* Div-based toggle switch — identical rendering across all browsers */
        .pfod-toggle-track {
            position: relative;
            flex: 0 0 auto;
            width: 18vw;
            max-width: 110px;
            min-width: 56px;
            height: 22px;
            border-radius: 11px;
            background: #444;
            cursor: pointer;
        }
        .pfod-toggle-track-disabled {
            opacity: 0.85;
            cursor: default;
        }
        .pfod-toggle-thumb {
            position: absolute;
            top: 50%;
            left: -2px;
            transform: translateY(-50%);
            width: 26px;
            height: 26px;
            border-radius: 50%;
            background: radial-gradient(circle at 38% 35%, #e0e0e0, #888);
            box-shadow: 0 2px 5px rgba(0,0,0,0.5);
            transition: left 0.15s ease;
            pointer-events: none;
        }
        .pfod-toggle-thumb-right {
            left: calc(100% - 24px);
        }
        /* Multi-option slider (>2 options) — full-width thin track with labels below */
        .pfod-slider-container {
            width: 100%;
            box-sizing: border-box;
        }
        /* Hit area: tall transparent flexbox that centres the track vertically.
           Height = track (10px) + 2 × (2 × thumb-diameter 32px) = 138px.
           This gives a ±64px clickable zone above and below the thin track. */
        .pfod-slider-hit-area {
            display: flex;
            align-items: center;
            width: 100%;
            height: 44px;
            cursor: pointer;
            box-sizing: border-box;
        }
        .pfod-slider-hit-area-disabled {
            cursor: default;
        }
        .pfod-slider-track {
            position: relative;
            width: 100%;
            height: 10px;
            border-radius: 5px;
            background: #444;
            box-sizing: border-box;
        }
        .pfod-slider-thumb {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            width: 32px;
            height: 32px;
            border-radius: 50%;
            background: radial-gradient(circle at 38% 35%, #e0e0e0, #888);
            box-shadow: 0 2px 5px rgba(0,0,0,0.5);
            transition: left 0.15s ease;
            pointer-events: none;
        }
        /* Label row below the slider: first option left, last option right */
        .pfod-slider-opt-labels-row {
            display: flex;
            justify-content: space-between;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            font-style: normal;
            font-weight: normal;
            text-decoration: none;
            white-space: nowrap;
        }
        /* Navigation button D-pad cross layout — rows are assigned dynamically in JS */
        .pfod-menu-nav-row {
            display: grid;
            grid-template-columns: 15cqi 15cqi 15cqi;
            row-gap: 4px;
            column-gap: 4cqi;
            margin-bottom: 4px;
            justify-content: center;
        }
        .pfod-menu-nav-button {
            min-width: 15cqi;
            min-height: 8cqi;
            padding: 6px 4px;
            border: 2px solid black;
            border-radius: 8px;
            background-color: inherit;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            cursor: pointer;
            text-align: center;
            white-space: pre-wrap;
        }
        .pfod-menu-nav-label {
            font-family: 'Roboto', Arial, sans-serif;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            padding: 2px 4px;
            white-space: pre-wrap;
        }
        /* Drawing item wrapper inside the menu scroll area */
        .pfod-menu-dwg-wrapper {
            width: 100%;
            margin-bottom: 4px;
            display: flex;
            justify-content: center;
        }
        .pfod-menu-dwg-wrapper canvas {
            display: block;
            width: 100%;
            height: auto;
            border: 2px solid black;
            border-radius: 8px;
            box-sizing: border-box;
        }
        /* Placeholder shown inside a menu drawing wrapper while the dwg
           dimensions are still in flight (first load, cache clear, slow BLE).
           Removed from the DOM once the device's response populates the
           drawing data — see pfodMenuDisplay.handleMenuResize. */
        .pfod-menu-dwg-loading {
            width: 100%;
            box-sizing: border-box;
            border: 2px solid black;
            border-radius: 8px;
            background-color: #0000ff;
            color: white;
            font-family: Arial, sans-serif;
            font-size: 16px;
            font-weight: bold;
            text-align: center;
            padding: 28px 12px;
        }

        /* INPUT DISPLAY MODE - text input (Section 10: {'...}).  The
           input panel itself (#input-container + children) is black-on-
           white; the surrounding wrappers are WHITE so on wide windows
           the area beside the 500-px-capped panel reads as a frame
           that matches menu-mode. */
        body.input-mode #canvas-pane {
            flex: 1;
            display: flex;
            flex-direction: column;
            background-color: white;
            overflow: hidden;
            min-height: 0;
        }
        body.input-mode #canvas-container {
            flex: 1;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            min-height: 0;
        }
        body.input-mode #white-border,
        body.input-mode #black-border {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
        }
        body.input-mode #border-inner {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            display: flex;
            flex-direction: column;
            flex: 1;
            min-height: 0;
        }
        body.input-mode #canvas-wrapper {
            flex: 1;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            min-height: 0;
        }
        body.input-mode #canvas-wrapper > canvas {
            display: none;
        }
        body.input-mode #button-bar {
            height: 40px;
            background-color: black;
            display: flex;
            align-items: center;
            gap: 0;
            padding: 0;
            border: none;
            flex-shrink: 0;
            width: 100%;
            /* Match the 500 px cap + centring used by #input-container
               below, so toolbar + input pane read as one panel — same
               pattern as the menu-mode toolbar. */
            max-width: 500px;
            align-self: center;
        }
        body.input-mode .toolbar-button {
            height: 40px;
            flex: 1;
            background-color: black;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            margin: 0;
        }
        /* Input container (hidden unless in input-mode).
           container-type:inline-size + --pfod-font-size:4cqi mirror
           #menu-container so the input panel's fonts cap at the
           container's 500-px inline-size instead of scaling with the
           viewport.  pfodSetFormattedText's default font resolver
           already emits cqi units; with no container ancestor those
           fall back to viewport — establishing one here is what makes
           the cap kick in. */
        #input-container {
            display: none;
            container-type: inline-size;
            --pfod-font-size: 4cqi;
        }
        body.input-mode #input-container {
            display: flex;
            flex-direction: column;
            flex: 1;
            min-height: 0;
            /* Cap at the same 500 px width as the menu-mode container
               so input screens read as a centred panel on wide windows.
               Parent #canvas-wrapper is flex column, so align-self:center
               centres on the horizontal cross-axis. */
            width: 100%;
            max-width: 500px;
            align-self: center;
        }
        #input-textarea {
            flex: 1;
            background: black;
            color: white;
            border: none;
            resize: none;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            text-align: left;
            padding: 4px;
            outline: none;
            min-height: 0;
        }
        #input-prompt {
            color: white;
            background: black;
            text-align: center;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            padding: 4px 0;
            flex-shrink: 0;
            /* Bottom-align via ::before pseudo-element (same pattern
               and rationale as #menu-prompt above — see the longer
               comment there).  The older `> * { margin-top: auto }`
               approach silently distributed space across siblings
               whenever the renderer appended more than one direct
               child. */
            display: flex;
            flex-direction: column;
        }
        #input-prompt::before {
            content: '';
            flex: 1 1 0;
            min-height: 0;
        }
        #input-action-bar {
            display: flex;
            align-items: center;
            background: black;
            padding: 4px;
            flex-shrink: 0;
            gap: 8px;
        }
        #input-submit-btn {
            background: white;
            border: 1px solid #ccc;
            border-radius: 4px;
            cursor: pointer;
            flex-shrink: 0;
            width: 48px;
            height: 40px;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
        }
        #input-popup {
            display: flex;
            align-items: center;
            border: 2px solid black;
            border-radius: 20px;
            background: white;
            padding: 6px 14px;
            font-size: 14px;
            color: #333;
        }

        /* NUMERIC INPUT DISPLAY MODE - full-screen slider+edit input (Section 11: {#...}) */
        body.numeric-input-mode #canvas-pane {
            flex: 1;
            display: flex;
            flex-direction: column;
            background-color: white;
            overflow: hidden;
            min-height: 0;
        }
        body.numeric-input-mode #canvas-container {
            flex: 1;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            min-height: 0;
        }
        body.numeric-input-mode #white-border,
        body.numeric-input-mode #black-border {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            flex: 1;
            display: flex;
            flex-direction: column;
            min-height: 0;
        }
        body.numeric-input-mode #border-inner {
            background-color: white;
            border-radius: 0;
            padding: 0;
            border-width: 0;
            display: flex;
            flex-direction: column;
            flex: 1;
            min-height: 0;
        }
        body.numeric-input-mode #canvas-wrapper {
            flex: 1;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            min-height: 0;
        }
        body.numeric-input-mode #canvas-wrapper > canvas {
            display: none;
        }
        body.numeric-input-mode #button-bar {
            height: 40px;
            background-color: black;
            display: flex;
            align-items: center;
            gap: 0;
            padding: 0;
            border: none;
            flex-shrink: 0;
            width: 100%;
            max-width: 500px;
            align-self: center;
        }
        body.numeric-input-mode .toolbar-button {
            height: 40px;
            flex: 1;
            background-color: black;
            border: none;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
            margin: 0;
        }
        /* Numeric input container (hidden unless in numeric-input-mode).
           Same container-query font cap as #menu-container / #input-container. */
        #numeric-input-container {
            display: none;
            container-type: inline-size;
            --pfod-font-size: 4cqi;
        }
        body.numeric-input-mode #numeric-input-container {
            display: flex;
            flex-direction: column;
            flex: 1;
            min-height: 0;
            background: black;
            position: relative;
            width: 100%;
            max-width: 500px;
            align-self: center;
        }
        #numeric-input-top {
            flex: 1;
            min-height: 0;
            display: flex;
            flex-direction: column;
            position: relative;
            overflow: hidden;
        }
        #numeric-input-value-display {
            padding: 12px 8px 4px 8px;
            cursor: pointer;
        }
        #numeric-input-value-text {
            color: white;
            font-size: 7cqi;
            font-weight: bold;
            display: block;
        }
        #numeric-input-field {
            display: none;
            background: black;
            color: white;
            border: none;
            border-bottom: 2px solid white;
            font-size: 7cqi;
            width: 100%;
            outline: none;
            padding: 4px 0;
            box-sizing: border-box;
        }
        #numeric-input-slider {
            width: calc(100% - 16px);
            margin: 8px 8px;
            display: block;
        }
        #numeric-input-prompt {
            color: #aaa;
            font-size: var(--pfod-font-size);
            line-height: var(--pfod-line-height);
            padding: 8px 8px 0 8px;
        }
        #numeric-input-popup {
            display: none;
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            align-items: center;
            border: 2px solid black;
            border-radius: 20px;
            background: white;
            padding: 6px 14px;
            font-size: 14px;
            color: #333;
            white-space: nowrap;
            z-index: 10;
        }
        #numeric-input-action-bar {
            display: flex;
            align-items: center;
            background: black;
            padding: 4px;
            flex-shrink: 0;
            gap: 8px;
        }
        #numeric-input-submit-btn {
            background: white;
            border: 1px solid #ccc;
            border-radius: 4px;
            cursor: pointer;
            flex-shrink: 0;
            width: 48px;
            height: 40px;
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 0;
        }

        /* SELECTION MODE - single (Section 12: {?...}) and multi (Section 13: {*...}) */
        body.selection-mode #canvas-pane {
            flex: 1; display: flex; flex-direction: column;
            background-color: white; overflow: hidden; min-height: 0;
        }
        body.selection-mode #canvas-container {
            flex: 1; display: flex; flex-direction: column;
            overflow: hidden; min-height: 0;
        }
        body.selection-mode #white-border,
        body.selection-mode #black-border {
            background-color: white; border-radius: 0; padding: 0; border-width: 0;
            flex: 1; display: flex; flex-direction: column; min-height: 0;
        }
        body.selection-mode #border-inner {
            background-color: white; border-radius: 0; padding: 0; border-width: 0;
            display: flex; flex-direction: column; flex: 1; min-height: 0;
        }
        body.selection-mode #canvas-wrapper {
            flex: 1; display: flex; flex-direction: column; overflow: hidden; min-height: 0;
        }
        body.selection-mode #canvas-wrapper > canvas { display: none; }
        body.selection-mode #button-bar {
            height: 40px; background-color: black; display: flex;
            align-items: center; gap: 0; padding: 0; border: none;
            flex-shrink: 0; width: 100%;
            max-width: 500px; align-self: center;
        }
        body.selection-mode .toolbar-button {
            height: 40px; flex: 1; background-color: black; border: none;
            cursor: pointer; display: flex; align-items: center;
            justify-content: center; padding: 0; margin: 0;
        }
        /* Selection container — same container-query font cap as the
           other input/menu containers, so prompt + option labels stop
           scaling once the panel hits its 500-px width cap. */
        #selection-container {
            display: none;
            container-type: inline-size;
            --pfod-font-size: 4cqi;
        }
        body.selection-mode #selection-container {
            display: flex; flex-direction: column; flex: 1; min-height: 0; background: black;
            width: 100%; max-width: 500px; align-self: center;
        }
        #selection-list {
            flex: 1; overflow-y: auto; min-height: 0;
        }
        .selection-item {
            display: flex; align-items: center; justify-content: space-between;
            padding: 5px 8px; cursor: pointer; min-height: 26px;
        }
        .selection-label {
            color: white; font-size: var(--pfod-font-size); line-height: var(--pfod-line-height); flex: 1;
        }
        .selection-separator {
            height: 1px; background: #333; margin: 0 8px;
        }
        /* Selection controls — halved from the previous 28×28 outer /
           12 px inner so they read as compact "pickers" on long lists
           like the colour picker (17 options).  Borders / tick stroke
           also scaled down so the visual weight stays balanced. */
        .selection-checkbox {
            width: 14px; height: 14px; border: 1px solid #1a4e8c;
            background: transparent; flex-shrink: 0;
            display: flex; align-items: center; justify-content: center;
            position: relative;
        }
        .selection-checkbox.selected { background: #1a4e8c; }
        .selection-checkbox.selected::after {
            content: ''; position: absolute;
            width: 3px; height: 6px;
            border-right: 2px solid white; border-bottom: 2px solid white;
            transform: rotate(45deg) translate(-1px, -1px);
        }
        .selection-radio {
            /* White border so the circle is visible against the
               #selection-container's black background — the previous
               #1a4e8c border was nearly invisible on black until the
               item was selected. */
            width: 14px; height: 14px; border: 1px solid white;
            border-radius: 50%; background: transparent; flex-shrink: 0;
            display: flex; align-items: center; justify-content: center;
            position: relative;
        }
        .selection-radio.selected { background: #1a4e8c; }
        .selection-radio.selected::after {
            content: ''; position: absolute;
            width: 6px; height: 6px;
            border-radius: 50%; background: white;
        }
        #selection-prompt {
            color: #aaa; font-size: var(--pfod-font-size); line-height: var(--pfod-line-height); text-align: center;
            padding: 8px; flex-shrink: 0;
        }
        #selection-action-bar {
            display: flex; align-items: center; background: black;
            padding: 4px; flex-shrink: 0; gap: 8px;
        }
        #selection-submit-btn {
            background: white; border: 1px solid #ccc; border-radius: 4px;
            cursor: pointer; flex-shrink: 0; width: 48px; height: 40px;
            display: flex; align-items: center; justify-content: center; padding: 0;
        }

        /* "Change Target" button on the Designer settings panel.  Black
           text on white background, with a thin grey border so the edge
           is visible against the prompt's near-white scrim.  Size /
           font are NOT overridden — keeps the dimensions identical to
           the browser-default look the user is replacing. */
        #designer-target-btn,
        #select-com-port-btn,
        #select-ble-device-btn {
            background-color: white;
            color: black;
            border: 1px solid #888;
        }
        #designer-target-btn {
            padding-left: 24px;
            padding-right: 24px;
        }
        /* Reduce the picker buttons to select-element height so their rows
           have the same vertical footprint as the Baud Rate / Timeout rows.
           The generic .connection-details button rule gives 10px top/bottom
           padding and 6px top/bottom margin — both are too tall here. */
        #select-com-port-btn,
        #select-ble-device-btn {
            padding-top: 4px;
            padding-bottom: 4px;
            margin-top: 0;
            margin-bottom: 0;
        }
        #designer-target-btn:hover,
        #select-com-port-btn:hover,
        #select-ble-device-btn:hover {
            background-color: #f5f5f5;
        }
        /* ID-specific disabled override — the ID selector (specificity 100)
           beats .connection-details button:disabled (specificity 011), so
           the grey disabled rule above doesn't reach these buttons without
           an equally-specific rule here. */
        #select-com-port-btn:disabled,
        #select-ble-device-btn:disabled {
            background-color: #cccccc;
            color: #666666;
            cursor: not-allowed;
            border-color: #bbb;
        }

        /* Board-selector overlay — Designer Target picker.  Modeled after
           #connection-prompt: fixed full-viewport scrim, centered panel.
           Hidden by default; openBoardSelector() flips display to flex. */
        #board-selector-overlay {
            position: fixed; top: 0; left: 0; width: 100%; height: 100%;
            background-color: rgba(0, 0, 0, 0.45);
            /* Must sit above #connection-prompt (z-index 2000) — the
               "Change Target" button lives inside that prompt, so the
               selector has to render on top of it. */
            z-index: 2100;
            display: flex; align-items: center; justify-content: center;
            padding: 20px; box-sizing: border-box;
        }
        #board-selector-panel {
            background: white; border-radius: 8px;
            box-shadow: 0 6px 24px rgba(0, 0, 0, 0.25);
            /* 540px = 360px × 1.5 (50% wider than the previous 360px max).
               95% viewport clamp keeps it clear of screen edges on small screens. */
            width: min(540px, 95%); max-height: 80vh;
            display: flex; flex-direction: column; overflow: hidden;
        }
        #board-selector-header {
            display: flex; align-items: center; justify-content: space-between;
            padding: 12px 16px; border-bottom: 1px solid #ddd;
            background: #f7f7f7;
        }
        #board-selector-header h2 {
            margin: 0; font-size: 18px; color: #333;
        }
        #board-selector-close {
            background: transparent; border: none; font-size: 24px;
            line-height: 1; cursor: pointer; padding: 0 6px; color: #555;
        }
        #board-selector-close:hover { color: #000; }
        /* Up/down scroll chevrons that sit ABOVE and BELOW the list — wired
           by boardSelector.js to scroll the list when content overflows.
           Hidden by default; the JS reveals them only when scrollHeight
           exceeds clientHeight.  Click steps a fixed amount; hold to
           keep stepping. */
        #board-selector-scroll-up,
        #board-selector-scroll-down {
            display: none;
            background: #f7f7f7; border: none; border-top: 1px solid #ddd;
            border-bottom: 1px solid #ddd;
            font-size: 14px; line-height: 1; padding: 4px 0;
            cursor: pointer; color: #555;
            text-align: center;
        }
        #board-selector-scroll-up   { border-top:    none; }
        #board-selector-scroll-down { border-bottom: none; }
        #board-selector-scroll-up:hover,
        #board-selector-scroll-down:hover { background: #eef5ff; color: #000; }
        #board-selector-list {
            padding: 0 16px; overflow-y: auto;
            display: flex; flex-direction: column; gap: 0;
        }
        .board-family-btn {
            background: white; border: 1px solid #bbb; border-radius: 6px;
            /* Tight vertical padding — the user wants minimal whitespace
               above/below each row so the family list reads as a dense
               picker, not a spaced-out menu. */
            padding: 2px 16px; font-size: 16px; text-align: left;
            cursor: pointer; color: #222;
        }
        .board-family-btn:hover { background: #eef5ff; border-color: #6aa6ff; }
        /* Back row is rendered as just another .board-family-btn so it
           inherits keyboard nav + scroll-into-view; this rule just
           tints it so the "go up one level" affordance reads at a
           glance and doesn't get mistaken for a selectable target. */
        .board-back-btn { background: #f0f0f0; color: #555; }
        .board-back-btn:hover { background: #e2e9f5; }
        /* Keyboard-focus highlight — applied by boardSelector.js as the
           user moves the focused index with ↑/↓.  Distinct from :hover
           so mouse hover and keyboard cursor can coexist without
           fighting for the same visual treatment. */
        .board-family-btn.kb-focused {
            background: #d8e8ff; border-color: #3a78d8; outline: none;
        }
