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

:root {
    --bg: #07060a;
    --text: #ddd9ec;
    /* Secondary text. The old value (#48465a) sat ~1.5:1 against the background and carried the
       log, the status line, file roles, check details and every hint — i.e. most of the words on
       the page. Raised to something actually readable; --text-faint keeps a step below it for the
       genuinely incidental. */
    --text-dim: #938fa9;
    --text-faint: #6b6782;
    --accent: #9db3dd;
    --good: #6cc182;
    --bad: #e0737f;
    --line: rgba(147, 143, 169, 0.22);
}

html, body {
    /* Without this the UA paints its LIGHT scrollbars and form controls regardless of what the
       page draws — which is why the file list kept a white scrollbar even with both the standard
       and -webkit- properties set. This is the switch that actually matters. */
    color-scheme: dark;
    height: 100%;
    background: var(--bg);
    color: var(--text);
    font-family: 'SF Mono', 'Menlo', 'Consolas', monospace;
    font-size: 12px;
    letter-spacing: 0.5px;
    overflow: hidden;
}

canvas, img { image-rendering: pixelated; max-width: 100%; }

/* Scrollbars. The default light-on-dark chrome scrollbar is the brightest thing on the page;
   these are the same muted line colour as every other border. Firefox gets the standard
   properties, WebKit/Blink the pseudo-elements — both are needed, neither alone covers it. */
/* Solid colours, not alpha: a translucent thumb picks up whatever is behind it and reads lighter
   than the page. Chrome 121+ honours `scrollbar-color` and then IGNORES the ::-webkit- rules, so
   both spellings have to describe the same thing. */
* { scrollbar-width: thin; scrollbar-color: #2b2836 transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
    background: #2b2836;
    border-radius: 5px;
    /* Border in the page colour + padding-box clipping insets the thumb, so it reads as a pill on
       the background rather than a bar butted against the content. */
    border: 2px solid var(--bg);
    background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover { background: #423e52; background-clip: padding-box; }
*::-webkit-scrollbar-corner { background: transparent; }
.filelist::-webkit-scrollbar-thumb { background: #2b2836; background-clip: padding-box; }
.filelist { scrollbar-color: #2b2836 transparent; }

/* ---- split pane --------------------------------------------------------
   Right column tops out at 800px = the emulator's 400x240 canvas at 2x, so
   dropping it in later needs no layout change. */
#app {
    display: grid;
    grid-template-columns: minmax(270px, 375px) minmax(480px, 1fr);
    gap: 1px;
    background: var(--line);
    height: 100%;
}

.pane {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-width: 0;
    min-height: 0;
    padding: 16px;
    background: var(--bg);
}

/* ---- controls ---------------------------------------------------------- */

.btn {
    border: none;
    background: none;
    font: inherit;
    letter-spacing: 1px;
    color: var(--text);
    cursor: pointer;
    opacity: 0.82;
    display: inline-flex;
    align-items: center;
    transition: opacity 0.1s;
    -webkit-tap-highlight-color: transparent;
}
.btn:hover { opacity: 1; }
.btn:active { transform: scale(0.96); }
.btn:disabled { opacity: 0.32; cursor: default; transform: none; }
.btn-primary { color: var(--accent); }
.btn:focus-visible, #drop:focus-visible, .log:focus-visible {
    outline: 1px solid var(--accent);
    outline-offset: 2px;
}

.dot { color: var(--text-faint); padding: 0 6px; }

/* ---- drop zone --------------------------------------------------------- */

#drop {
    /* Square reads better than a band, and the pane is narrow enough that it stays a sensible
       height. flex:none so it keeps the aspect instead of being stretched by the column. */
    flex: none;
    width: 100%;
    aspect-ratio: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    border: 1px solid var(--line);
    cursor: pointer;
    text-align: center;
    transition: background 0.15s, border-color 0.15s;
}
#drop:hover { border-color: rgba(120, 136, 170, 0.4); }
#drop.over {
    border-color: var(--accent);
    background: rgba(120, 136, 170, 0.06);
}

.drop-title { font-size: 14px; color: var(--text); letter-spacing: 1px; }
.drop-sub { font-size: 10px; color: var(--text-dim); }
.drop-pick { font-size: 11px; margin-top: 4px; }
.drop-hint {
    font-size: 10px;
    color: var(--text-faint);
    margin-top: 8px;
    padding: 0 12px;
    line-height: 1.6;
}

/* ---- file list --------------------------------------------------------- */

.filelist {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    font-size: 11px;
    line-height: 1.8;
}

