/* CONTROL: the default. Near-black, violet, high contrast -- a machine room.
   Every colour in the sheet is a token so the second persona can swap the whole
   look by redefining this block and nothing else. */
:root {
    --bg-primary: #050508;
    --bg-secondary: #0a0a12;
    --bg-tertiary: #12121e;
    --text-primary: #d0d0e0;
    --text-secondary: #5a5a7a;
    --accent: #7c3aed;
    --danger: #dc2626;
    --success: #22c55e;
    --border: #1a1a2e;

    /* Feedback levels: neutral, green, amber, red, neutral. */
    --level-1: #1a3a2a;
    --level-2: #2a3a1a;
    --level-3: #3a1a1a;

    /* Translucent derivatives. Kept as tokens rather than colour-mix() so the
       whole sheet stays within what the older mobile browsers here support. */
    --accent-wash:   rgba(124, 58, 237, 0.15);
    --accent-glow:   rgba(124, 58, 237, 0.30);
    --accent-shadow: rgba(124, 58, 237, 0.35);
    --danger-wash:   rgba(220, 38, 38, 0.10);
    --success-glow:  rgba(34, 197, 94, 0.50);
    --on-accent: #ffffff;
    /* The subtitle beside the logo. Red reads as a machine warning here; the
       study wants a label, not an alarm. */
    --version-fg: #dc2626;
}

/* STUDY: pale, cool, calm -- a lab rather than a machine room. Same structure,
   same contrast discipline, opposite mood. */
:root[data-persona="study"] {
    --bg-primary: #eef1f4;
    --bg-secondary: #e2e8ec;
    --bg-tertiary: #d3dce2;
    --text-primary: #24333c;
    --text-secondary: #6a7c88;
    --accent: #0e7c86;
    --danger: #a8453c;
    --success: #2c7f57;
    --border: #c2ced6;

    --level-1: #cfe0d4;
    --level-2: #e3e2c6;
    --level-3: #eed3ce;

    --accent-wash:   rgba(14, 124, 134, 0.12);
    --accent-glow:   rgba(14, 124, 134, 0.22);
    --accent-shadow: rgba(14, 124, 134, 0.25);
    --danger-wash:   rgba(168, 69, 60, 0.10);
    --success-glow:  rgba(44, 127, 87, 0.40);
    --on-accent: #ffffff;
    --version-fg: #35707a;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* Any element here with an explicit `display` would otherwise beat the browser's
   [hidden] rule, so toggling .hidden from JS would silently do nothing. */
[hidden] { display: none !important; }

/* Typography rule: every visible string is either ALL CAPS or all lowercase,
   never mixed. Caps carry structure -- headings, controls, machine telemetry.
   Lowercase carries voice and description. */
h2, h3,
.btn-feedback, .btn-stop, .btn-stop-mobile,
.picker-label, .metric-label, .metric-value,
.connection-status, .hold-label, .logo, .version,
.log-entry.log-system {
    text-transform: uppercase;
}

.mode-card p,
.log-entry.log-aria,
#toy-name, #log-placeholder,
select, option {
    text-transform: lowercase;
}

html, body {
    font-family: 'Courier New', Courier, monospace;
    background: var(--bg-primary);
    color: var(--text-primary);
    height: 100%;
    overflow: hidden; /* Prevent body scroll, let inner containers handle it */
}

.app-container {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh; /* Dynamic viewport height for mobile browsers */
    padding: 16px;
    gap: 16px;
}

.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}

.logo {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 1.2rem;
    font-weight: bold;
    letter-spacing: 2px;
}

.logo-icon { color: var(--accent); font-size: 1.5rem; }
.version { color: var(--version-fg); font-size: 0.65rem; letter-spacing: 1px; }
.connection-status { color: var(--text-secondary); font-size: 0.85rem; }