.frow {
    display: flex;
    gap: 8px;
    align-items: baseline;
    white-space: nowrap;
}
.frow .fpath { overflow: hidden; text-overflow: ellipsis; }
.frow .frole { color: var(--text-faint); font-size: 10px; margin-left: auto; padding-left: 12px; }
.frow.skip { color: var(--text-faint); }
.frow.reject { color: var(--bad); }
.frow.source .fpath { color: var(--text); }
.frow.header .fpath, .frow.asset .fpath { color: var(--text); opacity: 0.9; }
.fnote { color: var(--bad); font-size: 10px; line-height: 1.8; }

.pane-foot {
    display: flex;
    align-items: baseline;
    font-size: 11px;
    min-height: 18px;
}
.status { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.status.bad { color: var(--bad); }
.status.good { color: var(--good); }

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

/* Both panes open with a band of the same height — brand on the left, artifact + actions on the
   right — so the two columns start on one line. */
.brand, .out-head { min-height: 40px; flex: none; }

.brand { display: flex; align-items: center; gap: 9px; }
.brand-mark { display: block; width: 20px; height: 20px; }
.brand-name {
    /* The wordmark is the one thing on the page that is not UI text, so it uses the site's sans
       rather than the builder's monospace. Matches bedtime/web (label.text "Bedtime.", 700). */
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
    font-size: 22px;
    font-weight: 700;
    letter-spacing: 0;
    color: var(--text);
}

.out-head {
    display: flex;
    align-items: center;
    font-size: 13px;
}
.out-name {
    color: var(--text);
    letter-spacing: 1px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 50%;
}
.out-size { color: var(--text-dim); font-size: 11px; }

/* run and download sit together as one action group at the right, rather than run floating next
   to the filename and download pinned to the far edge. */
.out-actions { margin-left: auto; display: flex; align-items: center; gap: 16px; }
/* Same 13px as .out-name, so the artifact on the left and the actions on the right read as one
   line rather than the actions looking like a footnote. */
.out-actions .btn { font-size: 13px; gap: 7px; }
.btn .ico { width: 13px; height: 13px; flex: none; }

.bar { height: 2px; background: var(--line); }
.bar > i {
    display: block;
    height: 100%;
    width: 0;
    background: var(--accent);
    transition: width 0.2s linear;
}

/* ---- checks + sections ------------------------------------------------- */

.report {
    flex: 0 1 auto;
    min-height: 96px;
    overflow-y: auto;
}

.checks { list-style: none; font-size: 11px; }
.check { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; line-height: 1.8; }
.check .mark { width: 10px; flex: none; }
.check .title { flex: none; }
.check .detail {
    color: var(--text-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.check.pass .mark { color: var(--good); }
.check.fail .mark, .check.fail .title { color: var(--bad); }
.check.warn .mark, .check.warn .title { color: var(--accent); }
.check.skip { opacity: 0.65; }
.check-rows {
    flex-basis: 100%;
    list-style: none;
    font-size: 10px;
    color: var(--text-dim);
    padding: 0 0 4px 18px;
    line-height: 1.7;
    white-space: pre;
    overflow-x: auto;
}

.sections { margin-top: 10px; overflow-x: auto; }
.sections table { border-collapse: collapse; font-size: 10px; }
.sections td {
    text-align: left;
    padding: 1px 16px 1px 0;
    color: var(--text-dim);
    white-space: nowrap;
}

/* While the emulator is up the device needs room, but the log should still be readable — about ten
   lines — rather than collapsing to a sliver. The device's width cap below is derived from what is
   left after this. */
/* A share of the column rather than a fixed strip, so it stays proportionate on any window. The
   device is fitted to whatever the stage gets after this — see fitDevice() in app.js — so raising
   this shrinks the tape rather than causing an overlap. */
#stage:not([hidden]) ~ .log { flex: 0 0 50%; min-height: 180px; }

/* ---- log --------------------------------------------------------------- */

.log {
    flex: 1 1 auto;
    min-height: 120px;
    overflow: auto;
    border-top: 1px solid var(--line);
    padding-top: 10px;
    font-family: inherit;
    font-size: 10px;
    line-height: 1.6;
    letter-spacing: 0;
    color: var(--text-dim);
    white-space: pre-wrap;
    tab-size: 4;
    -webkit-user-select: text;
    user-select: text;
}

/* ---- narrow ------------------------------------------------------------ */

@media (max-width: 900px) {
    #app {
        grid-template-columns: 1fr;
        grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
        overflow-y: auto;
    }
    #drop { flex: 0 0 120px; }
}

/* The HTML `hidden` attribute is only honoured by a UA rule of the same specificity, so any
   author `display:` silently defeats it — which is exactly what .stage{display:flex} did. */
[hidden] { display: none !important; }

/* ---- emulator stage -----------------------------------------------------
   Shares the right column with #report (only one is visible at a time), so the
   layout never reflows when you switch between them. */
.stage {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 40px;
    flex: 1;
    min-height: 0;
    /* A hard guarantee: however the height estimate below lands, the device can never paint over
       the log. It shrinks instead. */
    overflow: hidden;
}

/* The device drawing, with the emulator canvas composited into its display cutout.
   The percentages below come straight from tape_simple.svg: the #display group is a rounded rect at
   translate(11.4201, 48.7401) measuring 171.48 x 107.76 inside a 203 x 168 viewBox, with a 3.8399
   corner radius. Keeping them as percentages means the overlay tracks the artwork at any width,
   with no JS measurement. Re-derive all of them if the SVG is ever re-exported. */
.device {
    position: relative;
    /* Width is set by fitDevice() in app.js from the stage's MEASURED height. It cannot be done in
       CSS: the overlay is positioned in percentages of this box, so the box has to keep the
       artwork's exact 203:168 aspect, and capping one axis with max-height would break the other.
       Successive guesses at a `100dvh - Npx` budget were all wrong for some window size. */
    width: min(100%, 620px);
    margin: 0 auto;
}

/* The outline sits ABOVE the screen, so the bezel frames the canvas instead of the canvas covering
   the inner half of the stroke. pointer-events:none keeps the canvas focusable through it. */
.device > svg {
    display: block;
    width: 100%;
    height: auto;
    position: relative;
    z-index: 1;
    pointer-events: none;
}

/* Outlines stay opaque white, as drawn. A translucent stroke looks calmer in isolation but the
   artwork has paths that cross and abut, and semi-transparent strokes composite twice wherever they
   do — which reads as bright seams along every overlap. Opacity is the bug, not the colour. */

/* Controls carry fill="#FF6666" in the asset. Hidden until pressed. */
.device svg #controls path { fill: transparent; transition: fill 0.05s linear; }
.device svg #controls path.on { fill: #FF6666; }

.device-screen {
    position: absolute;
    left: 5.6257%;    /* 11.4201 / 203 */
    top: 29.0120%;    /* 48.7401 / 168 */
    width: 84.4729%;  /* 171.48 / 203 */
    height: 64.1429%; /* 107.76 / 168 */
    z-index: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    /* Fills the whole display cutout so no page background shows through around the letterboxed
       canvas. Radius is the artwork's own 3.8399 corner, as a percentage of each axis of this box
       (3.8399/171.48 and 3.8399/107.76) so it stays circular at any scale. */
    /* COL_BG from emu/emu_shell_web.c — the same grey the emulator clears its framebuffer to, so
       the glass around the image is seamless with the image itself. */
    background: #313131;
    border-radius: 2.239% / 3.563%;
}

#screen {
    /* The bezel is slightly squarer than 5:3, so fit to width and let the canvas centre
       vertically rather than stretching the guest's pixels. Inset a little so the glass shows a
       margin around the image instead of running into the bezel. */
    width: 94%;
    height: auto;
    max-width: none;
    aspect-ratio: 400 / 240;
    image-rendering: pixelated; /* 1-bit art must not be smoothed */
    background: #313131;        /* matches COL_BG, so first paint is not a dark flash */
    border: 0;
    outline: none;
}
/* Breathing room around the device once it is actually running, so it sits centred in the pane
   rather than filling it. fitDevice() reads the padding back off the element, so the tape resizes
   to match instead of overflowing. */
.stage.is-live { padding: 40px; }

/* The display's own rounded outline lights while the emulator is LIVE — not while the canvas holds
   keyboard focus. Controls work page-wide regardless of focus, so a focus-driven indicator would
   go dark the moment you clicked the log while the tapp was still very much running. */
.stage.is-live .device svg #display { stroke: var(--accent); }

.stage-foot {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    max-width: 620px;      /* matches .device, so the footer lines up with the artwork */
    justify-content: space-between;
}
.stage-hint { color: var(--text-dim); font-size: 10px; letter-spacing: .5px; }

.btn-run:not(:disabled) { color: var(--good); }
/* One button, two states: play while idle, stop while the emulator holds the pane. */
.btn-run .ico-stop { display: none; }
.btn-run.is-stop .ico-play { display: none; }
.btn-run.is-stop .ico-stop { display: block; }
.btn-run.is-stop:not(:disabled) { color: var(--bad); }