.main-grid {
    display: grid;
    grid-template-columns: 1fr 1.5fr;
    gap: 16px;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

.panel {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 16px;
    overflow: hidden;
}

h2 {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 2px;
    color: var(--text-secondary);
    border-bottom: 1px solid var(--border);
    padding-bottom: 10px;
    flex-shrink: 0;
}

/* Mode Cards */
.mode-cards {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    flex-shrink: 0;
}

.mode-card {
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 14px 10px;
    text-align: center;
    cursor: pointer;
    transition: all 0.2s;
}

.mode-card:hover, .mode-card:active {
    border-color: var(--accent);
    background: var(--accent-wash);
}

/* Which protocol is running. On the study there is only one card, so without a
   selected state there is nothing on screen to show it was ever pressed. */
.mode-card.active {
    border-color: var(--accent);
    background: var(--accent-wash);
    box-shadow: 0 0 8px var(--accent-shadow);
}

/* A single full-width card reads as a section header rather than a control, so
   it has to say outright that it is one. Generated content cannot carry a
   data-i18n attribute, so app.js pushes both labels in as custom properties;
   the fallbacks here are what shows if that has not run yet. */
.mode-card-wide::after {
    content: var(--cta-label, 'select to begin');
    display: block;
    margin-top: 10px;
    font-size: 0.62rem;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--accent);
}
.mode-card-wide.active::after {
    content: var(--running-label, 'running');
    color: var(--success);
}

.mode-card h3 { font-size: 0.9rem; margin-bottom: 6px; color: var(--text-primary); }
.mode-card p { font-size: 0.7rem; color: var(--text-secondary); line-height: 1.3; }

/* Each persona brings its own protocols. Filtered in CSS off the root
   attribute, so switching costs no re-render and there is no flash of the
   wrong set -- index.html ships with the attribute already on. */
:root[data-persona="control"] .mode-card[data-for="study"],
:root[data-persona="study"]   .mode-card[data-for="control"] { display: none; }

/* The study is a single protocol, so its card takes the whole row instead of
   sitting in a three-column grid with two gaps where nothing is. */
:root[data-persona="study"] .mode-cards { grid-template-columns: 1fr; }
.mode-card-wide { text-align: left; padding: 16px 18px; }

/* Her standing release decision reads as the important value on the panel,
   because in the study it is the only one she actually chooses. */
#metric-release-value.permitted { color: var(--success); }
#metric-release-value.withheld  { color: var(--text-secondary); }
#metric-release-value.taken     { color: var(--accent); }

/* Feedback Buttons (Desktop) */
.feedback-grid {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.btn-feedback {
    padding: 18px;
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: bold;
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text-primary);
    cursor: pointer;
    text-transform: uppercase;
    letter-spacing: 1px;
    transition: all 0.1s;
    -webkit-tap-highlight-color: transparent; /* Remove mobile tap highlight */
}

/* Level colours live here rather than inline, so a strict script/style CSP can
   stay strict. Inline style attributes are blocked by style-src 'self'. */
.btn-feedback[data-level="0"] { background: var(--bg-tertiary); }
.btn-feedback[data-level="1"] { background: var(--level-1); }
.btn-feedback[data-level="2"] { background: var(--level-2); }
.btn-feedback[data-level="3"] { background: var(--level-3); }
.btn-feedback[data-level="4"] { background: var(--bg-secondary); }

.btn-feedback:active {
    transform: scale(0.97);
    filter: brightness(1.4);
}

/* Without a protocol these do nothing at all, so they must not look ready.
   Disabled also swallows the click, rather than letting it reach a handler that
   silently returns. */
.btn-feedback:disabled {
    opacity: 0.35;
    filter: saturate(0.25);
    cursor: not-allowed;
}
.btn-feedback:disabled:active { transform: none; filter: saturate(0.25); }

.feedback-hint {
    font-size: 0.68rem;
    letter-spacing: 1px;
    text-transform: lowercase;
    color: var(--accent);
    margin: -4px 0 10px;
}

/* Manual Section */
.btn-stop {
    margin-top: auto;   /* pin to the foot of the controls panel */
    width: 100%;
    padding: 12px;
    background: var(--danger);
    color: var(--on-accent);
    border: none;
    border-radius: 8px;
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: bold;
    cursor: pointer;
    letter-spacing: 1px;
}

/* Log Window */
.log-window {
    flex: 1;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 14px;
    overflow-y: auto;
    font-size: 0.8rem;
    line-height: 1.5;
}

.log-entry {
    margin-bottom: 8px;
    color: var(--text-secondary);
    padding-left: 10px;
    border-left: 2px solid var(--border);
}

.log-entry.active {
    color: var(--accent);
    border-left-color: var(--accent);
    text-shadow: 0 0 6px var(--accent-glow);
}

/* System lines are terse machine facts -- they should recede. */
.log-entry.log-system {
    color: var(--text-secondary);
    border-left-color: var(--border);
}

/* ARIA's voice. A different register from the log around it. */
.log-entry.log-aria {
    color: var(--accent);
    border-left-color: var(--accent);
    text-shadow: 0 0 6px var(--accent-glow);
    font-style: italic;
    padding-top: 2px;
    padding-bottom: 2px;
    margin-bottom: 12px;
}

/* Hold countdown -- present only while ARIA is keeping the device still. */
.hold-banner {
    flex-shrink: 0;
    background: var(--danger-wash);
    border: 1px solid var(--danger);
    border-radius: 8px;
    padding: 8px 12px;
}

.hold-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 6px;
}

.hold-label {
    font-size: 0.65rem;
    letter-spacing: 2px;
    color: var(--danger);
    font-weight: bold;
}

.hold-clock {
    font-size: 1.1rem;
    font-weight: bold;
    color: var(--danger);
    font-variant-numeric: tabular-nums;   /* stop the digits jittering */
}

.hold-track {
    height: 3px;
    background: var(--bg-tertiary);
    border-radius: 2px;
    overflow: hidden;
}

.hold-fill {
    height: 100%;
    background: var(--danger);
    width: 100%;
    transition: width 0.1s linear;
}

/*
 * A settle interval in the trial. Same clock, different meaning: nothing was
 * broken, she is simply making them wait, so it wears the accent rather than
 * the danger colour.
 */
.hold-banner.settling {
    background: var(--accent-wash);
    border-color: var(--accent);
}

.hold-banner.settling .hold-label,
.hold-banner.settling .hold-clock { color: var(--accent); }
.hold-banner.settling .hold-fill { background: var(--accent); }

.metric-value.danger { color: var(--danger); }

/* Awaiting narration from a local model, which can take a few seconds. */
.log-entry.log-aria.pending {
    font-style: normal;
    letter-spacing: 4px;
    animation: aria-thinking 1.4s ease-in-out infinite;
}

@keyframes aria-thinking {
    0%, 100% { opacity: 0.25; }
    50%      { opacity: 0.7; }
}

@media (prefers-reduced-motion: reduce) {
    .log-entry.log-aria.pending { animation: none; opacity: 0.45; }
}

/* Metrics */
.metrics {
    display: flex;
    justify-content: space-between;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border);
    flex-shrink: 0;
}

.metric { display: flex; flex-direction: column; gap: 2px; }
.metric-label { font-size: 0.65rem; color: var(--text-secondary); text-transform: uppercase; }
.metric-value { font-size: 1.2rem; font-weight: bold; color: var(--accent); }

/* Device Status Bar */
.device-status {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.85rem;
    color: var(--text-secondary);
    padding-bottom: 16px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}

.device-status .status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--danger);
    flex-shrink: 0;
}

/* Everything on screen is stale once the server stops answering. */
body.server-offline .main-grid {
    opacity: 0.45;
    filter: grayscale(0.6);
    transition: opacity 0.3s, filter 0.3s;
}

/* The status bar holds two unrelated things: what hardware is attached, and
   which ARIA is running it. Grouping them keeps the separator logic honest --
   the '.' chain belongs to the device chain alone. */
.status-group {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    row-gap: 8px;
    min-width: 0;
}

/* The rule only earns its place when SYSTEM actually sits beside the device
   chain; on a wrapped line it reads as an indent. app.js measures and sets
   .divided, the same way it does for the separators. */
.status-group-system.divided {
    padding-left: 14px;
    border-left: 1px solid var(--border);
}

.picker {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

/* Reads as one continuous status line -- "domi 2 · vibrate · device … · anatomy …".
   Only applied when the picker actually sits on the same line as what precedes
   it; at the start of a wrapped line the same glyph reads as a stray bullet.
   Whether it wraps is not knowable in CSS, so app.js sets .inline. */
.picker.inline::before {
    content: '·';
    color: var(--text-secondary);
    margin-right: 8px;
}

.picker-label {
    font-size: 0.68rem;
    font-weight: bold;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--text-primary);
    white-space: nowrap;
}

/* While the answer is still "unspecified" this is an open question, so it should
   read as one rather than blending into the status bar. */
#anatomy-select.unset {
    border-color: var(--accent);
    color: var(--accent);
    box-shadow: 0 0 8px var(--accent-shadow);
}

#anatomy-picker.unset .picker-label { color: var(--accent); }

/* A native select brings the OS widget with it -- a grey bevel and a system
   font -- which is the one thing on screen that does not look like the rest.
   Stripped back to the same box every other control uses. */
#toy-select, #anatomy-select, #persona-select, #lang-select {
    appearance: none;
    -webkit-appearance: none;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 4px 22px 4px 8px;      /* room for the caret drawn below */
    font-family: inherit;
    font-size: 0.75rem;
    font-weight: bold;
    letter-spacing: 1px;
    text-transform: uppercase;
    max-width: 40vw;
    cursor: pointer;
}

#toy-select:hover, #anatomy-select:hover, #persona-select:hover,
#lang-select:hover,
#toy-select:focus, #anatomy-select:focus, #persona-select:focus,
#lang-select:focus {
    outline: none;
    border-color: var(--accent);
}

/* Drawn as a character rather than a background image so it takes the palette
   with it -- a data: URI arrow would need one copy per persona. It is the last
   flex item in .picker, pulled back over the padding reserved above. */
.picker::after {
    content: '\25BE';
    margin-left: -16px;
    font-size: 0.7rem;
    color: var(--text-secondary);
    pointer-events: none;           /* the click still belongs to the select */
}

/* Both pickers plus the toy name will not fit one line on a phone. */
.device-status { flex-wrap: wrap; row-gap: 8px; }

.device-status .status-dot.connected {
    background: var(--success);
    box-shadow: 0 0 8px var(--success-glow);
}

/* The plea. Deliberately unlike the feedback row: it is not a level, it does
   not command anything, and it should not read as one of the graded buttons. */
.btn-beg {
    width: 100%;
    margin-bottom: 10px;
    padding: 10px;
    background: none;
    border: 1px dashed var(--border);
    border-radius: 8px;
    font-family: inherit;
    font-size: 0.75rem;
    font-weight: bold;
    letter-spacing: 2px;
    text-transform: uppercase;
    color: var(--text-secondary);
    cursor: pointer;
}
.btn-beg:hover { border-color: var(--accent); color: var(--accent); }
.btn-beg:active { transform: scale(0.99); }

/* Hidden mobile stop button (Desktop) */
.btn-stop-mobile {
    display: none;
}

/* =========================================================
   MOBILE RESPONSIVENESS (Crucial for one-handed use)
   ========================================================= */

@media (max-width: 768px) {
    /* The fixed bottom bar is a stop button stacked on the feedback row. Its height
       is derived from these so one edit keeps the bar, the offsets, and the space
       reserved for it in the scroll container all consistent. */
    :root {
        --fb-btn-h: 60px;   /* .btn-feedback */
        --fb-pad:   10px;   /* .feedback-grid padding */
        --stop-h:   48px;   /* .btn-stop-mobile */
        /* Plain lengths only -- this is used to reserve scroll space, and an
           env() nested in a custom property is not reliably substituted. */
        --bottom-bar: calc(var(--fb-btn-h) + (var(--fb-pad) * 2) + var(--stop-h));
    }

    .app-container {
        padding: 12px;
        gap: 12px;
    }

    .header {
        padding-bottom: 12px;
    }

    .logo {
        font-size: 1rem;
        gap: 8px;
    }

    .version { display: none; } 
    .device-status { padding-bottom: 12px; font-size: 0.8rem; }

    .main-grid {
        display: flex;
        flex-direction: column;
        /* Nothing on this screen scrolls except the log. The protocol cards and
           the metrics must stay put; the log window absorbs whatever is left. */
        overflow: hidden;
        /* Room for the fixed bar belongs on the element that scrolls, not inside
           the log panel -- putting it there is what collapsed the log window. */
        padding-bottom: calc(var(--bottom-bar) + env(safe-area-inset-bottom, 0px));
    }

    /* The controls panel keeps its natural height. Without this it shrinks against
       the log's min-height and, because .panel is overflow:hidden, the mode cards
       get sliced in half on shorter screens. */
    .main-grid > .panel:not(.log-panel) {
        flex: 0 0 auto;
    }

    /* On a phone the log is the only thing you actually read: the mode cards are
       used once and nothing else competes. Give it the screen, and strip the
       panel chrome that was eating ~80px of it. */
    .panel.log-panel {
        flex: 1 1 auto;
        min-height: 0;      /* must be free to shrink, or it pushes metrics out */
        padding: 12px;
    }

    .log-panel h2 { display: none; }   /* the log is self-evidently the log */

    .log-window {
        font-size: 0.9rem;
        min-height: 0;
    }

    /* Compact metrics: one tight row instead of two stacked label/value pairs. */
    .metrics { margin-top: 8px; padding-top: 8px; flex-wrap: wrap; gap: 4px 14px; }
    .metric { flex-direction: row; align-items: baseline; gap: 6px; }
    .metric-value { font-size: 0.95rem; }

    .log-entry { margin-bottom: 6px; }
    .log-entry.log-aria { margin-bottom: 8px; }

    /* Its .feedback-grid is fixed to the bottom bar, so this heading would sit
       alone above empty space. */
    .feedback-heading { display: none; }


    .panel {
        padding: 12px;
        gap: 12px;
    }

    .mode-cards {
        gap: 8px;
    }

    .mode-card {
        padding: 12px 6px;
    }
    
    .mode-card h3 { font-size: 0.85rem; }
    .mode-card p { display: none; } 

    /* The fixed bar carries SYSTEM SHUTDOWN here; the desktop stop would be a
       second button doing the same thing. */
    .btn-stop {
        display: none;
    }

    /* SHOW the mobile stop button */
    .btn-stop-mobile {
        display: block;
        width: 100%;
        padding: 14px;
        margin-bottom: 10px;
        background: var(--danger);
        color: var(--on-accent);
        border: none;
        border-radius: 12px;
        font-family: inherit;
        font-size: 1rem;
        font-weight: bold;
        cursor: pointer;
        letter-spacing: 1px;
        -webkit-tap-highlight-color: transparent;
    }

    /*
     * THE STICKY BOTTOM BAR (Contains Stop + Feedback Buttons)
     *
     * One fixed wrapper, stacked by normal flow. Positioning the stop button and
     * the feedback row separately meant the gap between them depended on a calc
     * resolving; if it didn't, `bottom` fell back to auto and the button floated
     * over the controls. Flow can't fail that way.
     */
    .control-bar {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 100;
        background: var(--bg-secondary);
        border-top: 2px solid var(--border);
        /* Clear of the iPhone home indicator. */
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }

    .btn-stop-mobile {
        border-bottom: 1px solid var(--border);
        border-radius: 0;
        height: var(--stop-h);
        padding: 0;
        margin-bottom: 0;
    }

    .feedback-grid {
        padding: var(--fb-pad);
        display: grid;
        grid-template-columns: repeat(5, 1fr);
        gap: 6px;
    }

    .btn-feedback {
        padding: 0;
        height: var(--fb-btn-h);
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 0.65rem; 
        border-radius: 0;
        text-align: center;
        line-height: 1.1;
    }

    .header {
        z-index: 101;
        background: var(--bg-primary);
        position: relative;
    }
    
    .device-status {
        z-index: 101;
        background: var(--bg-primary);
        position: relative;
    }
}

/* Extreme mobile adjustments for very small screens (e.g., iPhone SE) */
@media (max-width: 380px) {
    /* Only the button height changes; the bar height and the space reserved for
       it recompute from this. The old hardcoded 80px under-reserved and let the
       last log entry hide behind the bar. */
    :root { --fb-btn-h: 50px; }

    /* Nothing scrolls here, so every pixel of chrome comes straight out of the
       log window. Tighten the frame rather than let it collapse. */
    .app-container { padding: 8px; gap: 8px; }
    .header { padding-bottom: 8px; }
    .device-status { padding-bottom: 8px; font-size: 0.75rem; }
    .panel { padding: 10px; gap: 10px; }
    .panel.log-panel { padding: 10px; }
    .mode-card { padding: 9px 4px; }
    .mode-card h3 { font-size: 0.8rem; margin-bottom: 0; }
    .hold-banner { padding: 6px 10px; }
    .hold-row { margin-bottom: 4px; }
    .metrics { margin-top: 6px; padding-top: 6px; }

    .btn-feedback {
        height: var(--fb-btn-h);
        font-size: 0.6rem;
    }
}

/* =========================================================
   ONBOARDING GATES (invite, then device)
   ========================================================= */

.gate {
    position: fixed;
    inset: 0;
    display: flex;
    /* Not align-items: center. A flex item taller than its centring container
       overflows equally in both directions, and the half above the scroll
       origin cannot be reached -- the top of a long card is simply gone.
       flex-start plus margin:auto on the card centres it when it fits and
       scrolls cleanly when it does not. */
    align-items: flex-start;
    justify-content: center;
    padding: 20px;
    overflow-y: auto;
    background: var(--bg-primary);
    z-index: 200;
}

.gate-card {
    position: relative;
    margin: auto;
    width: 100%;
    max-width: 420px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 28px 24px;
}

.gate-card-wide { max-width: 560px; }

/* The gates come before the app shell and its System row, so they carry their
   own switch. Top-right of the card, quiet enough not to compete with the
   title, present enough to be found without being looked for. */
.lang-switch {
    position: absolute;
    top: 14px;
    right: 14px;
    display: flex;
    gap: 2px;
}

.lang-btn {
    background: none;
    border: 1px solid transparent;
    border-radius: 4px;
    padding: 2px 7px;
    font-family: inherit;
    font-size: 0.62rem;
    letter-spacing: 1px;
    color: var(--text-secondary);
    cursor: pointer;
    opacity: 0.6;
}

.lang-btn:hover { opacity: 1; }

.lang-btn.active {
    border-color: var(--border);
    color: var(--accent);
    opacity: 1;
}

.gate-title {
    font-size: 1.1rem;
    letter-spacing: 3px;
    margin-bottom: 10px;
    color: var(--text-primary);
}

.gate-lead {
    font-size: 0.8rem;
    line-height: 1.6;
    color: var(--text-secondary);
    margin-bottom: 20px;
    text-transform: lowercase;
}

.guide {
    margin: 0 0 22px 18px;
    padding: 0;
    font-size: 0.8rem;
    line-height: 1.7;
    color: var(--text-secondary);
    text-transform: lowercase;
}

.guide li { margin-bottom: 10px; padding-left: 4px; }
.guide b { color: var(--text-primary); }
.guide code {
    color: var(--accent);
    background: var(--bg-tertiary);
    padding: 1px 5px;
    border-radius: 4px;
    font-size: 0.75rem;
    /* These are short fragments to recognise in another app, so breaking one
       across two lines costs more than the wrap it saves. */
    white-space: nowrap;
    /* The all-lowercase house rule is for prose. These are literals the user has
       to match against another app's screen, so they keep their own casing. */
    text-transform: none;
}

/* The one failure the guide cannot fix, called out after the steps rather than
   as a sixth one -- it is a condition to check, not something to do. */
.guide-note {
    margin: 0 0 14px;
    font-size: 0.75rem;
    line-height: 1.6;
    color: var(--text-secondary);
    text-transform: lowercase;
    border-left: 2px solid var(--border);
    padding-left: 12px;
}

/* Close the gap the list leaves, without collapsing the space between notes. */
.guide + .guide-note { margin-top: -12px; }
.guide-note:last-of-type { margin-bottom: 20px; }
.guide-note b { color: var(--text-primary); }

.gate-form { display: flex; gap: 8px; }
.gate-form-stack { flex-direction: column; margin-top: 12px; }

.gate-form input {
    flex: 1;
    min-width: 0;
    background: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 12px;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 0.85rem;
}

.gate-form input:focus { outline: none; border-color: var(--accent); }

.gate-btn {
    background: var(--accent);
    color: var(--on-accent);
    border: none;
    border-radius: 8px;
    padding: 12px 18px;
    font-family: inherit;
    font-size: 0.8rem;
    font-weight: bold;
    letter-spacing: 1px;
    cursor: pointer;
    flex-shrink: 0;
}

.gate-btn:active { filter: brightness(1.2); }

.gate-note {
    margin-top: 14px;
    font-size: 0.78rem;
    line-height: 1.5;
    text-transform: lowercase;
}

.gate-note.good { color: var(--success); }
.gate-note.warn { color: var(--accent); }
.gate-note.bad  { color: var(--danger); }

.gate-check {
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}

.gate-check h2 { border: none; padding: 0; margin-bottom: 8px; }
.gate-check input[type="range"] {
    width: 100%;
    accent-color: var(--danger);
    margin-bottom: 12px;
}

.gate-btn-quiet { background: var(--bg-tertiary); color: var(--text-primary); }

.gate-reset { margin-top: 18px; }

.link-btn {
    background: none;
    border: none;
    padding: 0;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 0.7rem;
    text-decoration: underline;
    cursor: pointer;
    text-transform: lowercase;
}

.link-btn:hover { color: var(--accent); }

.session-controls {
    display: inline-flex;
    gap: 12px;
    margin-left: auto;
    flex-shrink: 0;
}

.gate-details { margin-top: 22px; border-top: 1px solid var(--border); padding-top: 16px; }

.gate-details summary {
    cursor: pointer;
    font-size: 0.68rem;
    letter-spacing: 1.5px;
    color: var(--text-secondary);
}

@media (max-width: 480px) {
    .gate { padding: 12px; align-items: flex-start; }
    .gate-card { padding: 20px 16px; }
    .gate-form { flex-direction: column; }
}
