/* =============================================================================
   PaleOS — a BeOS R5 desktop, as a Ghost theme
   =============================================================================

   Everything here is mixed from three root colours set in Ghost Admin
   (Design > Customise): the panel grey, the active tab yellow and the desktop
   backdrop. BeOS R5's own values are the defaults — panel rgb(216,216,216),
   tab #ffcb00, desktop #336698 — and every bevel, shadow and highlight below is
   derived from them with color-mix(), so changing one setting restyles the whole
   UI the way swapping a BeOS colour scheme did.

   The bevel vocabulary is the thing to understand before editing anything:

     RAISED  (buttons, panels, menus, scroll knobs)
             light on the top/left edges, shadow on the bottom/right
     SUNKEN  (text fields, list views, scroll troughs, the terminal surface)
             shadow on the top/left edges, light on the bottom/right

   Both are drawn with inset box-shadows rather than borders, two rings deep,
   because BeOS controls were two pixels of bevel and borders would eat into the
   box model of every control that has to line up on a 1px grid.

   CONTENTS
     1  Tokens and reset
     2  Typography
     3  Desktop and backdrop
     4  Desktop icons
     5  Deskbar
     6  Menus
     7  Window chrome
     8  Controls
     9  Scrollbars
    10  List and column views
    11  Alert panels
    12  Boot screen
    13  Login panel
    14  App: Terminal
    15  App: NetPale (browser)
    16  App: PaleMail
    17  App: PaleEdit (notes)
    18  Standalone documents and article typography
    19  No-JS index
    20  Small screens, motion, print
    21  PaleBIOS
    22  PaleBIOS Setup
   ========================================================================== */


/* -----------------------------------------------------------------------------
   1  TOKENS AND RESET
   -------------------------------------------------------------------------- */

:root {
    /* Set by default.hbs from the theme settings; repeated here so the
       stylesheet still renders correctly if it is ever loaded on its own. */
    --paleos-panel: #d8d8d8;
    --paleos-tab: #ffcb00;
    --paleos-desktop: #336698;

    /* Panel bevel ramp. Fallbacks first for anything without color-mix. */
    --panel: var(--paleos-panel);
    --panel-lit: #ebebeb;
    --panel-hi: #ffffff;
    --panel-shadow: #8c8c8c;
    --panel-dark: #5f5f5f;
    --panel-darkest: #2b2b2b;

    --tab: var(--paleos-tab);
    --tab-hi: #ffe07a;
    --tab-shadow: #c49c00;
    --tab-idle: #cfcfcf;

    --doc: #ffffff;
    --ink: #000000;
    --ink-soft: #4a4a4a;
    --ink-faint: #7b7b7b;

    --sel: #3b5f99;
    --sel-ink: #ffffff;
    --link: #1a4f8a;
    --danger: #b4231f;
    --ok: #1d7a33;

    --ui-font: "Swis721 BT", "Helvetica Neue", Helvetica, Arial, "DejaVu Sans", "Bitstream Vera Sans", sans-serif;
    --mono-font: "Bitstream Vera Sans Mono", "DejaVu Sans Mono", "Liberation Mono", Menlo, Consolas, "Courier New", monospace;

    --ui-size: 12px;
    --ui-small: 11px;
    --tab-h: 21px;
    --menubar-h: 20px;
    --statusbar-h: 18px;
    --sb-size: 15px;

    --raise: inset 1px 1px 0 var(--panel-hi), inset -1px -1px 0 var(--panel-shadow),
             inset 2px 2px 0 var(--panel-lit), inset -2px -2px 0 var(--panel-dark);
    --raise-1: inset 1px 1px 0 var(--panel-hi), inset -1px -1px 0 var(--panel-dark);
    --sink: inset 1px 1px 0 var(--panel-dark), inset -1px -1px 0 var(--panel-hi),
            inset 2px 2px 0 var(--panel-shadow), inset -2px -2px 0 var(--panel-lit);
    --sink-1: inset 1px 1px 0 var(--panel-dark), inset -1px -1px 0 var(--panel-hi);
}

@supports (color: color-mix(in srgb, white 50%, black)) {
    :root {
        --panel-lit: color-mix(in srgb, var(--paleos-panel) 55%, #ffffff);
        --panel-shadow: color-mix(in srgb, var(--paleos-panel) 62%, #000000);
        --panel-dark: color-mix(in srgb, var(--paleos-panel) 38%, #000000);
        --panel-darkest: color-mix(in srgb, var(--paleos-panel) 16%, #000000);
        --tab-hi: color-mix(in srgb, var(--paleos-tab) 60%, #ffffff);
        --tab-shadow: color-mix(in srgb, var(--paleos-tab) 72%, #000000);
        --tab-idle: color-mix(in srgb, var(--paleos-panel) 95%, #000000);
    }
}

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }

body.paleos-body {
    margin: 0;
    padding: 0;
    font: var(--ui-size)/1.35 var(--ui-font);
    color: var(--ink);
    background: var(--paleos-desktop);
    -webkit-font-smoothing: antialiased;
    overflow: hidden;
}

body.paleos-body.is-document {
    overflow: auto;
}

img { max-width: 100%; height: auto; border: 0; }

button, input, textarea, select {
    font: inherit;
    color: inherit;
}

button { cursor: default; }

a { color: var(--link); }

.sr-only {
    position: absolute !important;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

[hidden] { display: none !important; }


/* -----------------------------------------------------------------------------
   2  TYPOGRAPHY
   -------------------------------------------------------------------------- */

.paleos-label {
    font-size: var(--ui-size);
    color: var(--ink);
    white-space: nowrap;
}

.paleos-divider {
    height: 2px;
    margin: 10px 0;
    box-shadow: var(--sink-1);
    background: var(--panel);
}

.paleos-heading {
    margin: 0 0 6px;
    font-size: var(--ui-size);
    font-weight: 700;
}


/* -----------------------------------------------------------------------------
   3  DESKTOP AND BACKDROP
   -------------------------------------------------------------------------- */

.paleos-desktop,
.login-shell {
    position: fixed;
    inset: 0;
    overflow: hidden;
}

/* A FOLDER IS OVER THE DESKTOP AND CAN BECOME A DISK.
   Drawn as an inset frame rather than a tint, because the desktop's colour is
   the one thing in this system a person chooses for themselves and a wash over
   it reads as something having gone wrong. The frame is inside the edges so it
   is visible over a window as well as over bare desktop, and pointer-events
   stay off it: it is a statement, not a target. */
.paleos-desktop.is-disk-target::after {
    content: "";
    position: absolute;
    inset: 6px;
    pointer-events: none;
    z-index: 96000;
    border: 3px dashed var(--paleos-tab, #f0c020);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.35);
}

.desktop-backdrop {
    position: absolute;
    inset: 0;
    background-color: var(--paleos-desktop);
    /* BeOS desktops were a flat colour with a faint ordered dither on 8-bit
       displays. A 2px checker at very low contrast reads the same way without
       costing an image request. */
    background-image:
        linear-gradient(45deg, rgba(255, 255, 255, 0.025) 25%, transparent 25%, transparent 75%, rgba(255, 255, 255, 0.025) 75%),
        linear-gradient(45deg, rgba(255, 255, 255, 0.025) 25%, transparent 25%, transparent 75%, rgba(255, 255, 255, 0.025) 75%);
    background-size: 4px 4px;
    background-position: 0 0, 2px 2px;
}

.window-layer {
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.window-layer > * { pointer-events: auto; }


/* -----------------------------------------------------------------------------
   4  DESKTOP ICONS
   -------------------------------------------------------------------------- */

.desktop-icons {
    position: absolute;
    top: 12px;
    left: 10px;
    /* The whole width now. This used to stop short of the Deskbar's vertical
       strip in the top-right; nothing is there any more. */
    right: 10px;
    /* And it stops short of the bottom edge instead, where the dock is.
       Without this the icon flow has no height of its own and a full desktop
       puts its last row underneath it. */
    bottom: 44px;
    overflow-y: auto;
    display: flex;
    flex-flow: row wrap;
    align-content: flex-start;
    gap: 8px 0;
}

.desktop-icon {
    display: block;
    width: 84px;
    padding: 2px;
    border: 0;
    background: none;
    text-align: center;
    cursor: default;
}

/* Shrink-wrapped to the 32px image (and centred by the button's text-align) so
   the shortcut ribbon below can be pinned to the icon's own corner rather than
   the button's. */
.desktop-icon-glyph {
    display: inline-block;
    position: relative;
    line-height: 0;
}

/* A desktop application icon is a symlink into /PaleHD/apps, and BeOS marked a
   symlink with a small curved arrow in its lower-left corner. The ribbon is
   embedded rather than linked: a relative path would break anywhere this
   stylesheet is inlined or served from a different directory. */
.desktop-icon.is-shortcut .desktop-icon-glyph::after,
.pf-item.is-shortcut .pf-item-glyph::after {
    content: "";
    position: absolute;
    left: -2px;
    bottom: -1px;
    width: 12px;
    height: 12px;
    background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+PGNpcmNsZSBjeD0iOCIgY3k9IjgiIHI9IjciIGZpbGw9IiNmZGZkZmIiIHN0cm9rZT0iIzNhM2EzYSIgc3Ryb2tlLXdpZHRoPSIxLjQiLz48cGF0aCBkPSJNNSAxMWMwLTMuMiAyLTUgNC42LTUuMSIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMWMxYzFjIiBzdHJva2Utd2lkdGg9IjEuOCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIi8+PHBhdGggZD0iTTguNCAzLjYgMTEuNiA1LjkgOC4zIDh6IiBmaWxsPSIjMWMxYzFjIi8+PC9zdmc+")
        no-repeat center / contain;
    filter: drop-shadow(1px 1px 0 rgba(0, 0, 0, 0.4));
}

/* ...but inside PaleFiles the icons sit on a white list background, where that
   drop shadow reads as dirt. Deliberate override, not a stray duplicate. */
.pf-item.is-shortcut .pf-item-glyph::after { filter: none; }

.desktop-icon-glyph img,
.desktop-icon-glyph svg {
    width: 32px;
    height: 32px;
    /* BeOS icons sat on the desktop with a hard 1px drop shadow. */
    filter: drop-shadow(1px 1px 0 rgba(0, 0, 0, 0.45));
}

.desktop-icon-label {
    display: block;
    width: fit-content;
    margin-inline: auto;
    max-width: 80px;
    margin-top: 3px;
    padding: 0 3px;
    overflow: hidden;
    font-size: var(--ui-small);
    color: #fff;
    text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.6);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.desktop-icon.is-selected .desktop-icon-label {
    background: var(--sel);
    color: var(--sel-ink);
    text-shadow: none;
}

.desktop-icon.is-selected .desktop-icon-glyph img,
.desktop-icon.is-selected .desktop-icon-glyph svg {
    filter: drop-shadow(1px 1px 0 rgba(0, 0, 0, 0.45)) brightness(1.12);
}

.desktop-icon:focus-visible {
    outline: 1px dotted #fff;
    outline-offset: 1px;
}


/* -----------------------------------------------------------------------------
   5  MENUS

   The Deskbar was the first half of this section and is gone; what is left is
   the floating menu panel, which the Deskbar's system menu merely happened to
   be one user of. A right-click, a window's menu bar, the dock's overflow and
   a tray item all draw this.
   -------------------------------------------------------------------------- */

.paleos-menu {
    position: absolute;
    min-width: 168px;
    padding: 2px;
    background: var(--panel);
    box-shadow: var(--raise-1), 2px 2px 0 rgba(0, 0, 0, 0.3);
    border: 1px solid var(--panel-darkest);
    z-index: 95000;
}

.paleos-menu-item {
    display: block;
    width: 100%;
    padding: 3px 18px 3px 10px;
    border: 0;
    background: none;
    font-size: var(--ui-size);
    text-align: left;
    white-space: nowrap;
}

.paleos-menu-item:hover,
.paleos-menu-item:focus {
    background: var(--sel);
    color: var(--sel-ink);
    outline: 0;
}

.paleos-menu-item[disabled] {
    color: var(--ink-faint);
    background: none;
}

.paleos-menu-item .menu-icon {
    width: 16px;
    height: 16px;
    margin-right: 6px;
    vertical-align: -3px;
}

.paleos-menu-item .menu-shortcut {
    float: right;
    margin-left: 18px;
    color: var(--ink-faint);
}

.paleos-menu-item:hover .menu-shortcut { color: var(--sel-ink); }

.paleos-menu-sep {
    height: 2px;
    margin: 3px 1px;
    box-shadow: var(--sink-1);
}

.paleos-menu-label {
    padding: 2px 10px;
    font-size: var(--ui-small);
    font-weight: 700;
    color: var(--ink-soft);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}


/* -----------------------------------------------------------------------------
   7  WINDOW CHROME
   -------------------------------------------------------------------------- */

.paleos-window {
    position: absolute;
    display: flex;
    flex-direction: column;
    min-width: 220px;
    min-height: 120px;
}

/* The tab row is the strip the tab sits in. The tab itself is only as wide as
   its title plus its two boxes — the single most recognisable thing about a
   BeOS window — and the rest of the row is empty so windows behind show
   through. */
.window-tabrow {
    display: flex;
    align-items: flex-end;
    height: var(--tab-h);
    padding-left: 0;
}

.window-tab {
    display: flex;
    align-items: center;
    gap: 5px;
    max-width: calc(100% - 12px);
    height: var(--tab-h);
    padding: 0 7px;
    background: var(--tab-idle);
    border: 1px solid var(--panel-darkest);
    border-bottom: 0;
    box-shadow: inset 1px 1px 0 var(--panel-hi), inset -1px 0 0 var(--panel-shadow);
    cursor: default;
    user-select: none;
}

.paleos-window.is-active .window-tab,
.window-tab.is-active {
    background: var(--tab);
    box-shadow: inset 1px 1px 0 var(--tab-hi), inset -1px 0 0 var(--tab-shadow);
}

.window-title {
    overflow: hidden;
    font-size: var(--ui-size);
    font-weight: 700;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.paleos-window:not(.is-active) .window-title { color: var(--ink); }

/* All three to the right of the title: close, minimize, zoom.

   BeOS put the close box on the LEFT of the tab and the zoom box on the right,
   with the title between them, and this followed that until the three controls
   were grouped. The departure is deliberate: the title reads flush left the way
   a filename does everywhere else in the system, and a hand looking for a
   window control has one place to look rather than two.

   Close stays first of the three, where it was first of the tab, so the one
   that discards work is not somewhere a hand lands by accident on its way to
   zoom. */
.window-close,
.window-minimize,
.window-zoom {
    position: relative;
    flex: none;
    width: 13px;
    height: 13px;
    padding: 0;
    border: 1px solid var(--panel-darkest);
    background: var(--panel);
    box-shadow: var(--raise-1);
    cursor: default;
}

.window-close:active,
.window-minimize:active,
.window-zoom:active { box-shadow: var(--sink-1); }

/* The minimize box's glyph: a single rule along the bottom, which is where the
   window is going. Deliberately not the zoom box's nested squares and not the
   close box's emptiness — three controls 13px wide have to be told apart at a
   glance, so each is a different shape rather than a different size. */
.window-minimize::after {
    content: "";
    position: absolute;
    inset: auto 2px 2px 2px;
    height: 2px;
    background: var(--ink);
}

/* The zoom box's glyph: a small square tucked into a larger one. */
.window-zoom::before,
.window-zoom::after {
    content: "";
    position: absolute;
    border: 1px solid var(--ink);
}

.window-zoom::before { inset: 1px 3px 3px 1px; }
.window-zoom::after  { inset: 4px 1px 1px 4px; background: var(--panel); }

.window-frame {
    position: relative;
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    padding: 3px;
    background: var(--panel);
    border: 1px solid var(--panel-darkest);
    box-shadow: inset 1px 1px 0 var(--panel-hi), inset -1px -1px 0 var(--panel-shadow),
                3px 3px 7px rgba(0, 0, 0, 0.3);
}

.window-menubar {
    display: flex;
    align-items: center;
    gap: 1px;
    height: var(--menubar-h);
    flex: none;
    margin-bottom: 3px;
    box-shadow: inset 0 -1px 0 var(--panel-shadow);
}

.window-menu {
    padding: 2px 8px;
    border: 0;
    background: none;
    font-size: var(--ui-size);
}

.window-menu:hover,
.window-menu[aria-expanded="true"] {
    background: var(--sel);
    color: var(--sel-ink);
}

.window-menu-link {
    padding: 2px 8px;
    font-size: var(--ui-size);
    color: var(--ink);
    text-decoration: none;
}

.window-menu-link:hover { background: var(--sel); color: var(--sel-ink); }

.window-menu-static {
    padding: 2px 8px;
    font-size: var(--ui-small);
    color: var(--ink-soft);
}

.window-menubar-spacer { flex: 1; }

.window-content {
    flex: 1;
    min-height: 0;
    overflow: auto;
    background: var(--doc);
    box-shadow: var(--sink-1);
}

.window-content.is-panel {
    background: var(--panel);
    box-shadow: none;
    /* NO `overflow: visible` HERE ANY MORE. It let a panel whose content
       outgrew its frame paint outside the window: PaleStream's list of what
       this computer sends ran past the resize corner and down the desktop,
       which is the "elements not properly enclosed in windows" complaint. The
       frame is the boundary for every window; a panel that holds too much
       scrolls like the rest. */
    overflow: auto;
}

.window-statusbar {
    display: flex;
    flex: none;
    align-items: center;
    height: var(--statusbar-h);
    margin-top: 3px;
    padding-right: 16px;
    font-size: var(--ui-small);
    color: var(--ink-soft);
}

.status-cell {
    padding: 0 6px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    box-shadow: var(--sink-1);
    background: var(--panel);
    line-height: calc(var(--statusbar-h) - 2px);
    height: 100%;
}

.status-cell + .status-cell { margin-left: 3px; }
.status-grow { flex: 1; }

/* The window count and the clock, in the bottom-right of every PaleFiles
   status bar: what the Deskbar used to carry along its foot. Both are
   flex: none so the growing cell setStatus() writes to gives up the room
   instead — a long filename must not push the clock off the edge of the
   window. */
.status-windows,
.status-clock {
    flex: none;
    font: inherit;
    color: inherit;
    border: 0;
    cursor: default;
}

.status-windows {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.status-windows:active,
.status-clock:active { box-shadow: var(--raise-1); }
.status-windows[disabled] { color: var(--ink-faint, var(--ink-soft)); }

/* Two overlapping window frames, which is what the thing it counts looks
   like. Drawn rather than fetched: this is 12px of line art and an SVG request
   for it would cost more than it draws. */
.status-windows-glyph {
    position: relative;
    flex: none;
    width: 11px;
    height: 10px;
}

.status-windows-glyph::before,
.status-windows-glyph::after {
    content: "";
    position: absolute;
    width: 7px;
    height: 6px;
    border: 1px solid currentColor;
    /* The tab along the top, as a PaleOS window has. */
    border-top-width: 2px;
}

.status-windows-glyph::before { left: 0; top: 0; }

/* The front one, offset down and right, with a sliver of panel behind it so
   the two read as two rather than as a smudge. */
.status-windows-glyph::after {
    right: 0;
    bottom: 0;
    background: var(--panel);
    box-shadow: -1px -1px 0 var(--panel);
}

.status-count { font-variant-numeric: tabular-nums; }

/* Tabular figures, because a clock whose digits change width twitches once a
   minute in the corner of the eye. */
.status-clock { font-variant-numeric: tabular-nums; }

/* Applet buttons, bottom left of the window that owns them. In the statusbar
   rather than the content, so an application needs to leave no room for
   something it does not know it has: a window with no applets looks exactly as
   it did. */
.window-applets {
    display: flex;
    flex: none;
    align-items: center;
    gap: 3px;
    margin-right: 3px;
}

.paleos-button.is-applet {
    height: calc(var(--statusbar-h) - 2px);
    padding: 0 10px;
    font-size: var(--ui-small);
    line-height: 1;
    white-space: nowrap;
}

/* Resize corner, bottom-right, with the diagonal grip BeOS drew into it. */
.window-resize {
    position: absolute;
    right: 1px;
    bottom: 1px;
    width: 15px;
    height: 15px;
    background:
        linear-gradient(135deg, transparent 0 46%, var(--panel-shadow) 46% 54%, transparent 54%),
        linear-gradient(135deg, transparent 0 66%, var(--panel-shadow) 66% 74%, transparent 74%),
        var(--panel);
    box-shadow: var(--raise-1);
    cursor: nwse-resize;
}

.paleos-window.is-dragging,
.paleos-window.is-resizing { will-change: left, top, width, height; }

.paleos-window.is-zoomed { border-radius: 0; }


/* -----------------------------------------------------------------------------
   8  CONTROLS
   -------------------------------------------------------------------------- */

.paleos-button {
    min-width: 72px;
    padding: 3px 14px;
    background: var(--panel);
    border: 1px solid var(--panel-darkest);
    border-radius: 4px;
    box-shadow: var(--raise);
    font-size: var(--ui-size);
    text-align: center;
    text-decoration: none;
    color: var(--ink);
    display: inline-block;
}

.paleos-button:active,
.paleos-button.is-pressed { box-shadow: var(--sink); }

.paleos-button[disabled] {
    color: var(--ink-faint);
    box-shadow: var(--raise-1);
}

/* BeOS ringed the default button with a second rounded outline. */
.paleos-button.is-default {
    box-shadow: var(--raise), 0 0 0 2px var(--panel), 0 0 0 3px var(--panel-dark);
    font-weight: 700;
}

.paleos-button.is-default:active {
    box-shadow: var(--sink), 0 0 0 2px var(--panel), 0 0 0 3px var(--panel-dark);
}

.paleos-button-row {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: flex-end;
    margin-top: 14px;
}

.paleos-button-row.is-left { justify-content: flex-start; }

/* Small square toolbar buttons, as in the browser's back/forward row. */
.paleos-toolbutton {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    min-width: 26px;
    height: 24px;
    padding: 0 7px;
    background: var(--panel);
    border: 1px solid var(--panel-dark);
    border-radius: 3px;
    box-shadow: var(--raise-1);
    font-size: var(--ui-small);
}

.paleos-toolbutton:active { box-shadow: var(--sink-1); }

.paleos-toolbutton[disabled] { color: var(--ink-faint); }

.paleos-toolbutton img,
.paleos-toolbutton svg { width: 14px; height: 14px; }

.paleos-input,
.paleos-textarea {
    width: 100%;
    padding: 3px 5px;
    background: var(--doc);
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
    border-radius: 0;
    font-size: var(--ui-size);
}

.paleos-input:focus,
.paleos-textarea:focus {
    outline: 0;
    box-shadow: var(--sink-1), 0 0 0 2px var(--sel);
}

.paleos-textarea {
    resize: none;
    line-height: 1.45;
}

.paleos-field-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}

.paleos-field-row .paleos-label {
    width: 72px;
    flex: none;
    text-align: right;
}

.paleos-field-row.is-stacked {
    flex-direction: column;
    align-items: stretch;
    gap: 3px;
}

.paleos-field-row.is-stacked .paleos-label { width: auto; text-align: left; }

/* Checkbox and radio, drawn rather than native so they carry the same bevels. */
.paleos-check,
.paleos-radio {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: var(--ui-size);
}

.paleos-check input,
.paleos-radio input {
    appearance: none;
    width: 13px;
    height: 13px;
    margin: 0;
    flex: none;
    background: var(--doc);
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
    position: relative;
}

.paleos-radio input { border-radius: 50%; }

.paleos-check input:checked::after {
    content: "";
    position: absolute;
    inset: 2px;
    background: var(--ink);
}

.paleos-radio input:checked::after {
    content: "";
    position: absolute;
    inset: 3px;
    border-radius: 50%;
    background: var(--ink);
}

.paleos-select {
    padding: 2px 6px;
    background: var(--panel);
    border: 1px solid var(--panel-dark);
    border-radius: 3px;
    box-shadow: var(--raise-1);
    font-size: var(--ui-size);
}

.paleos-progress {
    height: 14px;
    background: var(--panel);
    box-shadow: var(--sink-1);
    overflow: hidden;
}

.paleos-progress-fill {
    height: 100%;
    width: 0;
    background: var(--sel);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45);
    transition: width 0.18s linear;
}


/* -----------------------------------------------------------------------------
   9  SCROLLBARS

   BeOS scrollbars had an arrow at each end and a knob carrying three grip
   lines. WebKit and Blink can be styled closely enough to read as the real
   thing; Firefox gets the colours through scrollbar-color and keeps its own
   geometry, which is the one deliberate compromise in this stylesheet.
   -------------------------------------------------------------------------- */

.paleos-body * {
    scrollbar-color: var(--panel) var(--panel-lit);
    scrollbar-width: thin;
}

.paleos-body ::-webkit-scrollbar {
    width: var(--sb-size);
    height: var(--sb-size);
}

.paleos-body ::-webkit-scrollbar-track {
    background: var(--panel-lit);
    box-shadow: var(--sink-1);
}

.paleos-body ::-webkit-scrollbar-thumb {
    background:
        radial-gradient(circle at 50% calc(50% - 4px), var(--panel-dark) 0 1px, transparent 1.3px),
        radial-gradient(circle at 50% 50%, var(--panel-dark) 0 1px, transparent 1.3px),
        radial-gradient(circle at 50% calc(50% + 4px), var(--panel-dark) 0 1px, transparent 1.3px),
        var(--panel);
    border: 1px solid var(--panel-dark);
    box-shadow: var(--raise-1);
}

.paleos-body ::-webkit-scrollbar-thumb:horizontal {
    background:
        radial-gradient(circle at calc(50% - 4px) 50%, var(--panel-dark) 0 1px, transparent 1.3px),
        radial-gradient(circle at 50% 50%, var(--panel-dark) 0 1px, transparent 1.3px),
        radial-gradient(circle at calc(50% + 4px) 50%, var(--panel-dark) 0 1px, transparent 1.3px),
        var(--panel);
}

.paleos-body ::-webkit-scrollbar-button:single-button {
    display: block;
    height: var(--sb-size);
    width: var(--sb-size);
    background: var(--panel);
    border: 1px solid var(--panel-dark);
    box-shadow: var(--raise-1);
    background-repeat: no-repeat;
    background-position: center;
    background-size: 7px 7px;
}

.paleos-body ::-webkit-scrollbar-button:single-button:vertical:decrement {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path d='M4 1 7 6H1z' fill='%23222'/></svg>");
}

.paleos-body ::-webkit-scrollbar-button:single-button:vertical:increment {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path d='M4 7 1 2h6z' fill='%23222'/></svg>");
}

.paleos-body ::-webkit-scrollbar-button:single-button:horizontal:decrement {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path d='M1 4 6 1v6z' fill='%23222'/></svg>");
}

.paleos-body ::-webkit-scrollbar-button:single-button:horizontal:increment {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path d='M7 4 2 7V1z' fill='%23222'/></svg>");
}

.paleos-body ::-webkit-scrollbar-corner { background: var(--panel); }


/* -----------------------------------------------------------------------------
   10  LIST AND COLUMN VIEWS
   -------------------------------------------------------------------------- */

.paleos-list {
    margin: 0;
    padding: 0;
    list-style: none;
    background: var(--doc);
}

.paleos-list-header {
    display: flex;
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--panel);
    box-shadow: inset 0 -1px 0 var(--panel-shadow);
}

.paleos-list-header span {
    padding: 2px 7px;
    font-size: var(--ui-small);
    font-weight: 700;
    border-right: 1px solid var(--panel-shadow);
    box-shadow: inset 0 1px 0 var(--panel-hi);
}

.paleos-list-row {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    padding: 3px 7px;
    border: 0;
    background: none;
    font-size: var(--ui-size);
    text-align: left;
    /* BeOS ruled list rows off with a pale blue grid line rather than
       striping them. */
    border-bottom: 1px solid #cfe0f2;
}

.paleos-list-row:hover { background: var(--panel-lit); }

.paleos-list-row.is-selected,
.paleos-list-row[aria-selected="true"] {
    background: var(--sel);
    color: var(--sel-ink);
}

.paleos-list-row img,
.paleos-list-row svg { width: 16px; height: 16px; flex: none; }

.paleos-list-cell {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.paleos-list-cell.is-grow { flex: 1; }

.paleos-list-cell.is-meta {
    flex: none;
    font-size: var(--ui-small);
    color: var(--ink-faint);
}

.paleos-list-row.is-selected .paleos-list-cell.is-meta { color: #dfe7f5; }

.paleos-list-empty {
    padding: 14px;
    font-size: var(--ui-size);
    color: var(--ink-faint);
    text-align: center;
}


/* -----------------------------------------------------------------------------
   11  ALERT PANELS
   -------------------------------------------------------------------------- */

.alert-layer {
    position: fixed;
    inset: 0;
    z-index: 97000;
    pointer-events: none;
}

.alert-layer > * { pointer-events: auto; }

.alert-scrim {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.12);
}

.alert-window {
    width: min(460px, calc(100vw - 32px));
}

.alert-window .window-content {
    background: var(--panel);
    box-shadow: none;
}

.alert-content {
    display: flex;
    gap: 14px;
    padding: 16px;
}

.alert-icon { flex: none; line-height: 0; }

.alert-body { flex: 1; min-width: 0; }

.alert-headline {
    margin: 0 0 8px;
    font-size: var(--ui-size);
    font-weight: 700;
}

.alert-text {
    margin: 0;
    font-size: var(--ui-size);
    line-height: 1.5;
}

.alert-text + .alert-text { margin-top: 8px; }

/* A short list inside an alert — what a service announces, and what has
   recently travelled. Tightened well in from the browser's default indent,
   which in a panel this narrow pushes a wrapped line into a second column of
   whitespace and reads as a bug. */
.alert-list {
    margin: 6px 0 0;
    padding-left: 18px;
    font-size: var(--ui-size);
    line-height: 1.5;
}

.alert-list li { margin: 0 0 2px; }

.alert-list code {
    font-family: var(--mono-font);
    font-size: 0.95em;
}

.alert-haiku {
    margin: 10px 0;
    padding: 9px 11px;
    background: var(--doc);
    box-shadow: var(--sink-1);
    font: var(--ui-size)/1.6 var(--mono-font);
    white-space: pre-wrap;
}

.alert-details {
    margin: 8px 0 0;
    padding-left: 18px;
    font-size: var(--ui-small);
}


/* -----------------------------------------------------------------------------
   12  BOOT SCREEN
   -------------------------------------------------------------------------- */

.paleos-boot {
    position: fixed;
    inset: 0;
    z-index: 99000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #000;
    color: #cfcfcf;
}

.boot-inner { text-align: center; }

.boot-logo { margin-bottom: 26px; }

.boot-logo img {
    width: 64px;
    height: 64px;
    image-rendering: auto;
}

.boot-wordmark {
    margin-top: 10px;
    font-size: 15px;
    font-weight: 700;
    letter-spacing: 0.22em;
    color: #fff;
}

/* The row of system icons that lights up one at a time. */
.boot-icons {
    display: flex;
    gap: 12px;
    justify-content: center;
    padding: 12px 16px;
    box-shadow: inset 1px 1px 0 #3a3a3a, inset -1px -1px 0 #101010;
    background: #161616;
}

.boot-icon {
    width: 28px;
    height: 28px;
    opacity: 0.18;
    filter: grayscale(1);
    transition: opacity 0.14s linear, filter 0.14s linear;
}

.boot-icon.is-lit {
    opacity: 1;
    filter: none;
}

.boot-caption {
    margin-top: 18px;
    font: var(--ui-small)/1.4 var(--mono-font);
    color: #8f8f8f;
}

.boot-skip {
    margin-top: 28px;
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #565656;
}


/* -----------------------------------------------------------------------------
   13  LOGIN PANEL
   -------------------------------------------------------------------------- */

.login-shell { z-index: 96000; }

.login-window {
    position: absolute;
    top: 50%;
    left: 50%;
    width: min(430px, calc(100vw - 28px));
    transform: translate(-50%, -54%);
}

.login-content { padding: 16px 18px 18px; }

.login-window .window-content {
    background: var(--panel);
    box-shadow: none;
    overflow: visible;
}

.login-masthead {
    display: flex;
    align-items: center;
    gap: 13px;
}

.login-flag { width: 48px; height: 48px; flex: none; }

/* The two-tone name mark: the name, then its initialism in the tab yellow.

   The name is white where it sits on something dark — the boot screen, the
   desktop — and takes the panel's own ink on a panel, where white would be
   invisible. The yellow half is the constant, because it is the half that
   carries the brand. */
.wordmark-head { color: var(--ink); }
.wordmark-tail { color: var(--paleos-tab); }

.paleos-boot .wordmark-head,
.login-footer .wordmark-head,
.desktop-icon .wordmark-head { color: #fff; }

.login-system {
    font-size: 15px;
    font-weight: 700;
    letter-spacing: 0.08em;
}

.login-tagline {
    margin-top: 3px;
    font-size: var(--ui-small);
    line-height: 1.4;
    color: var(--ink-soft);
}

.login-note {
    margin: 10px 0 0;
    font-size: var(--ui-small);
    line-height: 1.5;
    color: var(--ink-soft);
}

.login-status {
    min-height: 16px;
    margin: 9px 0 0;
    font-size: var(--ui-small);
    line-height: 1.4;
}

.login-status.is-ok { color: var(--ok); }
.login-status.is-error { color: var(--danger); }
.login-status.is-working { color: var(--ink-soft); }

.login-footer {
    position: absolute;
    right: 0;
    bottom: 10px;
    left: 0;
    font-size: var(--ui-small);
    color: rgba(255, 255, 255, 0.72);
    text-align: center;
    text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.4);
}


/* -----------------------------------------------------------------------------
   14  APP: TERMINAL
   -------------------------------------------------------------------------- */

.terminal-app {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: var(--doc);
}

.terminal-surface {
    flex: 1;
    min-height: 0;
    padding: 3px;
}

.terminal-app .xterm {
    height: 100%;
    padding: 0;
}

.terminal-app .xterm-viewport {
    background-color: transparent !important;
    scrollbar-width: thin;
}

/* Schemes, picked in Ghost Admin. Paper white is the authentic default; the
   phosphor schemes are a nod to the terminal theme this one replaced. */
.terminal-app[data-scheme="Paper white"]     { background: #ffffff; }
.terminal-app[data-scheme="Green phosphor"] { background: #04140a; }
.terminal-app[data-scheme="Amber phosphor"] { background: #160f02; }
.terminal-app[data-scheme="Midnight"]       { background: #0b0f1a; }

/* Fallback console, used when xterm.js did not load. Same command set, plainer
   surface: a scrolling transcript and one input line. */
.tty-out {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 6px 8px;
    font: 12px/1.45 var(--mono-font);
    white-space: pre-wrap;
    word-break: break-word;
}

.terminal-app .terminal-surface:has(.tty-out) { display: flex; flex-direction: column; }

.tty-row { min-height: 1.45em; }

.tty-line {
    display: flex;
    align-items: baseline;
    gap: 4px;
    flex: none;
    padding: 4px 8px 7px;
    font: 12px/1.45 var(--mono-font);
}

.tty-prompt { white-space: pre; }

.tty-input {
    flex: 1;
    min-width: 0;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    outline: 0;
}

.terminal-app[data-scheme="Green phosphor"] .tty-out,
.terminal-app[data-scheme="Green phosphor"] .tty-line { color: #3cf06a; }

.terminal-app[data-scheme="Amber phosphor"] .tty-out,
.terminal-app[data-scheme="Amber phosphor"] .tty-line { color: #ffb000; }

.terminal-app[data-scheme="Midnight"] .tty-out,
.terminal-app[data-scheme="Midnight"] .tty-line { color: #cfd8e8; }

/* A menu torn off a window's menu bar is positioned in fixed coordinates by the
   app, so it needs no offsets of its own here. */
.paleos-menu.is-floating { position: fixed; }


/* -----------------------------------------------------------------------------
   15  APP: NETPALE (BROWSER)
   -------------------------------------------------------------------------- */

.np-app {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: var(--panel);
}

.np-toolbar {
    display: flex;
    flex: none;
    align-items: center;
    gap: 4px;
    padding: 0 0 4px;
}

.np-locationbar {
    display: flex;
    flex: none;
    align-items: center;
    gap: 6px;
    padding: 0 0 4px;
}

.np-locationbar .paleos-label { flex: none; }

.np-location {
    flex: 1;
    min-width: 0;
    padding: 2px 5px;
    background: var(--doc);
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
    font: var(--ui-small)/1.5 var(--mono-font);
}

.np-location:focus { outline: 0; box-shadow: var(--sink-1), 0 0 0 2px var(--sel); }

.np-viewport {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: 20px var(--np-pad) 36px;
    background: var(--doc);
    box-shadow: var(--sink-1);
}

.np-status {
    display: flex;
    flex: none;
    align-items: center;
    gap: 5px;
    height: 20px;
    margin-top: 4px;
    font-size: var(--ui-small);
    color: var(--ink-soft);
}

.np-status-text {
    flex: 1;
    overflow: hidden;
    padding: 0 6px;
    white-space: nowrap;
    text-overflow: ellipsis;
    box-shadow: var(--sink-1);
    line-height: 18px;
    height: 100%;
}

.np-status .paleos-progress { width: 96px; flex: none; height: 18px; }

/* The browser's rendered document: the site index, an article, a tag listing. */
.np-page { max-width: 64ch; margin: 0 auto; }

.np-page-head {
    margin-bottom: 18px;
    padding-bottom: 10px;
    border-bottom: 2px solid var(--panel);
}

.np-page-title {
    margin: 0;
    font-size: 21px;
    line-height: 1.25;
}

.np-page-meta {
    margin: 6px 0 0;
    font-size: var(--ui-small);
    color: var(--ink-faint);
}

.np-index-item {
    display: block;
    width: 100%;
    padding: 9px 10px;
    margin-bottom: 2px;
    border: 0;
    background: none;
    text-align: left;
}

.np-index-item:hover { background: #eef2f8; }

.np-index-item:focus-visible { outline: 1px dotted var(--ink); }

.np-index-title {
    display: block;
    font-size: 14px;
    font-weight: 700;
    color: var(--link);
    text-decoration: underline;
}

.np-index-meta {
    display: block;
    margin-top: 2px;
    font-size: var(--ui-small);
    color: var(--ink-faint);
}

.np-index-excerpt {
    display: block;
    margin-top: 4px;
    font-size: var(--ui-size);
    line-height: 1.5;
    color: var(--ink-soft);
}

.np-badge {
    display: inline-block;
    margin-left: 6px;
    padding: 0 4px;
    background: var(--paleos-tab);
    border: 1px solid var(--tab-shadow);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #3a2c00;
    vertical-align: 1px;
}

.np-feature {
    margin: 0 0 16px;
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
    line-height: 0;
}

.np-gate {
    margin-top: 20px;
    padding: 14px 16px;
    background: var(--panel);
    box-shadow: var(--raise-1);
}

.np-gate h2 { margin: 0 0 7px; font-size: 14px; }
.np-gate p { margin: 0 0 10px; font-size: var(--ui-size); line-height: 1.5; }


/* -----------------------------------------------------------------------------
   15b  NETPALE: THE START PAGE AND THE SITES IT SERVES

   Everything from here to the end of this block is rendered *inside* the
   browser's viewport, so it deliberately stops looking like BeOS. A window's
   chrome is an operating system; what the window displays is a web page, and a
   page drawn in panel grey with bevelled buttons would read as part of the
   window rather than as something the browser went and fetched. The sites use a
   serif masthead, their own accent colour and ordinary web typography.
   -------------------------------------------------------------------------- */

.np-viewport { --np-pad: 24px; }

.np-portal { max-width: 70ch; }

.np-portal-head { margin-bottom: 22px; }

.np-portal-title {
    margin: 0;
    font-size: 22px;
    letter-spacing: -0.01em;
}

.np-portal-sub {
    margin: 4px 0 0;
    font-size: var(--ui-size);
    color: var(--ink-faint);
}

.np-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
    gap: 16px 12px;
}

.np-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
    padding: 8px 4px 10px;
    border: 0;
    background: none;
    text-align: center;
}

.np-tile:hover { background: #eef2f8; }
.np-tile:focus-visible { outline: 1px dotted var(--ink); }

/* The tile mark: a lettered square, the way a browser's speed dial shows a site
   that has no icon of its own. */
.np-tile-mark {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 54px;
    height: 54px;
    border: 1px solid rgba(0, 0, 0, 0.35);
    box-shadow: inset 1px 1px 0 rgba(255, 255, 255, 0.35), 1px 1px 0 rgba(0, 0, 0, 0.18);
    color: #fff;
    font-size: 20px;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.np-tile-name {
    font-size: var(--ui-size);
    font-weight: 700;
    line-height: 1.25;
}

.np-tile-host {
    font-size: 10px;
    line-height: 1.3;
    color: var(--ink-faint);
    word-break: break-word;
}

.np-portal-note {
    margin-top: 22px;
    padding: 12px 14px;
    background: #f3f6fa;
    border-left: 3px solid var(--sel);
    font-size: var(--ui-size);
    line-height: 1.55;
}

.np-portal-note code,
.ws-note code {
    padding: 1px 4px;
    background: #fff;
    border: 1px solid #d4dde8;
    font: 0.92em var(--mono-font);
}

/* ---- a site -------------------------------------------------------------- */

/* The page runs the full width of the viewport so the masthead, nav strip and
   footer can carry edge-to-edge backgrounds; a wrapper inside each keeps their
   contents on the same column as the body text. */
.ws-page {
    --ws-accent: #2f6fb5;
    --ws-serif: Georgia, "Times New Roman", "Liberation Serif", serif;
    --ws-col: 72ch;
    color: #1b1b1b;
}

.ws-masthead {
    margin: -20px calc(-1 * var(--np-pad)) 24px;
    padding: 4px 0 0;
    border-bottom: 3px solid var(--ws-accent);
    background: #fff;
}

.ws-masthead-inner {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    max-width: var(--ws-col);
    margin: 0 auto;
    padding: 0 var(--np-pad) 10px;
}

.ws-body {
    max-width: var(--ws-col);
    margin: 0 auto;
}

.ws-wordmark {
    padding: 0;
    border: 0;
    background: none;
    font: 700 27px/1.1 var(--ws-serif);
    letter-spacing: -0.015em;
    color: #121212;
    text-align: left;
}

.ws-wordmark:hover { color: var(--ws-accent); }

.ws-domain {
    font: 11px/1 var(--mono-font);
    color: var(--ink-faint);
}

.ws-nav { background: var(--ws-accent); }

.ws-nav-inner {
    display: flex;
    flex-wrap: wrap;
    gap: 0 2px;
    max-width: var(--ws-col);
    margin: 0 auto;
    padding: 0 var(--np-pad);
}

.ws-nav-link {
    padding: 6px 11px;
    border: 0;
    background: none;
    font-size: var(--ui-small);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.86);
}

.ws-nav-link:hover { background: rgba(255, 255, 255, 0.16); color: #fff; }

.ws-nav-link.is-current { background: #fff; color: var(--ws-accent); }

.ws-page-title {
    margin: 0 0 18px;
    font: 700 25px/1.15 var(--ws-serif);
}

.ws-section {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin: 26px 0 12px;
    padding-bottom: 5px;
    border-bottom: 1px solid #d9d9d9;
}

.ws-section:first-child { margin-top: 0; }

.ws-section-head {
    margin: 0;
    font-size: var(--ui-small);
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ws-accent);
}

.ws-section-more {
    padding: 0;
    border: 0;
    background: none;
    font-size: var(--ui-small);
    color: var(--ink-faint);
}

.ws-section-more:hover { color: var(--ws-accent); text-decoration: underline; }

.ws-story { margin-bottom: 18px; }

.ws-story-title {
    display: block;
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    font: 700 17px/1.3 var(--ws-serif);
    color: #121212;
    text-align: left;
}

.ws-story.is-lead .ws-story-title { font-size: 22px; }

.ws-story-title:hover { color: var(--ws-accent); text-decoration: underline; }

.ws-story-meta {
    margin: 4px 0 0;
    font-size: var(--ui-small);
    color: var(--ink-faint);
}

.ws-story-excerpt {
    margin: 6px 0 0;
    font-size: 13.5px;
    line-height: 1.55;
    color: #3a3a3a;
}

.ws-kicker {
    margin: 0 0 6px;
    font-size: var(--ui-small);
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--ws-accent);
}

.ws-article-title {
    margin: 0 0 6px;
    font: 700 27px/1.18 var(--ws-serif);
    letter-spacing: -0.01em;
}

.ws-article .gh-content { margin-top: 18px; }

.ws-figure {
    margin: 18px 0;
    line-height: 0;
}

.ws-figure img { border: 1px solid #ccc; }

.ws-note {
    margin: 12px 0 0;
    font-size: var(--ui-size);
    line-height: 1.6;
    color: var(--ink-soft);
}

.ws-footer {
    margin: 34px calc(-1 * var(--np-pad)) -36px;
    padding: 14px 0 20px;
    border-top: 3px solid var(--ws-accent);
    background: #f4f4f2;
    font-size: var(--ui-small);
    color: var(--ink-faint);
}

.ws-footer-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    max-width: var(--ws-col);
    margin: 0 auto;
    padding: 0 var(--np-pad);
}

.ws-footer-link {
    padding: 0;
    border: 0;
    background: none;
    font-size: var(--ui-small);
    color: var(--ws-accent);
    text-decoration: underline;
}


/* -----------------------------------------------------------------------------
   16  APP: PALEMAIL
   -------------------------------------------------------------------------- */

.mail-app {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: var(--panel);
}

.mail-toolbar {
    display: flex;
    flex: none;
    align-items: center;
    gap: 4px;
    padding-bottom: 4px;
}

.mail-body {
    display: flex;
    flex: 1;
    min-height: 0;
    gap: 3px;
}

.mail-sidebar {
    flex: none;
    width: 128px;
    overflow: auto;
    background: var(--doc);
    box-shadow: var(--sink-1);
}

.mail-main {
    display: flex;
    flex: 1;
    min-width: 0;
    flex-direction: column;
    gap: 4px;
}

.mail-headers {
    flex: none;
    padding: 7px 8px;
    background: var(--panel);
    box-shadow: var(--raise-1);
}

.mail-headers .paleos-field-row { margin-bottom: 5px; }
.mail-headers .paleos-field-row:last-child { margin-bottom: 0; }

.mail-compose {
    flex: 1;
    min-height: 0;
    display: flex;
}

.mail-compose textarea {
    flex: 1;
    padding: 9px 11px;
    font: var(--ui-size)/1.55 var(--ui-font);
}

.mail-readonly {
    padding: 2px 5px;
    background: var(--panel-lit);
    box-shadow: var(--sink-1);
    font-size: var(--ui-size);
    flex: 1;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.mail-reading {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: 12px 14px;
    background: var(--doc);
    box-shadow: var(--sink-1);
    font-size: var(--ui-size);
    line-height: 1.55;
}

.mail-reading h3 { margin: 0 0 4px; font-size: 14px; }

.mail-reading-meta {
    margin: 0 0 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--panel);
    font-size: var(--ui-small);
    color: var(--ink-faint);
}

.mail-reading-body { white-space: pre-wrap; }


/* -----------------------------------------------------------------------------
   16b  APP: PALEFILES

   A file window: a path field, then either an icon field or a column list. The
   icon field is the default because that is how a BeOS volume opened.
   -------------------------------------------------------------------------- */

.pf-app {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: var(--panel);
}

.pf-toolbar {
    display: flex;
    flex: none;
    align-items: center;
    gap: 4px;
    padding-bottom: 4px;
}

.pf-path {
    flex: 1;
    min-width: 0;
    padding: 2px 6px;
    background: var(--doc);
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
    font: var(--ui-small)/1.6 var(--mono-font);
}

.pf-path:focus { outline: 0; box-shadow: var(--sink-1), 0 0 0 2px var(--sel); }

.pf-view {
    flex: 1;
    min-height: 0;
    overflow: auto;
    background: var(--doc);
    box-shadow: var(--sink-1);
}

.pf-icons {
    display: flex;
    flex-flow: row wrap;
    align-content: flex-start;
    gap: 6px 2px;
    padding: 10px 8px;
}

.pf-item {
    width: 88px;
    padding: 4px 2px 5px;
    border: 0;
    background: none;
    text-align: center;
}

.pf-item-glyph {
    display: inline-block;
    position: relative;
    line-height: 0;
}

.pf-item-glyph img { width: 32px; height: 32px; }

.pf-item-label {
    display: block;
    width: fit-content;
    margin-inline: auto;
    max-width: 84px;
    margin-top: 3px;
    padding: 0 3px;
    overflow: hidden;
    font-size: var(--ui-small);
    line-height: 1.3;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pf-item.is-selected .pf-item-label {
    background: var(--sel);
    color: var(--sel-ink);
}

.pf-item:focus-visible { outline: 1px dotted var(--ink); }

.pf-empty {
    padding: 18px;
    font-size: var(--ui-size);
    color: var(--ink-faint);
    text-align: center;
}

/* The reading pane, for a document opened inside the file window. */
.pf-reader {
    padding: 12px 14px;
    font: 12px/1.6 var(--mono-font);
    white-space: pre-wrap;
    word-break: break-word;
}

.pf-reader-head {
    margin: 0 0 10px;
    padding-bottom: 7px;
    border-bottom: 1px solid var(--panel);
    font: 700 var(--ui-size)/1.4 var(--ui-font);
}


/* -----------------------------------------------------------------------------
   16c  APP: CLOCK
   -------------------------------------------------------------------------- */

.clock-app {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    height: 100%;
    padding: 10px;
    background: var(--panel);
}

.clock-face { width: 100%; max-width: 190px; height: auto; }

.clock-digital {
    font: 700 17px/1 var(--mono-font);
    font-variant-numeric: tabular-nums;
}

.clock-date {
    margin-top: -4px;
    font-size: var(--ui-small);
    color: var(--ink-soft);
}

.clock-app[data-view="digital"] .clock-face { display: none; }

.clock-app[data-view="digital"] .clock-digital { font-size: 30px; }


/* -----------------------------------------------------------------------------
   17  APP: PALEEDIT (NOTES)
   -------------------------------------------------------------------------- */

.notes-app {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: var(--panel);
}

.notes-body {
    display: flex;
    flex: 1;
    min-height: 0;
    gap: 3px;
}

.notes-list {
    flex: none;
    width: 150px;
    overflow: auto;
    background: var(--doc);
    box-shadow: var(--sink-1);
}

.notes-editor-wrap {
    display: flex;
    flex: 1;
    min-width: 0;
    flex-direction: column;
    gap: 4px;
}

.notes-title-row { flex: none; }

.notes-editor {
    flex: 1;
    min-height: 0;
    padding: 11px 13px;
    background: var(--doc);
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
    font: 13px/1.6 var(--ui-font);
    resize: none;
}

.notes-editor:focus { outline: 0; box-shadow: var(--sink-1), 0 0 0 2px var(--sel); }

/* MONOSPACED MEANS CODE, AND CODE DOES NOT SOFT-WRAP.
   A textarea wraps at word boundaries, which is right for prose and wrong for
   anything whose indentation carries meaning: a long line folds back to the
   left margin and every line under it reads as a hanging indent, so a file of
   source becomes a wall nobody can follow. Lines keep their length here and the
   view scrolls sideways instead — which is what every editor does, and what the
   person who chose this font was asking for. */
.notes-editor[data-font="mono"] {
    font-family: var(--mono-font);
    font-size: 12px;
    white-space: pre;
    overflow-x: auto;
}

.notes-wordcount {
    flex: none;
    font-size: var(--ui-small);
    color: var(--ink-soft);
}


/* -----------------------------------------------------------------------------
   18  STANDALONE DOCUMENTS AND ARTICLE TYPOGRAPHY
   -------------------------------------------------------------------------- */

.document-shell {
    max-width: 860px;
    margin: 0 auto;
    padding: 26px 16px 60px;
}

.document-window {
    position: static;
    width: 100%;
    margin-bottom: 26px;
}

.document-window .window-content {
    overflow: visible;
    background: var(--doc);
}

.document-content { padding: 26px 30px 34px; }

.document-feature {
    margin: 0 0 22px;
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
    line-height: 0;
}

.document-feature figcaption {
    padding: 6px 8px;
    background: var(--panel);
    font-size: var(--ui-small);
    line-height: 1.4;
    color: var(--ink-soft);
}

.document-header {
    margin-bottom: 22px;
    padding-bottom: 14px;
    border-bottom: 2px solid var(--panel);
}

.document-title {
    margin: 0;
    font-size: 27px;
    line-height: 1.2;
    letter-spacing: -0.01em;
}

.document-byline {
    margin: 9px 0 0;
    font-size: var(--ui-small);
    color: var(--ink-faint);
}

.document-tags { margin: 6px 0 0; font-size: var(--ui-small); }

.author-portrait {
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
    margin-bottom: 10px;
}

.document-gate {
    margin-top: 26px;
    padding: 18px 20px;
    background: var(--panel);
    box-shadow: var(--raise-1);
}

.document-gate h2 { margin: 0 0 8px; font-size: 15px; }
.document-gate p { margin: 0 0 12px; font-size: 13px; line-height: 1.55; }

/* Ghost's rendered content, in both the standalone document and NetPale. */
.gh-content {
    font-size: 15px;
    line-height: 1.65;
    color: #1b1b1b;
}

.gh-content > * + * { margin-top: 1.1em; }

.gh-content h2 { margin-top: 1.8em; font-size: 20px; line-height: 1.3; }
.gh-content h3 { margin-top: 1.6em; font-size: 16px; line-height: 1.35; }
.gh-content h4 { margin-top: 1.5em; font-size: 14px; }

.gh-content a { color: var(--link); text-decoration: underline; }

.gh-content blockquote {
    margin-left: 0;
    margin-right: 0;
    padding: 2px 0 2px 16px;
    border-left: 4px solid var(--paleos-tab);
    color: var(--ink-soft);
}

.gh-content img,
.gh-content video {
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
}

.gh-content figure { margin: 1.6em 0; }

.gh-content figcaption {
    margin-top: 7px;
    font-size: var(--ui-small);
    line-height: 1.45;
    color: var(--ink-faint);
    text-align: center;
}

.gh-content pre {
    padding: 12px 14px;
    overflow-x: auto;
    background: #f4f4f4;
    box-shadow: var(--sink-1);
    font: 12px/1.55 var(--mono-font);
}

.gh-content code {
    padding: 1px 4px;
    background: #f0f0f0;
    box-shadow: var(--sink-1);
    font: 0.92em var(--mono-font);
}

.gh-content pre code { padding: 0; background: none; box-shadow: none; }

.gh-content hr {
    height: 2px;
    margin: 2em 0;
    border: 0;
    box-shadow: var(--sink-1);
}

.gh-content table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

.gh-content th,
.gh-content td {
    padding: 6px 9px;
    border: 1px solid var(--panel-shadow);
    text-align: left;
}

.gh-content th { background: var(--panel); }

.gh-content ul,
.gh-content ol { padding-left: 24px; }

.gh-content li + li { margin-top: 0.35em; }

.kg-width-full img,
.kg-width-wide img { width: 100%; }

.kg-card { margin: 1.6em 0; }

.listing { margin: 0; padding: 0; list-style: none; }

.listing-row {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 8px 2px;
    border-bottom: 1px solid var(--panel);
}

.listing-title { flex: 1; font-size: 14px; font-weight: 700; }

.listing-meta { flex: none; font-size: var(--ui-small); color: var(--ink-faint); }

.pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 24px;
    padding-top: 14px;
    border-top: 2px solid var(--panel);
    font-size: var(--ui-size);
}

.plain-badge {
    display: inline-block;
    padding: 0 5px;
    background: var(--paleos-tab);
    border: 1px solid var(--tab-shadow);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #3a2c00;
}


/* -----------------------------------------------------------------------------
   19  NO-JS INDEX
   -------------------------------------------------------------------------- */

.plain-index {
    max-width: 720px;
    margin: 0 auto;
    padding: 34px 20px 70px;
    background: var(--doc);
    box-shadow: var(--raise-1);
}

.plain-lede { font-size: 14px; color: var(--ink-soft); }

.plain-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    margin: 18px 0 26px;
    padding-bottom: 12px;
    border-bottom: 2px solid var(--panel);
    font-size: 13px;
}

.plain-post {
    margin-bottom: 26px;
    padding-bottom: 18px;
    border-bottom: 1px solid var(--panel);
}

.plain-post h2 { margin: 0 0 5px; font-size: 17px; line-height: 1.3; }

.plain-meta { margin: 0 0 7px; font-size: var(--ui-small); color: var(--ink-faint); }

.plain-note { margin-top: 30px; font-size: var(--ui-small); color: var(--ink-faint); }


/* -----------------------------------------------------------------------------
   16d  APP: PALEPRESS

   A markdown composer: the documents down the left, the headers across the top,
   then the editor and its preview side by side. The preview is deliberately
   styled as a web page rather than as panel furniture — it is standing in for
   what the piece will look like once published, not for part of the window.
   -------------------------------------------------------------------------- */

.press-app {
    display: flex;
    height: 100%;
    min-height: 0;
    background: var(--panel);
}

.press-sidebar {
    flex: none;
    width: 168px;
    display: flex;
    flex-direction: column;
    min-height: 0;
    border-right: 1px solid var(--panel-dark);
}

.press-list {
    flex: 1;
    min-height: 0;
    overflow: auto;
    background: var(--doc);
    box-shadow: var(--sink-1);
}

.press-item-name {
    display: block;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.press-item-sub {
    display: block;
    font: 10px/1.3 var(--mono-font);
    color: var(--ink-faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.paleos-list-row.is-selected .press-item-sub { color: #dfe7f5; }

.press-sidebar-foot {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    padding: 5px;
}

.press-count { font-size: 10px; color: var(--ink-faint); }

.press-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.press-headers {
    flex: none;
    padding: 7px 8px 2px;
    border-bottom: 1px solid var(--panel-dark);
}

.press-headers .paleos-field-row { margin-bottom: 5px; }
.press-headers .paleos-label { width: 56px; }
.press-slug { font-family: var(--mono-font); font-size: var(--ui-small); }

.press-panes {
    flex: 1;
    min-height: 0;
    display: flex;
    gap: 3px;
    padding: 3px;
}

.press-editor {
    flex: 1;
    min-width: 0;
    padding: 9px 11px;
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
    background: var(--doc);
    font: 12px/1.6 var(--mono-font);
    resize: none;
}

.press-editor:focus { outline: 0; box-shadow: var(--sink-1), 0 0 0 2px var(--sel); }

.press-preview {
    flex: 1;
    min-width: 0;
    overflow: auto;
    padding: 12px 16px 20px;
    background: var(--doc);
    box-shadow: var(--sink-1);
}

.press-panes[data-mode="preview"] .press-editor { display: none; }
.press-panes[data-mode="editor"] .press-preview { display: none; }


/* -----------------------------------------------------------------------------
   19b  ROLODEX

   Three columns: the card list, the alphabet strip that filters it, and the open
   card. The strip is the thing that makes it read as a rolodex rather than a
   list box, so it keeps its full height even when the window is short.
   -------------------------------------------------------------------------- */

.rx-app {
    display: flex;
    height: 100%;
    min-height: 0;
    background: var(--panel);
}

.rx-sidebar {
    flex: none;
    width: 176px;
    display: flex;
    flex-direction: column;
    min-height: 0;
    border-right: 1px solid var(--panel-dark);
}

.rx-searchrow { padding: 5px; }
.rx-search { width: 100%; box-sizing: border-box; }

.rx-list {
    flex: 1;
    min-height: 0;
    overflow: auto;
    background: var(--doc);
    box-shadow: var(--sink-1);
}

.rx-item { align-items: flex-start; }

.rx-item-name {
    display: block;
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rx-item-sub {
    display: block;
    font-size: 10px;
    color: var(--ink-faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.rx-item.is-selected .rx-item-sub { color: #e8eef6; }

.rx-sidebar-foot {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    padding: 5px;
}

.rx-count { font-size: 10px; color: var(--ink-faint); }

.rx-strip {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    width: 19px;
    padding: 4px 1px;
    gap: 1px;
    overflow: auto;
    background: var(--panel-dark);
}

.rx-strip-key {
    flex: none;
    padding: 0;
    height: 13px;
    border: 0;
    background: none;
    font-size: 9px;
    line-height: 13px;
    font-weight: 700;
    color: var(--ink-soft);
    cursor: pointer;
}

.rx-strip-key:hover:not([disabled]) { background: var(--panel-lit); }
.rx-strip-key.is-active { background: var(--paleos-tab); color: #000; }
.rx-strip-key.is-empty { color: var(--panel-shadow); cursor: default; }

.rx-card {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.rx-card-head {
    flex: none;
    padding: 6px 8px;
    border-bottom: 1px solid var(--panel-dark);
}

.rx-name {
    width: 100%;
    box-sizing: border-box;
    font-size: 13px;
    font-weight: 700;
}

.rx-card-body {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: 8px;
}

.rx-row { margin-bottom: 4px; }
.rx-row .paleos-input { flex: 1; min-width: 0; }
.rx-label { flex: none; width: 58px; }
.rx-area { resize: vertical; min-height: 34px; font-family: inherit; }

.rx-row.is-custom { gap: 5px; }
.rx-custom-label { flex: none; width: 92px; }
.rx-custom-value { flex: 1; min-width: 0; }

.rx-drop {
    flex: none;
    width: 17px;
    height: 17px;
    padding: 0;
    border: 1px solid var(--panel-darkest);
    background: var(--panel);
    box-shadow: var(--raise-1);
    cursor: pointer;
    position: relative;
}

.rx-drop::before,
.rx-drop::after {
    content: "";
    position: absolute;
    left: 3px;
    right: 3px;
    top: 7px;
    height: 2px;
    background: #6a2020;
}

.rx-drop::before { transform: rotate(45deg); }
.rx-drop::after { transform: rotate(-45deg); }
.rx-drop:active { box-shadow: var(--sink-1); }

.rx-card-actions {
    display: flex;
    gap: 6px;
    padding-top: 2px;
}

/* -----------------------------------------------------------------------------
   19c  BACKGROUNDS PREFERENCE PANEL

   BeOS previewed a desktop picture inside a drawing of a monitor, which is both
   charming and genuinely useful: it shows the placement without disturbing the
   desktop you are looking at.
   -------------------------------------------------------------------------- */

.bg-panel {
    display: flex;
    flex-direction: column;
    gap: 10px;
    height: 100%;
    padding: 12px;
    box-sizing: border-box;
}

.bg-body {
    display: flex;
    gap: 14px;
    align-items: flex-start;
    flex: 1;
    min-height: 0;
}

.bg-monitor {
    flex: none;
    width: 162px;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.bg-monitor-bezel {
    width: 162px;
    height: 124px;
    padding: 9px;
    box-sizing: border-box;
    background: var(--panel);
    border-radius: 7px 7px 3px 3px;
    box-shadow: var(--raise-1), inset 0 1px 0 rgba(255, 255, 255, 0.5);
}

.bg-monitor-screen {
    width: 100%;
    height: 100%;
    background-color: var(--paleos-desktop);
    box-shadow: var(--sink-1);
}

.bg-monitor-neck {
    width: 30px;
    height: 7px;
    background: var(--panel);
    box-shadow: inset -1px 0 0 var(--panel-shadow), inset 1px 0 0 var(--panel-hi);
}

.bg-monitor-stand {
    width: 66px;
    height: 7px;
    background: var(--panel);
    border-radius: 0 0 3px 3px;
    box-shadow: var(--raise-1);
}

.bg-controls {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.bg-controls .paleos-select { flex: 1; min-width: 0; }

.bg-swatches {
    display: flex;
    gap: 5px;
    flex-wrap: wrap;
}

.bg-swatch {
    width: 20px;
    height: 20px;
    padding: 0;
    border: 1px solid var(--panel-darkest);
    box-shadow: var(--raise-1);
    cursor: pointer;
}

.bg-swatch:active { box-shadow: var(--sink-1); }

.bg-upload-row {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

.bg-note {
    margin: 0;
    font-size: 10px;
    line-height: 1.45;
    color: var(--ink-soft);
}

.bg-note.is-quiet { color: var(--ink-faint); }
.bg-note.is-error { color: #a81d1d; font-weight: 700; }


/* -----------------------------------------------------------------------------
   19f  PALESERVER, THE PRESS FOOT, AND SEALED MAIL
   -------------------------------------------------------------------------- */

.ps-app { padding: 13px; }

.ps-head { display: flex; align-items: center; gap: 11px; }

.ps-row {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 2px 0;
    font-size: var(--ui-size);
}

.ps-lamp {
    flex: none;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--panel-shadow);
    box-shadow: var(--sink-1);
}

.ps-lamp[data-state="ok"] { background: var(--ok); }
.ps-lamp[data-state="error"] { background: var(--danger); }
.ps-lamp[data-state="off"] { background: var(--panel-shadow); }

.ps-label { flex: none; width: 118px; }
.ps-value { color: var(--ink-soft); }

/* THE POST REPORT'S TWO EXTRA PIECES.

   The code sits at the right-hand end in fixed pitch, the way the startup
   screen puts it in its own column: a reader scanning for "which one had
   something to say" is scanning a column, not reading sentences. It is NOT
   emphasised, because a code is an answer rather than a fault — only the three
   that halt are faults, and you cannot be reading this window if one of them
   fired.

   `is-bad` is the row that genuinely did not answer, and it matches
   palebios.js's own class name for the same state so the two renderings of one
   report cannot drift into disagreeing. */
.ps-row .ps-value { flex: 1 1 auto; }
.ps-code {
    flex: none;
    font-family: var(--mono-font);
    font-size: calc(var(--ui-size) - 1px);
    color: var(--ink-soft);
    letter-spacing: 0.02em;
}
.ps-row.is-bad .ps-label,
.ps-row.is-bad .ps-value,
.ps-row.is-bad .ps-code { color: var(--danger); font-weight: 700; }

.ps-terms {
    background: var(--doc);
    box-shadow: var(--sink-1);
    margin-bottom: 8px;
}

.ps-tick { flex: none; width: 14px; text-align: center; }

/* ---- PalePress: the address line and the foot ---------------------------- */

.press-address {
    margin: 2px 0 0;
    font: 11px/1.4 var(--mono-font);
    color: var(--ink-faint);
}

.press-address.is-live { color: var(--ok); }

.press-cat { flex: none; width: 110px; }

.press-foot {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 5px 8px 7px;
}

.press-notice {
    margin: 0;
    font-size: var(--ui-small);
    line-height: 1.4;
    color: var(--ink-soft);
}

.press-notice.is-error { color: var(--danger); }

/* ---- PaleMail ------------------------------------------------------------ */

.mail-split { display: flex; flex: 1; min-height: 0; gap: 3px; }

.mail-list {
    flex: none;
    width: 216px;
    overflow: auto;
    background: var(--doc);
    box-shadow: var(--sink-1);
}

.mail-row-who { display: block; font-weight: 700; }

.mail-row-subject {
    display: block;
    font-size: 10px;
    color: var(--ink-faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.paleos-list-row.is-selected .mail-row-subject { color: #dfe7f5; }

/* A draft or submission too long for Faucet to carry. Said on the row rather
   than left to be discovered on another computer. Not an error colour: nothing
   has gone wrong and nothing is at risk — it simply stays here. */
.mail-row-local {
    display: block;
    margin-top: 2px;
    font-size: 9px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-faint);
    opacity: 0.85;
}

.paleos-list-row.is-selected .mail-row-local { color: #c7d4ea; opacity: 1; }

.mail-locked {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 8px;
    padding: 20px 22px;
    background: var(--panel);
}

.mail-compose-pane {
    display: flex;
    flex: 1;
    min-height: 0;
    flex-direction: column;
    gap: 4px;
}

.mail-sealnote {
    margin: 0;
    padding: 4px 8px;
    font-size: var(--ui-small);
    line-height: 1.4;
    color: var(--ink-soft);
    background: var(--panel-lit);
    box-shadow: var(--sink-1);
}

.mail-sealnote.is-sealed { color: #1d5c2c; }

.mail-me { padding: 6px 7px; }

.mail-me-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-faint);
}

.mail-me-address {
    font: 10px/1.4 var(--mono-font);
    word-break: break-all;
}

/* Mail over its quarter of the disk. The sidebar is narrow, so this wraps and
   is allowed to be several lines tall — it is read once and then acted on,
   not scanned. Same amber as PaleDisk's ceiling warning: a thing to know
   about, not a failure. Nothing has been lost and nothing is refused. */
.mail-share {
    display: flex;
    flex-direction: column;
    gap: 3px;
    margin: 6px 0 0;
    padding: 6px 7px;
    border-top: 2px solid var(--panel-shadow);
}

.mail-share-badge {
    align-self: flex-start;
    padding: 1px 6px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #4a3600;
    background: var(--paleos-tab, #ffcb00);
    box-shadow: var(--sink-1);
}

.mail-share-why {
    font-size: 11px;
    line-height: 1.45;
    color: var(--ink-soft);
}

/* The newest five hundred of more than that. Reads as part of the list, above
   the first row, and says plainly that the rest are still there — the one
   thing somebody looking at a shortened list needs to know. */
.mail-more {
    padding: 4px 8px;
    font-size: 11px;
    line-height: 1.4;
    color: var(--ink-soft);
    background: var(--panel-lit);
    box-shadow: var(--sink-1);
}

.login-note.is-error { color: var(--danger); }

.rx-write { min-width: 0; }


/* -----------------------------------------------------------------------------
   19e  THE TRAY, AND FAUCET

   BeOS let a windowless process put a small icon in the Deskbar beside the
   clock. The Deskbar is gone; these sit on the dock now, right of the divider
   and left of Log Out and Shut Down, and nothing is drawn at all until
   something is in it.
   -------------------------------------------------------------------------- */

/* Sized and bevelled like .dock-system, because that is what it sits beside
   on the dock. In the Deskbar these had no border and no background of their
   own — the Deskbar's own tray panel supplied both, and a bare 16px icon with
   nothing behind it reads as a broken image rather than as a control. */
.tray-item {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    /* 30px, the size of every other icon on the strip. The dock is one row of
       one kind of thing to the eye, and a tray item two-thirds the height of
       its neighbours reads as a mistake rather than as a distinction. */
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--panel-darkest);
    background: var(--panel);
    box-shadow: var(--raise-1);
    cursor: default;
    line-height: 0;
    position: relative;
}

.tray-item img { width: 16px; height: 16px; }

.tray-item:hover { background: var(--panel-lit); }
.tray-item:active { box-shadow: var(--sink-1); }

/* The state reads off the icon itself: dimmed when off, a thin bar underneath
   in the tab yellow when running, red when it cannot reach the server. */
.tray-item[data-state="off"] img { opacity: 0.4; filter: grayscale(1); }

.tray-item[data-state="idle"]::after,
.tray-item[data-state="working"]::after,
.tray-item[data-state="error"]::after,
.tray-item[data-state="blocked"]::after {
    content: "";
    position: absolute;
    left: 4px;
    right: 4px;
    bottom: 1px;
    height: 2px;
    background: var(--paleos-tab);
}

.tray-item[data-state="error"]::after,
.tray-item[data-state="blocked"]::after { background: var(--danger); }

.tray-item.is-busy img { animation: faucet-drip 1.1s linear infinite; }

@keyframes faucet-drip {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.45; }
}

/* ---- the Faucet window --------------------------------------------------- */

/* A column: the body scrolls, the buttons stay put. The window grew a row per
   application that can sync, so its height is no longer something the markup
   can know in advance. */
.faucet-app {
    height: 100%;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    padding: 13px 13px 10px;
}

.faucet-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding-right: 4px;
}

.faucet-app > .paleos-button-row { flex: none; margin-bottom: 0; }

.faucet-head {
    display: flex;
    align-items: center;
    gap: 11px;
}

.faucet-title {
    font-size: 15px;
    font-weight: 700;
    letter-spacing: 0.04em;
}

.faucet-sub {
    margin-top: 2px;
    font-size: var(--ui-small);
    color: var(--ink-soft);
}

/* The two remedies, under the status, only when the disk is what is in the
   way. Left-aligned with the sentence above rather than right-aligned like a
   dialog's buttons: these are things offered, not a decision being forced. */
.faucet-roomrow {
    margin: 2px 0 8px;
    justify-content: flex-start;
}

.faucet-statusrow {
    display: flex;
    align-items: flex-start;
    gap: 7px;
    margin: 2px 0 6px;
}

.faucet-status {
    margin: 0;
    font-size: var(--ui-size);
    line-height: 1.45;
}

.faucet-status.is-error { color: var(--danger); }

/* A BeOS status lamp: sunken well, lit centre. */
.faucet-lamp {
    flex: none;
    width: 11px;
    height: 11px;
    margin-top: 3px;
    border-radius: 50%;
    background: var(--panel-shadow);
    box-shadow: var(--sink-1);
}

.faucet-lamp[data-state="idle"] { background: var(--ok); }
.faucet-lamp[data-state="working"] { background: var(--paleos-tab); }
.faucet-lamp[data-state="error"],
.faucet-lamp[data-state="blocked"] { background: var(--danger); }


/* -----------------------------------------------------------------------------
   19d  SUBMENUS, DRAG TARGETS, LOCKED ITEMS, THE TRASH BADGE
   -------------------------------------------------------------------------- */

.paleos-menu-item.has-submenu { padding-right: 24px; }

.menu-arrow {
    float: right;
    margin-left: 14px;
    font-size: 9px;
    line-height: 1.5;
    color: var(--ink-soft);
}

.paleos-menu-item:hover .menu-arrow { color: var(--sel-ink); }

/* A folder lights up only for a drop it would actually accept. */
.pf-item.is-drop-target .pf-item-label,
.paleos-list-row.is-drop-target {
    background: var(--sel);
    color: var(--sel-ink);
}

.pf-item.is-drop-target .pf-item-glyph img { filter: brightness(1.15); }

.pf-item.is-dragging,
.paleos-list-row.is-dragging { opacity: 0.45; }

/* Somebody else's file. The dimming is a hint, not the rule — the rule is
   enforced in the core, and asking anyway gets a refusal by name. */
.pf-item.is-locked .pf-item-label,
.paleos-list-row.is-locked .paleos-list-cell.is-grow { color: var(--ink-soft); }

.pf-item.is-locked .pf-item-glyph img,
.paleos-list-row.is-locked img { opacity: 0.86; }

/* How much is in the Trash, in the corner of its icon. */
.desktop-icon-badge {
    position: absolute;
    right: -5px;
    bottom: -2px;
    min-width: 13px;
    height: 13px;
    padding: 0 2px;
    border: 1px solid var(--panel-darkest);
    border-radius: 7px;
    background: var(--paleos-tab);
    box-shadow: 1px 1px 0 rgba(0, 0, 0, 0.4);
    font: 700 9px/12px var(--ui-font);
    color: #3a2c00;
    text-align: center;
}


/* -----------------------------------------------------------------------------
   20  SMALL SCREENS, MOTION, PRINT

   A tiling window manager is wrong on a phone, so below 760px the desktop drops
   its absolute positioning: windows stack down the page at full width, the
   Deskbar becomes a fixed strip along the top, and drag/resize affordances are
   hidden because there is nothing sensible for them to do.
   -------------------------------------------------------------------------- */

/* =============================================================================
   19g  ACCESS DENIED, ERROR PAGES, AND THE KEY ROW
   =============================================================================

   Two full-page states and one small control. The pages are reached when
   something has gone wrong or somebody has arrived somewhere they cannot go,
   so they are laid out to be read rather than skimmed: a picture, a heading,
   a sentence of cause, then what to do. Both sit inside the ordinary document
   window, which is what keeps them looking like part of the system instead of
   a web page that lost its stylesheet.
   ========================================================================== */

.denied-content,
.error-content {
    display: flex;
    gap: 18px;
    align-items: flex-start;
    padding: 18px 20px 20px;
}

.denied-art,
.error-art {
    flex: 0 0 auto;
    border: 1px solid #55565a;
    box-shadow: inset -1px -1px 0 #9a9a9a, inset 1px 1px 0 #f4f4f4;
    background: #336698;
    line-height: 0;
}

.denied-art svg,
.error-art svg { display: block; image-rendering: pixelated; }

.denied-body,
.error-body { flex: 1 1 auto; min-width: 0; }

.denied-head,
.error-head {
    font-family: var(--ui-font);
    font-size: 17px;
    font-weight: bold;
    margin: 0 0 6px;
    color: #101010;
}

.error-code {
    font-family: var(--mono-font);
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: #6a6a6a;
    margin: 0 0 2px;
}

.denied-lede,
.error-lede {
    font-size: 13px;
    line-height: 1.5;
    margin: 0 0 12px;
    max-width: 52ch;
}

/* The three facts, as a definition list: a shape that makes "what / why /
   what now" legible without numbering it like a procedure. */
.denied-facts { margin: 0 0 14px; }

.denied-facts dt {
    font-family: var(--ui-font);
    font-size: 11px;
    font-weight: bold;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #3b5a80;
    margin: 10px 0 2px;
}

.denied-facts dd {
    margin: 0;
    font-size: 12px;
    line-height: 1.5;
    max-width: 56ch;
}

.denied-facts dd code,
.error-steps code {
    font-family: var(--mono-font);
    font-size: 11px;
    background: #e8e8e8;
    border: 1px solid #c0c0c0;
    padding: 0 3px;
}

.error-steps {
    margin: 0 0 14px;
    padding-left: 18px;
    font-size: 12px;
    line-height: 1.55;
    max-width: 56ch;
}

.error-steps li { margin-bottom: 4px; }

.denied-foot {
    font-size: 11px;
    color: #5a5a5a;
    margin: 12px 0 0;
    max-width: 54ch;
}

.error-details {
    border: 1px solid #c0c0c0;
    background: #efefef;
    padding: 8px 10px;
    margin: 0 0 14px;
}

.error-details-head {
    font-family: var(--ui-font);
    font-size: 11px;
    font-weight: bold;
    margin: 0 0 4px;
}

/* ---- the key row, in Faucet -------------------------------------------------

   Faucet's second lamp. The first says whether syncing is happening; this one
   says whether it can be done safely, which is a different question and
   deserves its own line rather than a footnote. */

/* What may be sent, one application per row. A checkbox, the application's
   name, and in smaller type what turning it on would actually send — because
   "PaleMail" on its own does not tell somebody that their letters are what is
   about to leave the machine. */
.faucet-sources {
    background: var(--doc);
    box-shadow: var(--sink-1);
    max-height: 132px;
    overflow: auto;
    margin: 3px 0 2px;
    padding: 2px 0;
}

.faucet-source {
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 3px 7px;
    font-size: 12px;
}

.faucet-source:hover { background: var(--panel-lit); }
.faucet-source input { flex: none; align-self: center; }

.faucet-source-name { flex: none; font-family: var(--ui-font); }

.faucet-source-what {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 11px;
    color: var(--ink-faint);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Stay unlocked. Set in under the key row rather than beside it, because it is
   a thing you agree to rather than a thing you operate. */
.faucet-hold {
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 2px 7px 4px 24px;
    font-size: 12px;
}

.faucet-hold input { flex: none; align-self: center; }
.faucet-hold-label { flex: none; }

.faucet-hold-note {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 11px;
    color: var(--ink-faint);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* What the books say for this application, from the last pass. Right-aligned
   and not allowed to shrink, because it is the column somebody scans down when
   they are wondering which application has stopped moving. */
.faucet-source-books {
    flex: none;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    color: var(--ink-soft);
    white-space: nowrap;
}

.faucet-keyrow {
    display: flex;
    align-items: center;
    gap: 8px;
}

.faucet-keyline {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 11px;
    line-height: 1.4;
    color: #3a3a3a;
}

.paleos-button.is-small {
    min-width: 0;
    padding: 1px 8px;
    font-size: 11px;
}

/* phraseDialog's `extras` slot: whatever the decision needs, above the field.
   Spaced away from the paragraph above and the field below, because a checkbox
   crowded against either reads as part of it rather than as a choice. */
.phrase-extras {
    margin: 8px 0 2px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* The passphrase dialog's two fields. */
.key-form {
    margin: 10px 0 8px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.key-form .paleos-input { width: 100%; }

/* ---- Backups, an applet of Faucet's -------------------------------------

   The same column as Faucet's own window, for the same reason: the number of
   rows is the number of applications that can sync plus however many copies
   the server is holding, so nothing here can know its height in advance. */
.bk-wrap {
    height: 100%;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    padding: 13px 13px 10px;
}

.bk-app {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding-right: 4px;
}

.bk-wrap > .paleos-button-row { flex: none; margin-bottom: 0; }

.bk-head-row {
    display: flex;
    align-items: center;
    gap: 11px;
}

.bk-head {
    margin: 10px 0 4px;
    font-size: var(--ui-small);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-soft);
}

.bk-head:first-child { margin-top: 0; }

/* ---- two copies disagree ----

   Faucet has stopped and is waiting for an answer, so this reads as a held
   state rather than as another section of a list: boxed, with the warning
   colour the halt screens use, and at the top of the window because a question
   somebody has to scroll to is a question that goes unanswered. Hidden
   entirely when there is nothing to resolve, which is almost always. */
.bk-split {
    border: 1px solid var(--warn-edge, #8a6a2a);
    background: var(--warn-fill, #2a2112);
    padding: 10px 12px;
    margin-bottom: 12px;
}

.bk-split .bk-head { color: var(--warn-ink, #e8c88a); }

.bk-split .paleos-button-row { margin-bottom: 0; }

/* ---- what a backup holds ---- */

.bk-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 0;
    font-size: var(--ui-size);
}

.bk-name { flex: none; min-width: 108px; font-family: var(--ui-font); }

.bk-state { flex: 1 1 auto; min-width: 0; color: var(--ok); }

/* NOT covered is the line somebody came here to find, so it is the one thing
   in this window drawn in the warning colour. */
.bk-state.is-off { color: var(--danger); font-weight: 700; }

.bk-add { flex: none; }

.bk-quiet {
    margin: 6px 0 0;
    font-size: var(--ui-small);
    line-height: 1.45;
    color: var(--ink-faint);
}

/* ---- one copy ---- */

.bk-backup {
    background: var(--doc);
    box-shadow: var(--sink-1);
    margin: 0 0 6px;
    padding: 6px 8px 7px;
}

.bk-backup-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
}

.bk-when { font-size: var(--ui-size); font-weight: 700; }

.bk-size {
    flex: none;
    font: 11px/1.4 var(--mono-font);
    color: var(--ink-faint);
}

/* Why the copy exists, when it exists for a reason. A daily copy has no line
   here at all rather than one saying "daily", which the heading above it has
   already said. */
.bk-why {
    margin-top: 1px;
    font-size: var(--ui-small);
    color: var(--ink-soft);
}

.bk-acts { margin: 5px 0 0; justify-content: flex-start; }

.bk-note {
    flex: none;
    margin: 8px 0 0;
    font-size: var(--ui-small);
    line-height: 1.45;
    color: var(--ink-soft);
}

.bk-note.is-ok { color: var(--ok); }
.bk-note.is-error { color: var(--danger); font-weight: 700; }

/* =============================================================================
   19h  THE INSTALLER, PREFERENCES AND PaleProfile
   =============================================================================

   Three windows that did not exist before the kernel did. The installer is a
   full-screen shell like the login panel, because it is the only thing on
   screen; Preferences and PaleProfile are ordinary windows with a tab strip down
   the top, which is the shape a control panel wants.
   ========================================================================== */

.install-shell {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--paleos-desktop, #336698);
    padding: 24px 16px;
    overflow: auto;
    z-index: 96000;
}

.install-window { width: min(560px, 100%); }
.install-content { padding: 16px 18px 18px; }

.install-step {
    font-family: var(--mono-font);
    font-size: 10px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #6a6a6a;
    margin: 0 0 10px;
}

.install-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 10px;
}

.install-title {
    font-family: var(--ui-font);
    font-size: 16px;
    font-weight: bold;
    margin: 0 0 4px;
}

.install-sub { font-size: 11px; color: #5a5a5a; margin: 0; }

.install-text {
    font-size: 12px;
    line-height: 1.55;
    margin: 0 0 10px;
    max-width: 58ch;
}

.install-note {
    font-size: 11px;
    line-height: 1.5;
    color: #5a5a5a;
    margin: 8px 0 0;
    max-width: 58ch;
}

.install-note.is-error { color: #a01010; }

.install-list {
    margin: 0 0 12px;
    padding-left: 18px;
    font-size: 12px;
    line-height: 1.55;
    max-width: 58ch;
}

.install-list li { margin-bottom: 6px; }

.install-choices {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 12px 0;
}

/* Each choice is a button the size of the sentence explaining it, because the
   explanation is the part somebody is actually choosing between. */
.install-choice {
    display: block;
    width: 100%;
    text-align: left;
    padding: 10px 12px;
    background: #e8e8e8;
    border: 1px solid #8a8a8a;
    box-shadow: inset -1px -1px 0 #9a9a9a, inset 1px 1px 0 #ffffff;
    cursor: pointer;
    font-family: var(--ui-font);
}

.install-choice:hover { background: #f0f0f0; }
.install-choice:active { box-shadow: inset 1px 1px 0 #9a9a9a, inset -1px -1px 0 #ffffff; }
.install-choice.is-default { border-color: #1b2f4a; border-width: 2px; }
.install-choice strong { display: block; font-size: 13px; margin-bottom: 3px; }
.install-choice span { display: block; font-size: 11px; line-height: 1.45; color: #4a4a4a; }

/* A volume row in the installer: icon on the left, name and capacity on the
   right, the way a disk has been listed by every installer since they existed. */
.install-volume {
    display: flex;
    align-items: center;
    gap: 11px;
    text-align: left;
}

.install-volume img { flex: 0 0 auto; image-rendering: pixelated; }

/* Fresh start, or from an export. The same row as a volume — it is the same
   kind of choice, made on the same screen — with one difference: the restore
   row is drawn disabled when there is nothing in the drive to restore from,
   rather than left out. An option that is absent reads as "PaleOS cannot do
   this"; one that is there and greyed with its reason reads as "the disk is
   the problem", which is the true and more useful sentence. */
.install-subtitle {
    font-family: var(--ui-font);
    font-size: 13px;
    font-weight: bold;
    margin: 16px 0 0;
}

.install-source {
    display: flex;
    align-items: center;
    gap: 11px;
    text-align: left;
}

.install-source img { flex: 0 0 auto; image-rendering: pixelated; }

.install-source[disabled] {
    cursor: default;
    background: #dedede;
    color: #6a6a6a;
}

.install-source[disabled] strong,
.install-source[disabled] span { color: #6a6a6a; }
.install-source[disabled] img { opacity: 0.55; }

/* A second and third export on the same disk sit under the first, smaller:
   the first is the offer, the rest are there for when it is the wrong one. */
.install-source.is-more { padding: 7px 12px; }
.install-source.is-more strong { font-size: 12px; font-weight: normal; }

.install-restore-name {
    font-family: var(--mono-font);
    font-size: 11px;
    color: #1b2f4a !important;
}

.install-restore-note { margin-top: 10px; }

/* The list is a drop target: an export dragged onto it lands on the disk in
   the drive and is chosen. Dashed while the pointer is over it, the same
   language the desktop uses for a folder being dropped on it — one gesture,
   one way of saying "this will be taken". */
.install-restore.is-drop-target {
    outline: 2px dashed var(--paleos-tab, #ffcb00);
    outline-offset: 2px;
}

.install-drop-hint {
    margin: 0;
    align-self: center;
}
.install-restored { color: #1d5c2c; }

.install-volume-text { display: block; min-width: 0; }
.install-volume-text strong { margin-bottom: 2px; }

.install-volume-size {
    font-family: var(--mono-font);
    font-size: 10px;
    color: #3b5a80;
    margin-top: 3px;
}

.install-choice.is-disabled,
.install-choice:disabled {
    opacity: 0.55;
    cursor: default;
    background: #e4e4e4;
}

.install-choice.is-disabled:hover,
.install-choice:disabled:hover { background: #e4e4e4; }

/* ---- Preferences and PaleProfile ------------------------------------------------ */

.prefs-app {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.prefs-tabs {
    display: flex;
    gap: 2px;
    padding: 6px 8px 0;
    border-bottom: 1px solid #8a8a8a;
    flex: 0 0 auto;
}

.prefs-tab {
    font-family: var(--ui-font);
    font-size: 11px;
    padding: 3px 10px;
    background: #c8c8c8;
    border: 1px solid #8a8a8a;
    border-bottom: 0;
    cursor: pointer;
}

.prefs-tab.is-active { background: #e8e8e8; font-weight: bold; }

.prefs-pane {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding: 12px 14px 14px;
}

.prefs-lede {
    font-size: 12px;
    line-height: 1.55;
    margin: 0 0 12px;
    max-width: 62ch;
}

.prefs-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.prefs-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 8px;
    background: #efefef;
    border: 1px solid #d0d0d0;
}

.prefs-row-body { flex: 1 1 auto; min-width: 0; }

.prefs-row-title {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
    font-size: 12px;
    font-weight: bold;
}

.prefs-row-sub { font-size: 11px; line-height: 1.45; color: #4a4a4a; }
.prefs-row-sub.is-dim { color: #7a7a7a; font-family: var(--mono-font); font-size: 10px; }

.prefs-row-actions { display: flex; gap: 4px; flex: 0 0 auto; }

/* ---- a preview window ---------------------------------------------------

   The piece as it will read. Deliberately NOT the site's own typography: a
   preview that looked exactly like the published page would be a preview a
   member could mistake for one, and the banner is doing that work on its own
   only if the page under it does not argue with it. So this is the system's
   document face — the same one PaleEdit and the reader pane use — at a
   comfortable reading measure. */
.preview-banner {
    display: flex;
    gap: 8px;
    align-items: baseline;
    padding: 5px 8px;
    background: var(--tab);
    border-bottom: 1px solid var(--panel-dark);
    font-size: 11px;
    line-height: 1.4;
}

.preview-banner strong { flex: none; }

.preview-page {
    padding: 14px 18px 22px;
    overflow: auto;
    background: var(--doc);
    /* A measure, not the full window width. A line of text the width of a
       zoomed window is a line nobody can follow back to its start. */
    max-width: 46em;
}

.preview-title {
    font-size: 17px;
    margin: 0 0 10px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--panel-dark);
}

.preview-body { font-size: var(--ui-size); line-height: 1.5; }
.preview-body h1, .preview-body h2, .preview-body h3,
.preview-body h4, .preview-body h5, .preview-body h6 { margin: 14px 0 6px; }
.preview-body p { margin: 0 0 10px; }
.preview-body blockquote {
    margin: 0 0 10px;
    padding: 2px 10px;
    border-left: 3px solid var(--panel-dark);
    color: #4a4a4a;
}
.preview-body pre {
    margin: 0 0 10px;
    padding: 8px;
    overflow: auto;
    background: var(--panel);
    border: 1px solid var(--panel-dark);
    box-shadow: var(--sink-1);
    font-family: var(--mono-font);
    font-size: 11px;
}
.preview-body code { font-family: var(--mono-font); font-size: 11px; }
.preview-body ul, .preview-body ol { margin: 0 0 10px; padding-left: 22px; }
.preview-body img { max-width: 100%; height: auto; }

/* A LINK THAT DOES NOT OPEN still has to look like a link, because the point
   of reading a preview is to check what you wrote — including that you meant
   to put a link there. It is underlined and coloured as one, and dotted
   underneath to say it is not live; the address is in its title attribute. */
.preview-body a.is-inert {
    color: #003c8c;
    text-decoration: underline;
    text-decoration-style: dotted;
    cursor: help;
}

/* The Defaults panel's second section. A divider and a heading rather than a
   second window, because the system choices are the same kind of setting as
   the file rows above them and come out of the same record — but they govern
   the system rather than a file type, and the eye needs telling where one
   list stops.

   The divider is the same two-tone bevel the dock's own divider uses, so a
   line drawn inside a panel reads as part of the same system rather than as
   a rule somebody added. */
.prefs-divider {
    height: 0;
    margin: 10px 0 2px;
    border-top: 1px solid var(--panel-dark);
    border-bottom: 1px solid var(--panel-light);
}

.prefs-heading {
    font-size: var(--ui-size);
    font-weight: bold;
    color: var(--ink);
    padding: 2px 0 4px;
}

/* A row whose control is a set of checkboxes rather than one dropdown. The
   column stays narrow so the title and sub-line keep the width they have in
   every other row — a row that reflows its neighbours because its control is
   a different shape is a row that makes the list look broken. */
.prefs-check-row {
    display: flex;
    flex-direction: column;
    gap: 3px;
    flex: 0 0 auto;
    max-width: 190px;
}

/* Wrapped, for the application list, which is as long as the volume's
   application list and would otherwise make the panel tall enough to scroll
   past the footer. */
.prefs-check-row.is-wrap {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 2px 10px;
    max-width: 230px;
}

.prefs-check-row .paleos-check { font-size: 11px; }

/* A checkbox switched off because the cap is reached reads as unavailable
   rather than as broken: the label dims with it, which is the one visible
   difference between "you cannot have this" and "nothing happened". */
.prefs-check-row input:disabled + span { color: #8a8a8a; }

.prefs-file {
    font-family: var(--mono-font);
    font-size: 10px;
    font-weight: normal;
    color: #6a6a6a;
}

.prefs-badge {
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    background: #3b6fb5;
    color: #fff;
    padding: 1px 5px;
}

.profile-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 4px;
}

.profile-picture {
    border: 1px solid #55565a;
    background: #d8d8d8;
    object-fit: cover;
}

.profile-thumb {
    border: 1px solid #8a8a8a;
    background: #d8d8d8;
    object-fit: cover;
    flex: 0 0 auto;
}

/* The one control on somebody else's masthead. */
.ws-friend { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.ws-friend-note { font-size: 11px; color: #6a6a6a; font-style: italic; }

/* A kernel-backed file in a folder listing. Shown, never editable. */
.paleos-list-row[data-kind="sysfile"] .paleos-list-cell:first-child { color: #3a3a3a; }

/* The generated passphrase, in the key dialog. Shown as a block of monospace
   with room to breathe: it is meant to be read off the screen and copied onto
   paper, and four hyphenated pairs run together are unreadable at body size. */
.key-made {
    border: 1px solid #c0c0c0;
    background: #efefef;
    padding: 9px 10px 8px;
    margin: 10px 0 6px;
}

.key-phrase {
    display: block;
    font-family: var(--mono-font);
    font-size: 13px;
    line-height: 1.6;
    letter-spacing: 0.02em;
    word-spacing: 0.35em;
    color: #101010;
    background: #fff;
    border: 1px solid #c0c0c0;
    padding: 7px 8px;
    margin: 4px 0 7px;
    user-select: all;
    overflow-wrap: break-word;
}

.paleos-button-row.is-tight { margin: 0; gap: 6px; }

/* Get Info, and the bar that says how full PaleHD is. A disk gauge earns its
   place by being readable at a glance: one bar, one colour that changes only
   when it matters, and the numbers spelled out underneath for anyone who wants
   the real figure rather than an impression. */
.prefs-info { margin: 0 0 10px; }

.disk-bar {
    height: 14px;
    border: 1px solid #55565a;
    background: #fff;
    box-shadow: inset 1px 1px 0 #9a9a9a;
    margin: 6px 0 5px;
    overflow: hidden;
}

.disk-bar-fill {
    height: 100%;
    background: #3b6fb5;
    transition: width 180ms linear;
}

.disk-bar[data-state="warn"] .disk-bar-fill { background: #f0c020; }
.disk-bar[data-state="full"] .disk-bar-fill { background: #d02020; }

/* The volume list in the installer gains a third kind of row, and the erase
   choice sits under it rather than beside it. */
.install-erase {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 8px 2px 0;
    font-size: 12px;
}

/* Reader mode. One window, and a strip that says what this is. The desktop
   element is reused so the backdrop and window machinery work unchanged, but
   everything that makes it a desktop — icons, the Deskbar — is simply never
   drawn, and the strip takes the Deskbar's place at the top. */
.paleos-desktop.is-reader .desktop-icons,
.paleos-desktop.is-reader .paleos-dock { display: none !important; }

.reader-bar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 30px;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 8px;
    background: var(--paleos-panel, #d8d8d8);
    border-bottom: 1px solid #55565a;
    box-shadow: inset 0 1px 0 #f4f4f4, 0 1px 0 #9a9a9a;
    z-index: 90000;
    font-size: 11px;
}

.reader-bar-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.reader-bar-text strong { font-family: var(--ui-font); }

/* The one window sits under the strip rather than behind it. */
.paleos-desktop.is-reader .paleos-window { top: 38px !important; }

/* -----------------------------------------------------------------------------
   ABOUT, AND THE CHANGELOG
   A system that can be installed and updated has to be able to say what it is.
   About is a window rather than an alert because the version table is scrolled
   and clicked, and the changelog is read the way release notes are read: top
   down, newest first.
   -------------------------------------------------------------------------- */

/* Both of these fill their window and scroll inside it. A panel that spills
   past the frame is the one thing a window manager must never allow, and
   neither of these has a length anybody can predict: the version table grows
   with the system, and the changelog grows with every release. */
.changelog {
    height: 100%;
    overflow: auto;
    box-sizing: border-box;
}

/* About is a column: the content scrolls, the buttons do not. */
.about-panel {
    height: 100%;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    padding: 2px 2px 2px 2px;
}

.about-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding-right: 4px;
}

.about-panel > .paleos-button-row { flex: none; margin-bottom: 0; }

.about-head {
    display: flex;
    align-items: center;
    gap: 11px;
    margin: 2px 0 4px;
}

.about-head img { flex: none; image-rendering: auto; }

.about-name {
    font-family: var(--ui-font);
    font-size: 17px;
    font-weight: 700;
    letter-spacing: 0.1px;
    line-height: 1.1;
}

.about-release { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
.about-site { font-size: 11px; color: var(--ink-faint); margin-top: 1px; }

.about-line { font-size: 12px; margin: 3px 0; }

/* The version table. Every row is a button, because every row opens that
   part's own About — so it has to look and behave like something you press. */
.about-versions {
    background: var(--doc);
    box-shadow: var(--sink-1);
    max-height: 184px;
    overflow: auto;
    margin: 4px 0 3px;
}

.about-versions .paleos-list-row { width: 100%; }
.about-versions .paleos-list-cell.is-meta { width: 86px; flex: none; text-align: left; }
.about-versions .paleos-list-cell.is-meta:last-child { width: 62px; text-align: right; }

.about-hint { font-size: 11px; color: var(--ink-faint); margin: 0 0 2px; }

.about-notice { font-size: 11px; margin: 4px 0 2px; }
.about-small { font-size: 10px; color: var(--ink-faint); margin: 2px 0; line-height: 1.45; }

.changelog { padding: 2px 6px 10px 2px; }

.changelog-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin: 10px 0 2px;
    padding-bottom: 3px;
    border-bottom: 1px solid var(--panel-shadow);
}

.changelog-head:first-child { margin-top: 2px; }

.changelog-version {
    font-family: var(--ui-font);
    font-size: 14px;
    font-weight: 700;
}

.changelog-name { font-size: 12px; color: var(--ink-soft); flex: 1 1 auto; }
.changelog-date { font-size: 11px; color: var(--ink-faint); flex: none; }

.changelog-summary { font-size: 12px; margin: 4px 0 6px; }

.changelog-group {
    font-family: var(--ui-font);
    font-size: 11px;
    font-weight: 700;
    margin: 8px 0 2px;
}

.changelog-list { margin: 0 0 4px; padding-left: 17px; }
.changelog-list li { font-size: 12px; line-height: 1.5; margin: 1px 0; }

/* Preferences shows a version beside every appliance and service, and an Info
   button that opens the same About panel the version table does. */
.prefs-version {
    flex: none;
    width: 50px;
    text-align: right;
    font-size: 11px;
    color: var(--ink-faint);
}

.paleos-list-row.is-selected .prefs-version { color: #dfe7f5; }

/* -----------------------------------------------------------------------------
   WHEN THE SYSTEM HAS LOST FILES
   A browser can take PaleOS's storage with the cookies, so the system has to
   be able to say so. These are the three places it says it: the volume's own
   icon, a ribbon at the top of PaleFiles, and a panel in Preferences. All three
   are the same red and the same wording, because somebody who sees one of
   them will go looking for the others.
   -------------------------------------------------------------------------- */

/* The disk's icon wears it. Red rather than yellow: yellow is the colour of
   this system's furniture, and a warning has to be a different thing. */
/* An application with something waiting. The badge is the same one the Trash
   and a damaged PaleHD use, in the colour that means "attend to this" rather
   than "something is wrong": blue, not red. */
.desktop-icon.has-waiting .desktop-icon-badge {
    background: #3b6fb5;
    border-color: #1f4a84;
    color: #ffffff;
}

.desktop-icon.has-waiting .desktop-icon-label { font-weight: 700; }

.desktop-icon.needs-repair .desktop-icon-badge {
    background: #d02020;
    border-color: #6a0d0d;
    color: #fff;
}

.desktop-icon.needs-repair .desktop-icon-label {
    background: #b4231f;
    color: #fff;
}

/* Waiting for the server is not damage, so it is quieter: the label goes to
   the system's own blue rather than to red, and there is no badge. */
.desktop-icon.is-waiting .desktop-icon-label {
    background: #3b5f99;
    color: #fff;
}

.pf-alarm {
    display: flex;
    align-items: center;
    gap: 9px;
    margin: 0 0 8px;
    padding: 6px 8px;
    border: 1px solid #8c1a17;
    background: #ffe9e7;
    box-shadow: inset 0 1px 0 #fff6f5;
    font-size: 11px;
}

.pf-alarm-text { flex: 1 1 auto; }
.pf-alarm-text strong { font-family: var(--ui-font); }

/* Preferences gets two: the alarm, for damage that has happened, and the caution,
   for damage that has not happened yet. They look different on purpose — a
   warning that looks identical to a standing notice gets read as wallpaper. */
.prefs-alarm,
.prefs-caution {
    margin: 10px 0;
    padding: 8px 10px;
    border: 1px solid var(--panel-dark);
    box-shadow: inset 1px 1px 0 var(--panel-hi);
}

.prefs-alarm {
    border-color: #8c1a17;
    background: #ffe9e7;
}

.prefs-caution {
    border-color: #a98a1c;
    background: #fff8e0;
}

.prefs-alarm .alert-headline,
.prefs-caution .alert-headline { margin: 0 0 4px; font-size: 12px; }

.prefs-alarm .alert-text,
.prefs-caution .alert-text { margin: 3px 0; font-size: 11px; line-height: 1.5; }

/* A Get Info value that is reporting a condition rather than a fact. */
.ps-value.is-warn { color: #a81713; font-weight: 700; }
.ps-value.is-ok { color: var(--ink-soft); }

/* -----------------------------------------------------------------------------
   THE WELCOME TOUR
   One picture and one idea per card. The drawing is the size it is because it
   has to read at a glance without anybody leaning in.
   -------------------------------------------------------------------------- */

.tour-art {
    margin: 0 0 14px;
    line-height: 0;
    box-shadow: var(--sink-1);
    background: var(--paleos-desktop, #336698);
}

.tour-art svg { display: block; width: 100%; height: auto; }

.tour-title { margin: 0 0 7px; font-size: 17px; }

.tour-dots {
    display: flex;
    justify-content: center;
    gap: 7px;
    margin: 16px 0 2px;
}

.tour-dot {
    width: 9px;
    height: 9px;
    padding: 0;
    border: 1px solid var(--panel-dark);
    border-radius: 50%;
    background: var(--panel);
    box-shadow: var(--sink-1);
    cursor: pointer;
}

.tour-dot.is-here {
    background: var(--sel);
    border-color: var(--panel-darkest);
    box-shadow: none;
}

.tour-dot:focus-visible { outline: 1px dotted var(--ink); outline-offset: 2px; }

/* The two appliances Preferences sets itself, rather than handing to an app. */
.prefs-settings { padding: 12px 13px 10px; }

.prefs-swatches { display: flex; gap: 6px; flex-wrap: wrap; }

.prefs-swatch {
    width: 22px;
    height: 22px;
    padding: 0;
    border: 1px solid var(--panel-darkest);
    box-shadow: var(--raise-1);
    cursor: pointer;
}

.prefs-swatch:active { box-shadow: var(--sink-1); }

/* -----------------------------------------------------------------------------
   PALEREADER
   A page of a PDF, as text. The paper is white and has a measure, because this
   is for reading rather than for inspecting a file.
   -------------------------------------------------------------------------- */

.pr-app {
    height: 100%;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    background: var(--panel);
}

.pr-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    background: var(--doc);
    box-shadow: var(--sink-1);
    margin: 8px;
}

.pr-paper {
    /* About 68 characters at this size, which is where a line stops being
       comfortable. The page is centred in whatever width the window has. */
    max-width: 34em;
    margin: 0 auto;
    padding: 20px 22px 26px;
}

.pr-line {
    margin: 0 0 9px;
    font-size: 12.5px;
    line-height: 1.55;
    text-align: left;
}

.pr-gap { height: 7px; }

.pr-paper .paleos-list-empty { padding: 26px 0; }

/* -----------------------------------------------------------------------------
   FAUCET: THE TAP THAT DRIPS, AND THE TWO PANES
   The tap is the status indicator. It drips while something is being sent and
   stands still when nothing is, which is a thing you can read without reading.
   -------------------------------------------------------------------------- */

/* A field inside an alert, for the one thing an alert sometimes has to ask
   for: a phrase typed back before something irreversible happens. */
.alert-fields {
    margin: 9px 0 4px;
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.alert-fields .paleos-input { max-width: 240px; }

/* The quiet button: present, findable, and not competing with anything. */
.paleos-button.is-quiet {
    min-width: 0;
    color: var(--ink-soft);
    font-size: 11px;
}

.paleos-button.is-quiet:hover { color: var(--danger); }

.faucet-drip {
    flex: none;
    display: block;
    width: 32px;
    height: 40px;
    line-height: 0;
}

.faucet-drop {
    /* Parked inside the spout and invisible until there is something to say. */
    opacity: 0;
}

.faucet-drip[data-on="yes"] .faucet-drop {
    animation: faucet-fall 2.2s linear infinite;
}

/* One drop, forming at the spout and falling away. The long still gap at the
   end is deliberate: a tap that drips continuously reads as a fault, and this
   one is meant to read as working. */
@keyframes faucet-fall {
    0%   { opacity: 0; transform: translateY(0) scale(0.4); }
    12%  { opacity: 1; transform: translateY(0) scale(1); }
    30%  { opacity: 1; transform: translateY(10px) scale(0.95); }
    44%  { opacity: 0; transform: translateY(17px) scale(0.75); }
    100% { opacity: 0; transform: translateY(17px) scale(0.75); }
}

.faucet-pane {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    padding-right: 4px;
}

.faucet-server { padding: 2px 0; }

@media (prefers-reduced-motion: reduce) {
    .faucet-drip[data-on="yes"] .faucet-drop { animation: none; opacity: 1; }
}

@media (max-width: 620px) {
    .reader-bar-text span { display: none; }
}

@media (max-width: 760px) {
    .install-window { width: 100%; }
    .install-content { padding: 12px 12px 14px; }
    .prefs-row { flex-wrap: wrap; }
    .prefs-row-actions { width: 100%; }

    .denied-content,
    .error-content { flex-direction: column; gap: 12px; }

    .denied-art, .error-art { align-self: center; }

    /* The Deskbar used to lie across the top of a narrow screen, which is why
       the icons started 36px down. With it gone they start at the top and stop
       short of the bottom edge instead, where the dock is. */
    .desktop-icons {
        top: 8px;
        bottom: 44px;
        overflow-y: auto;
        left: 0;
        right: 0;
        gap: 4px 0;
        padding: 0 6px;
    }

    .window-layer {
        position: absolute;
        top: 120px;
        right: 0;
        bottom: 0;
        left: 0;
        overflow-y: auto;
        padding: 0 8px 20px;
    }

    .paleos-window {
        position: relative !important;
        left: auto !important;
        top: auto !important;
        width: 100% !important;
        height: auto !important;
        min-height: 60vh;
        margin-bottom: 12px;
    }

    .window-resize { display: none; }

    .np-viewport { --np-pad: 15px; padding: 14px var(--np-pad) 26px; }
    .document-content { padding: 18px 16px 24px; }
    .document-title { font-size: 22px; }

    .mail-sidebar,
    .notes-list { width: 104px; }

    .rx-app { flex-wrap: wrap; }
    .rx-sidebar { width: 128px; }
    .rx-card { flex-basis: 100%; order: 3; min-height: 300px; }
    .rx-label { width: 52px; }

    .bg-body { flex-direction: column; align-items: stretch; }
    .bg-monitor { align-self: center; }

    .press-app { flex-wrap: wrap; }
    .press-sidebar { width: 124px; }
    .press-main { flex-basis: 100%; order: 3; min-height: 320px; }
    .press-panes { flex-direction: column; }
}

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
}

@media print {
    .paleos-dock, .desktop-icons, .window-tabrow,
    .window-statusbar, .window-menubar, .paleos-boot, .login-shell { display: none !important; }

    body.paleos-body { overflow: visible; background: #fff; }

    .window-frame { border: 0; box-shadow: none; padding: 0; }
    .document-shell { max-width: none; padding: 0; }
    .gh-content { font-size: 11pt; }
}

/* The duration choice in the Stay Unlocked dialog. */
.hold-span {
    display: flex;
    align-items: baseline;
    gap: 7px;
    padding: 3px 0;
    font-size: 13px;
}
.hold-span input { flex: none; align-self: center; }


/* ===========================================================================
   THE DOCK
   ===========================================================================

   One strip centred on the bottom edge, always there. Minimized windows on the
   left, then a divider, then the tray and Log Out and Shut Down.

   It replaces the Deskbar, which was a VERTICAL strip in the top-right with
   room for names beside each icon. A horizontal strip has no such room, so the
   dock shows icons only — the title is on the hover, and the overflow menu
   spells them out.
   ======================================================================== */

.paleos-dock {
    position: absolute;
    bottom: 6px;
    left: 50%;
    display: flex;
    gap: 6px;
    align-items: center;
    padding: 4px;
    background: var(--panel);
    box-shadow: var(--raise-1);
    transform: translateX(-50%);
    /* Under the alert layer, above the windows: a minimized
       window must not be restorable from behind a modal. */
    z-index: 89000;
    user-select: none;
}

/* ALWAYS DRAWN. Log Out and Shut Down are on it and are wanted at all times,
   so the strip does not come and go — only the minimized windows on its left
   do, and the divider with them. An earlier version hid the whole strip when
   nothing was minimized, which was right while it held nothing else. */
.dock-windows,
.dock-fixed {
    display: flex;
    gap: 6px;
    align-items: center;
}

.dock-windows:empty { display: none; }

/* A groove rather than a line: the same inset bevel every divider in the
   system uses, so it reads as part of the panel and not as a border somebody
   drew on it. */
.dock-divider {
    flex: none;
    align-self: stretch;
    width: 2px;
    margin: 2px 1px;
    box-shadow: var(--sink-1);
}

.dock-divider[hidden] { display: none; }

.dock-item {
    position: relative;
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--panel-darkest);
    background: var(--panel);
    box-shadow: var(--raise-1);
    cursor: default;
}

.dock-item:active { box-shadow: var(--sink-1); }
.dock-item img { display: block; pointer-events: none; }

.dock-more-count {
    font-size: 10px;
    font-weight: 700;
    color: var(--ink);
}

/* The SAME SIZE as a minimized window's icon. These were smaller for a round,
   on the reasoning that they are not windows and should not read as one — but
   a strip of 30px icons with two 22px ones on the end reads as a strip that
   has been patched, and the size difference says "lesser" about the two
   controls that end the session. One size, one row.

   Glyphs rather than labels: two words on the strip of every screen is two
   words a person reads once and then never again. */
.dock-system {
    position: relative;
    flex: none;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--panel-darkest);
    background: var(--panel);
    box-shadow: var(--raise-1);
    cursor: default;
}

.dock-system:active { box-shadow: var(--sink-1); }

/* All Windows: the same size as a minimized window's icon, because what it
   opens is about windows and it should read as belonging with them rather than
   with the two system buttons it happens to sit beside. */
.dock-all {
    position: relative;
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--panel-darkest);
    background: var(--panel);
    box-shadow: var(--raise-1);
    cursor: default;
}

.dock-all:active { box-shadow: var(--sink-1); }

/* Three window frames, as the application's own icon has. Drawn rather than
   fetched: at this size an SVG request would cost more than the six rules
   that draw it, and these have to match the glyph in PaleFiles' status bar
   exactly — one picture for one idea, in both places it appears. */
.dock-all::before,
.dock-all::after {
    content: "";
    position: absolute;
    width: 13px;
    height: 10px;
    border: 1px solid var(--ink);
    /* The tab along the top, as a PaleOS window has. */
    border-top-width: 3px;
    background: var(--panel);
}

.dock-all::before { left: 5px; top: 6px; }
.dock-all::after { right: 5px; bottom: 6px; }

/* Log Out: a door. Shut Down: the power ring, open at the top. */
#dock-logout::before,
#dock-logout::after,
#dock-shutdown::before,
#dock-shutdown::after {
    content: "";
    position: absolute;
}

/* Retuned for 30px: the same two shapes, drawn further out. */
#dock-logout::before {
    inset: 6px 10px 6px 7px;
    border: 1px solid var(--ink);
    border-right: none;
}

#dock-logout::after {
    top: 14px;
    right: 7px;
    width: 6px;
    height: 1px;
    background: var(--ink);
    box-shadow: 1px -3px 0 var(--ink), 1px 3px 0 var(--ink);
}

#dock-shutdown::before {
    inset: 7px;
    border: 1px solid var(--ink);
    border-radius: 50%;
    clip-path: polygon(0 22%, 40% 22%, 40% 0, 60% 0, 60% 22%, 100% 22%, 100% 100%, 0 100%);
}

#dock-shutdown::after {
    top: 6px;
    left: 50%;
    width: 1px;
    height: 9px;
    background: var(--ink);
    transform: translateX(-50%);
}


/* ===========================================================================
   WINDOWS — everything you have open
   ===========================================================================

   A grid of tiles rather than a list of rows. The brief was Exposé: you look,
   you spot the one you want, you click it — and scanning a grid is the faster
   motion for that than reading a column top to bottom.

   Each tile is the application's icon, large, with the window's own title
   under it and its state in one word. NOT a live miniature: a real one would
   mean cloning and scaling each window's DOM, which works for a window made of
   ordinary elements and comes out BLANK for the Terminal, for PaleReader and
   for anything in a frame. A grid where some tiles show the real thing and
   others are empty rectangles is worse than one where none of them pretend to.
   ======================================================================== */

.winx-app {
    height: 100%;
    overflow: auto;
    padding: 10px;
}

.winx-grid {
    display: grid;
    /* Tiles take what they need and the row fills out; the window can be
       dragged narrow without the tiles deforming. */
    grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
    gap: 8px;
    align-content: start;
}

.winx-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 10px 6px 8px;
    border: 1px solid var(--panel-darkest);
    background: var(--panel);
    box-shadow: var(--raise-1);
    cursor: default;
    text-align: center;
    overflow: hidden;
}

.winx-tile:active { box-shadow: var(--sink-1); }

/* The one in front wears the window tab's own yellow, which is the colour the
   system already uses to mean "this is the active window". */
.winx-tile.is-active { background: var(--tab); }

/* Put away: dimmed, the way the dock's own icons are not — here the tile has
   to carry the difference on its own, because unlike the dock this grid holds
   both kinds at once. */
.winx-tile.is-minimized .winx-thumb img { opacity: 0.45; filter: grayscale(1); }

.winx-thumb {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
}

.winx-thumb img { display: block; pointer-events: none; }

.winx-name {
    width: 100%;
    font-size: var(--ui-size);
    line-height: 1.25;
    /* Two lines, then an ellipsis. A window title can be a whole filename and
       a tile that grew to fit one would break the grid's rhythm. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
}

.winx-state {
    font-size: 10px;
    color: var(--ink-soft);
}

.winx-tile.is-active .winx-state { color: #6a5200; }

/* The close box, in the tile's own top-right corner. Its own button, so the
   two actions never collide: the tile raises, this closes. One control that
   did both depending on where you hit it is the arrangement that loses
   somebody's work. */
.winx-close {
    position: absolute;
    top: 3px;
    right: 3px;
    width: 14px;
    height: 14px;
    padding: 0;
    border: 1px solid var(--panel-darkest);
    background: var(--panel);
    box-shadow: var(--raise-1);
    cursor: default;
}

.winx-close:active { box-shadow: var(--sink-1); }

.winx-close::before,
.winx-close::after {
    content: "";
    position: absolute;
    top: 5px;
    left: 2px;
    width: 8px;
    height: 1px;
    background: var(--ink);
}

.winx-close::before { transform: rotate(45deg); }
.winx-close::after { transform: rotate(-45deg); }


/* =============================================================================
   21  PALEBIOS
   =============================================================================

   The firmware's screen, and the only part of PaleOS that is not a BeOS
   desktop. It is a boot screen: black, monospaced, left-aligned, and sized so
   thirteen check lines and a picker both fit a phone without scrolling.

   WHY IT DOES NOT USE THE PANEL BEVEL. Everything else here is mixed from the
   three root colours set in Ghost Admin, and this deliberately is not. A
   firmware screen has to be legible when the thing it is reporting on has
   failed, and the panel ramp depends on color-mix, custom properties and a
   theme setting — three things that are fine on a working machine and are
   exactly what POST exists to doubt. Four literal greys and a monospace stack
   with five fallbacks will render on anything.

   IT IS ALSO THE FIRST THING A READER OF THE SITE SEES, which is why the
   healthy case is a wordmark and one line. The thirteen lines are what a
   machine with something to say gets, and nobody has to ask for them.
   ========================================================================== */

.palebios {
    position: fixed;
    inset: 0;
    z-index: 99500;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    padding: 24px 16px;
    overflow: auto;
    background: #000;
    color: #cfcfcf;
    font-family: var(--mono-font);
    font-size: 12px;
    line-height: 1.5;
    /* Selectable on purpose: a member reading a code down the phone to
       somebody wants to be able to copy it. */
    -webkit-font-smoothing: antialiased;
}

/* Above the installer (96000) and the desktop, below the boot splash's 99000
   only in the one case where both are up — which screen() prevents by hiding
   the splash rather than racing it. */

.palebios-wordmark {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.22em;
    color: #fff;
    margin-bottom: 10px;
}

/* ---- the healthy case: a mark and one line ------------------------------- */

.palebios-mark { text-align: center; }

.palebios-mark .palebios-wordmark { margin-bottom: 8px; }

.palebios-line {
    color: #8f8f8f;
    letter-spacing: 0.04em;
}

/* ---- the thirteen lines -------------------------------------------------- */

.palebios-post {
    width: min(620px, 100%);
}

.palebios-sub {
    color: #6f6f6f;
    margin-bottom: 14px;
    letter-spacing: 0.04em;
}

.palebios-checks {
    display: flex;
    flex-direction: column;
    /* No gap. Thirteen lines reading as one block is what a POST looks like,
       and the dotted leader does the separating. */
}

/* Name, then a dotted leader, then what was found, then the code.

   THE LEADER IS ON THE ROW AND THE CELLS MASK IT, which is the old
   table-of-contents trick and the only version of this that survives contact
   with a screen. The first attempt put an absolutely positioned rule on the
   detail cell and stretched it back towards the name with `right: calc(100% +
   4px)` — which is measured against the detail's own box, so it resolved to a
   negative width and drew three pixels of dots jammed against the name. It
   looked like a typo in the text rather than a rule.

   Here the dots run the whole width behind the row, and each cell carries the
   screen's own black so only the GAPS show through. `justify-self: start`
   matters: a grid item stretches to fill its column by default, and a cell
   stretched to 20ch would paint over the dots it is supposed to leave. */
.palebios-check {
    display: grid;
    grid-template-columns: 20ch 1fr auto;
    align-items: baseline;
    gap: 0;
    padding: 1px 0;
    background-image: linear-gradient(to right, #3a3a3a 1px, transparent 1px);
    background-size: 4px 1px;
    background-repeat: repeat-x;
    background-position: left calc(1.5em - 3px);
}

.palebios-check-name,
.palebios-check-detail,
.palebios-check-code {
    justify-self: start;
    background: #000;
}

.palebios-check-name { color: #cfcfcf; padding-right: 8px; }

.palebios-check-detail {
    color: #8f8f8f;
    padding: 0 8px;
}

.palebios-check-code {
    color: #c8a200;
    letter-spacing: 0.08em;
    justify-self: end;
    padding-left: 8px;
}

/* A code is not damage. PER-01 fires on every browser that has not been asked
   for persistence, and a red line there would be the firmware crying wolf on
   a healthy machine — so amber for "worth saying", red only for ok: false. */
.palebios-check.is-bad .palebios-check-name,
.palebios-check.is-bad .palebios-check-detail { color: #ff6a6a; }
.palebios-check.is-bad .palebios-check-code { color: #ff6a6a; }

/* ---- the countdown ------------------------------------------------------- */

.palebios-countdown {
    width: min(620px, 100%);
    color: #8f8f8f;
    text-align: center;
    /* Reserved height, because the text changes every second and a line that
       grows from "in 9" to "in 10" must not move the picker under it. */
    min-height: 1.5em;
}

/* ---- the picker ---------------------------------------------------------- */

.palebios-picker { width: min(620px, 100%); }

.palebios-choices {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 4px;
}

/* A row the size of the sentence explaining it, the same bargain the
   installer's choices make — the explanation is the part somebody is choosing
   between. 44px minimum because this is reachable on a phone. */
.palebios-choice {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    min-height: 44px;
    padding: 9px 12px;
    text-align: left;
    background: #141414;
    color: #cfcfcf;
    border: 1px solid #3a3a3a;
    font-family: inherit;
    font-size: inherit;
    cursor: pointer;
}

.palebios-choice:hover { background: #1e1e1e; border-color: #5a5a5a; }
.palebios-choice:focus-visible { outline: 2px solid #c8a200; outline-offset: 1px; }
.palebios-choice:active { background: #0d0d0d; }

.palebios-choice-name {
    color: #fff;
    font-weight: 700;
    letter-spacing: 0.04em;
}

.palebios-choice-note {
    color: #8f8f8f;
    text-align: right;
}

/* A refused volume is LISTED AND MARKED, never hidden: a member looking for
   the disk they just made and not finding it goes looking for a bug. Dimmed
   rather than struck through, and the note says why in words. */
.palebios-choice.is-refused {
    background: #0c0c0c;
    border-style: dashed;
    border-color: #2e2e2e;
    color: #6f6f6f;
    cursor: not-allowed;
}

.palebios-choice.is-refused:hover {
    background: #0c0c0c;
    border-color: #2e2e2e;
}

.palebios-choice.is-refused .palebios-choice-name { color: #8f8f8f; font-weight: 400; }
.palebios-choice.is-refused .palebios-choice-note { color: #c8a200; }

/* ---- a halt -------------------------------------------------------------- */

/* Two sentences, in prose rather than monospace, because this one is read
   rather than scanned — and because somebody meeting it is being told their
   browser cannot do something, which is not the moment for a terminal voice. */
.palebios-halt {
    width: min(58ch, 100%);
    font-family: var(--ui-font);
    font-size: 13px;
    line-height: 1.6;
    color: #ffd3d3;
    padding: 12px 14px;
    background: #1a0d0d;
    border: 1px solid #5a2a2a;
}

/* The one sentence on the halt screen that is not about the halt: what is on
   the disk in the drive. Prose, like the halt it sits under and for the same
   reason — it is read rather than scanned — and quiet rather than red,
   because an export sitting in the drive is news and not damage. */
.palebios-drive {
    width: min(58ch, 100%);
    font-family: var(--ui-font);
    font-size: 13px;
    line-height: 1.6;
    color: #9f9f9f;
}

/* ---- small screens ------------------------------------------------------- */

@media (max-width: 520px) {
    .palebios { font-size: 11px; gap: 14px; }

    /* The dotted leader and a three-column grid are a desktop affordance. On a
       phone the detail goes under the name, which is narrower and reads the
       same. */
    .palebios-check {
        grid-template-columns: 1fr auto;
        padding: 3px 0;
        background-image: none;
    }

    /* PLACED EXPLICITLY, all three. Auto-placement put the name on row one,
       the full-width detail on row two and then the code on row three — so
       PER-01 floated alone at the right, two lines below the check it belongs
       to and reading like a line of its own. The code goes beside its name. */
    .palebios-check-name { grid-area: 1 / 1 / 2 / 2; }
    .palebios-check-code { grid-area: 1 / 2 / 2 / 3; }
    .palebios-check-detail {
        grid-area: 2 / 1 / 3 / -1;
        padding: 0 0 0 10px;
    }

    .palebios-choice {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }
    .palebios-choice-note { text-align: left; }
}

/* Reduced motion has nothing to turn off here — the countdown is a number
   changing, not an animation — and that is worth saying so the next person
   does not go looking for the rule that is missing. */


/* =============================================================================
   22  PALEBIOS SETUP
   =============================================================================

   Five screens behind a tab strip, in the same black-and-monospace vocabulary
   as POST — same four greys, same stack, same reasons. A settings editor that
   looked like the desktop would be claiming the desktop is running, and on
   the screen you reach by halting a boot that is the one thing it must not
   say.

   It is a tablist and is built as one: roving tabindex, aria-selected, and a
   focus ring that is visible rather than tasteful. Somebody arriving here has
   pressed Esc on purpose and is navigating with a keyboard.
   ========================================================================== */

.palesetup {
    position: fixed;
    inset: 0;
    z-index: 99600;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 20px 16px 28px;
    overflow: auto;
    background: #000;
    color: #cfcfcf;
    font-family: var(--mono-font);
    font-size: 12px;
    line-height: 1.5;
}

/* Above the firmware's own screen (99500), because entering Setup clears that
   one — the two are never up together and this is the belt to that braces. */

.palesetup-head {
    width: min(720px, 100%);
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}

.palesetup-wordmark {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.22em;
    color: #fff;
}

/* Amber, and only ever words. A dot would need a legend; "unsaved changes" is
   the legend. */
.palesetup-dirty {
    color: #c8a200;
    letter-spacing: 0.04em;
}

/* ---- the tab strip ------------------------------------------------------- */

.palesetup-tabs {
    width: min(720px, 100%);
    display: flex;
    gap: 0;
    border-bottom: 1px solid #3a3a3a;
}

.palesetup-tab {
    flex: 1 1 0;
    min-height: 44px;
    padding: 8px 10px;
    background: #0c0c0c;
    color: #8f8f8f;
    border: 1px solid #3a3a3a;
    border-bottom: none;
    margin-right: -1px;
    font-family: inherit;
    font-size: inherit;
    letter-spacing: 0.06em;
    cursor: pointer;
}

.palesetup-tab:hover { background: #161616; color: #cfcfcf; }

/* The selected tab joins the panel below it, the way a tab should: its bottom
   edge is the one gap in the strip's rule. */
.palesetup-tab.is-on {
    background: #141414;
    color: #fff;
    font-weight: 700;
    box-shadow: 0 1px 0 0 #141414;
}

.palesetup-tab:focus-visible {
    outline: 2px solid #c8a200;
    outline-offset: -3px;
}

/* ---- the panel ----------------------------------------------------------- */

.palesetup-body {
    width: min(720px, 100%);
    flex: 0 0 auto;
    padding: 16px 2px 0;
}

.palesetup-body:focus-visible { outline: none; }

.palesetup-legend {
    color: #fff;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    font-size: 11px;
    margin: 18px 0 8px;
    padding-bottom: 4px;
    border-bottom: 1px solid #2e2e2e;
}

/* ---- name/value rows, as on the POST screen ------------------------------ */

.palesetup-rows { display: flex; flex-direction: column; }

.palesetup-row {
    display: grid;
    grid-template-columns: 16ch 1fr;
    align-items: baseline;
    gap: 0;
    padding: 2px 0;
}

.palesetup-row-name { color: #8f8f8f; padding-right: 8px; }

/* Anywhere, because a user-agent string and a 31-character id are both longer
   than the column and neither one may be cut off: an id read off a screen is
   how somebody tells two disks apart. */
.palesetup-row-value { color: #cfcfcf; overflow-wrap: anywhere; }

/* ---- fields -------------------------------------------------------------- */

.palesetup-field { margin-bottom: 16px; }

.palesetup-field-label {
    display: block;
    color: #fff;
    margin-bottom: 4px;
}

.palesetup-field-control { margin-bottom: 4px; }

.palesetup-input,
.palesetup-select {
    min-height: 32px;
    padding: 5px 8px;
    background: #141414;
    color: #fff;
    border: 1px solid #3a3a3a;
    font-family: inherit;
    font-size: inherit;
}

.palesetup-input { width: 16ch; }
.palesetup-select { min-width: 24ch; max-width: 100%; }

.palesetup-input:focus-visible,
.palesetup-select:focus-visible,
.palesetup-check:focus-visible {
    outline: 2px solid #c8a200;
    outline-offset: 1px;
}

/* Big enough to hit with a thumb, which the browser default is not. */
.palesetup-check { width: 18px; height: 18px; accent-color: #c8a200; }

.palesetup-note {
    color: #8f8f8f;
    max-width: 68ch;
    margin: 4px 0 0;
}

/* ---- actions ------------------------------------------------------------- */

.palesetup-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 10px 0 6px;
}

.palesetup-button {
    min-height: 36px;
    padding: 7px 14px;
    background: #141414;
    color: #fff;
    border: 1px solid #5a5a5a;
    font-family: inherit;
    font-size: inherit;
    letter-spacing: 0.04em;
    cursor: pointer;
}

.palesetup-button:hover { background: #1e1e1e; border-color: #8f8f8f; }
.palesetup-button:active { background: #0d0d0d; }
.palesetup-button:focus-visible { outline: 2px solid #c8a200; outline-offset: 1px; }

.palesetup-button[disabled] {
    color: #6f6f6f;
    border-color: #2e2e2e;
    cursor: default;
}

.palesetup-button[disabled]:hover { background: #141414; border-color: #2e2e2e; }

/* ---- a drive ------------------------------------------------------------- */

.palesetup-drive {
    border: 1px solid #2e2e2e;
    padding: 10px 12px;
    margin-bottom: 10px;
    background: #0c0c0c;
}

.palesetup-drive-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid #2e2e2e;
}

.palesetup-drive-name {
    color: #fff;
    font-weight: 700;
    letter-spacing: 0.04em;
}

/* Amber for anything worth saying, red only for damage — the same division
   the POST lines make, and for the same reason: a disk that has simply never
   been checked is not a disk with something wrong with it. */
.palesetup-drive-badge { color: #c8a200; }
.palesetup-drive-badge.is-bad { color: #ff6a6a; }

/* ---- boot order ---------------------------------------------------------- */

.palesetup-order { display: flex; flex-direction: column; gap: 4px; }

.palesetup-order-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 10px;
    background: #0c0c0c;
    border: 1px solid #2e2e2e;
}

.palesetup-order-n { color: #c8a200; min-width: 2ch; }
.palesetup-order-name { color: #cfcfcf; flex: 1 1 auto; overflow-wrap: anywhere; }
.palesetup-order-moves { display: flex; gap: 4px; flex: 0 0 auto; }

/* Square, because they carry an arrow and nothing else. 36px is the smallest
   that is still honestly tappable. */
.palesetup-order-moves .palesetup-button {
    min-width: 36px;
    padding: 6px 8px;
    text-align: center;
}

/* ---- the foot ------------------------------------------------------------ */

.palesetup-foot {
    width: min(720px, 100%);
    margin-top: 20px;
    padding-top: 10px;
    border-top: 1px solid #2e2e2e;
    color: #6f6f6f;
    letter-spacing: 0.04em;
}

/* ---- small screens ------------------------------------------------------- */

@media (max-width: 520px) {
    .palesetup { font-size: 11px; padding: 14px 12px 24px; }

    /* Five tabs across 390px is 78px each, which is narrower than the word
       "Rescue" at this size. They wrap instead and keep their 44px. */
    .palesetup-tabs { flex-wrap: wrap; border-bottom: none; gap: 4px; }
    .palesetup-tab {
        flex: 1 1 30%;
        border: 1px solid #3a3a3a;
        margin-right: 0;
    }
    .palesetup-tab.is-on { box-shadow: none; }

    /* The value goes under the name, as on the POST screen and for the same
       reason: a 16ch column and a user-agent string do not share a line. */
    .palesetup-row { grid-template-columns: 1fr; padding: 4px 0; }
    .palesetup-row-name { padding-right: 0; }

    .palesetup-input { width: 100%; }
    .palesetup-select { width: 100%; min-width: 0; }
    .palesetup-actions > .palesetup-button { flex: 1 1 100%; }
    .palesetup-order-moves .palesetup-button { flex: 0 0 auto; }
}

/* What an operation said. Amber, because it is an answer rather than a label,
   and set apart from the standing notes around it — the whole reason it lives
   in state rather than in a node is that it kept being mistaken for one of
   them and redrawn away. */
.palesetup-said {
    margin-top: 12px;
    padding: 8px 10px;
    background: #141414;
    border-left: 2px solid #c8a200;
    color: #e8e8e8;
    max-width: 68ch;
}


/* ----------------------------------------------------------------------------
   23  PALEDISK

   Two panes with a hard rule between them: the device list on the left at a
   fixed width, the detail on the right taking what is left and scrolling on its
   own. The left pane does not scroll with the right one, because the list is
   how you move between volumes and a list that scrolls away while you read is
   a list you have to go back and find.

   This is a desktop application, so it uses the panel ramp and the ink
   variables like every other one — nothing here borrows the firmware's black
   screen. PaleDisk runs after the handover, with a member signed in.
   -------------------------------------------------------------------------- */

.paledisk-app {
    display: flex;
    align-items: stretch;
    height: 100%;
    min-height: 0;
    background: var(--panel);
    color: var(--ink);
}

.paledisk-pane-left {
    flex: 0 0 196px;
    min-width: 0;
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--panel-dark);
    background: var(--panel-shadow);
}

.paledisk-pane-right {
    flex: 1 1 auto;
    min-width: 0;
    overflow-y: auto;
    padding: 12px 14px 16px;
}

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

.paledisk-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 8px 0 4px;
}

.paledisk-group {
    padding: 4px 10px 6px;
    font-size: 11px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-soft);
}

.paledisk-row {
    display: flex;
    align-items: baseline;
    gap: 6px;
    width: 100%;
    padding: 5px 10px;
    border: 0;
    background: transparent;
    font: inherit;
    color: var(--ink);
    text-align: left;
    cursor: pointer;
}

.paledisk-row:hover { background: var(--panel-lit); }

.paledisk-row.is-selected {
    background: var(--paleos-tab, #ffcb00);
    color: #000;
}

.paledisk-row-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The state a volume is in, said in the list rather than only in the pane: it
   is the one thing you want to know before clicking. */
.paledisk-row-state {
    flex: 0 0 auto;
    font-size: 11px;
    color: var(--ink-soft);
}

.paledisk-row.is-selected .paledisk-row-state { color: #3a3000; }

.paledisk-row-icon { flex: 0 0 auto; }

.paledisk-list-foot {
    flex: 0 0 auto;
    padding: 8px 8px 10px;
    border-top: 1px solid var(--panel-dark);
}

.paledisk-list-foot .paleos-button { width: 100%; }

/* ---- the detail pane ---- */

.paledisk-head { margin-bottom: 14px; }

.paledisk-title {
    margin: 0 0 6px;
    font-size: 15px;
    font-weight: 700;
}

.paledisk-subtitle {
    margin: 18px 0 8px;
    font-size: 12px;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--ink-soft);
    border-bottom: 1px solid var(--panel-dark);
    padding-bottom: 4px;
}

.paledisk-name {
    width: 100%;
    max-width: 320px;
    font-size: 14px;
    font-weight: 700;
}

/* THE ID, GREYED AND MONOSPACED, because paths and the boot order are built on
   it: it has to be visible and it must not look like something to type over. */
.paledisk-id,
.paledisk-mono {
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: 11px;
    color: var(--ink-soft);
}

.paledisk-id { margin: 4px 0 2px; }

.paledisk-field {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 6px 0;
    border-bottom: 1px solid var(--panel-lit);
}

.paledisk-label {
    flex: 0 0 96px;
    font-weight: 700;
    font-size: 12px;
}

.paledisk-value { flex: 1 1 auto; min-width: 0; }

/* A note is standing text — an explanation that is true whatever happened. It
   is deliberately quieter than everything around it. */
.paledisk-note {
    margin: 4px 0 0;
    font-size: 11px;
    line-height: 1.45;
    color: var(--ink-soft);
    max-width: 64ch;
}

.paledisk-note.is-error { color: #a01818; }

/* WHAT AN OPERATION SAID, which is not a note: it is the answer to something
   you just did, and it has to stand out from the standing text around it. The
   same lesson as Setup's own said-line — it lives in state, not in a node,
   because every operation re-reads the volume and re-draws. */
.paledisk-said {
    margin: 0 0 12px;
    padding: 8px 10px;
    background: var(--panel-lit);
    border-left: 3px solid var(--panel-dark);
    font-size: 12px;
    max-width: 68ch;
}

.paledisk-said.is-ok { border-left-color: #2f7a2f; }
.paledisk-said.is-error { border-left-color: #a01818; }

/* ---- capacity ---- */

.paledisk-capacity { max-width: 420px; }

.paledisk-bar {
    height: 14px;
    border: 1px solid var(--panel-darkest);
    background: var(--doc);
    box-shadow: var(--sink-1, inset 1px 1px 0 var(--panel-shadow));
    overflow: hidden;
}

.paledisk-bar-fill {
    height: 100%;
    background: repeating-linear-gradient(
        90deg,
        var(--paleos-tab, #ffcb00) 0 6px,
        color-mix(in srgb, var(--paleos-tab, #ffcb00) 80%, #000) 6px 8px
    );
}

.paledisk-capacity-line {
    margin-top: 4px;
    font-size: 11px;
}

/* A ceiling this browser will no longer cover.

   A BADGE AND A SENTENCE, not a tinted panel. The disk is working and nothing
   has been taken away — a block of warning colour across the capacity field
   would read as damage, which is what the health badge below is for and this
   is not. The amber is the system's own warning colour, borrowed for a word
   rather than for an area. */
.paledisk-atrisk {
    margin-top: 6px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    max-width: 64ch;
}

.paledisk-atrisk-badge {
    align-self: flex-start;
    padding: 1px 6px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #4a3600;
    background: var(--paleos-tab, #ffcb00);
    box-shadow: var(--sink-1);
}

.paledisk-atrisk-why {
    font-size: 11px;
    line-height: 1.45;
    color: var(--ink-soft);
}

.paledisk-headroom { font-size: 12px; max-width: 64ch; }

/* ---- health ---- */

.paledisk-badge {
    display: inline-block;
    padding: 1px 7px;
    border: 1px solid var(--panel-darkest);
    font-size: 11px;
    font-weight: 700;
}

.paledisk-badge.is-ok { background: #cfe8cf; color: #163f16; }
.paledisk-badge.is-warn { background: #f3e2b0; color: #4a3600; }
.paledisk-badge.is-bad { background: #f0c8c8; color: #5f1010; }

/* ---- what is taking up room ---- */

.paledisk-cats {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 2px 16px;
    max-width: 420px;
}

.paledisk-cat {
    display: contents;
}

.paledisk-cat-name { font-size: 12px; }

.paledisk-cat-size {
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: 11px;
    text-align: right;
}

.paledisk-total {
    margin: 8px 0 0;
    font-size: 12px;
    font-weight: 700;
}

/* ---- operations ---- */

.paledisk-op-rows {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 8px;
    align-items: center;
}

.paledisk-op {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

/* WHY A BUTTON IS DISABLED, beside it rather than only in a title attribute. A
   greyed button with no reason is a promise that something could be done if you
   found the right moment. */
.paledisk-op-why {
    font-size: 11px;
    color: var(--ink-soft);
    max-width: 30ch;
}

.paleos-button.is-danger { color: #7a0f0f; font-weight: 700; }

/* A narrow window puts the list above the detail rather than squeezing both.
   196px of device list against 360px of pane is not a two-pane layout any more,
   it is two columns of ellipsis. */
@media (max-width: 560px) {
    .paledisk-app { flex-direction: column; }

    .paledisk-pane-left {
        flex: 0 0 auto;
        max-height: 40%;
        border-right: 0;
        border-bottom: 1px solid var(--panel-dark);
    }

    .paledisk-field { flex-direction: column; gap: 2px; }
    .paledisk-label { flex: 0 0 auto; }
}

/* The drive with no disk in it. A row that is not a button, because there is
   nothing to select — the Insert button below is what acts on it. */
.paledisk-empty-bay {
    padding: 5px 10px;
    font-size: 12px;
    color: var(--ink-soft);
    font-style: italic;
}

.paledisk-list-foot .paleos-button + .paleos-button { margin-top: 4px; }

/* The second window a magic link opens, once it has handed the session over.
   Deliberately plain: it is not a desktop and should not pretend to be one, and
   a person reading it is about to close it. */
.paleos-handoff {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 24px;
    text-align: center;
    background: var(--paleos-desktop, #336698);
}

.paleos-handoff-title {
    margin: 0;
    font-size: 20px;
    color: #fff;
}

.paleos-handoff-note {
    margin: 0;
    max-width: 42ch;
    line-height: 1.5;
    color: #fff;
}

/* The notification banner: top right, over everything, and out of the way of
   the dock at the bottom. It is a strip rather than a window because it is not
   somewhere to work — it says one thing and offers two actions, and one of
   those is to stop showing it. */
.note-banner {
    position: fixed;
    top: 12px;
    right: 12px;
    z-index: 9000;
    display: flex;
    align-items: center;
    gap: 10px;
    max-width: 340px;
    padding: 8px 10px;
    background: var(--panel);
    box-shadow: var(--raise-1);
    cursor: pointer;
}

.note-banner-text { flex: 1; line-height: 1.35; }

.note-banner-close {
    flex: none;
    border: 0;
    background: transparent;
    cursor: pointer;
    font: inherit;
    line-height: 1;
    padding: 2px 4px;
}

.note-row.is-unread .prefs-row-label { font-weight: bold; }

/* ---- the two runner strips a window carries -----------------------------
   App class at the bottom left — the tools belonging to this window's own
   application. Task class at the bottom right — the machine's own: windows,
   time, tap, notifications. Both live in the status bar, which every window
   already has, so an application does not have to leave room for something it
   does not know about.

   `margin-left: auto` on the task strip is what puts it against the right
   edge without the status bar needing to know either strip exists. */
.window-runners {
    display: flex;
    align-items: center;
    gap: 2px;
    flex: none;
}

.window-runners.is-task { margin-left: auto; }

.paleos-iconbutton.is-runner {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    background: transparent;
    padding: 1px 3px;
    cursor: pointer;
    line-height: 1;
}

.paleos-iconbutton.is-runner:hover { background: var(--panel-hi); }
.paleos-iconbutton.is-runner:active { box-shadow: var(--sink-1); }
.paleos-iconbutton.is-runner img { display: block; pointer-events: none; }

.paleos-iconbutton.is-runner.has-face { padding: 1px 5px; }
.runner-face { font: inherit; line-height: 1; white-space: nowrap; }

.prefs-group { margin: 18px 0 2px; font-size: 1rem; }
.prefs-group:first-child { margin-top: 0; }
.prefs-group-note { margin: 0 0 8px; font-size: .9rem; opacity: .8; }

.time-now { font-size: 2rem; margin: 0 0 2px; }
.time-date { margin: 0 0 14px; }

/* THE MUSIC BANNER, bottom right. The notifications banner is top right, and
   the two have to be able to be on screen at once: a tune playing while a
   letter arrives is the ordinary case, not an edge one. Opposite corners
   rather than a stack, so neither can push the other anywhere.

   The 12px here is only the gap. How far up the dock pushes it is set in JS
   from PaleOS.windows.workArea(), because the dock has no height in this file
   — its height comes from its contents, so any number written here would have
   been a guess. A `--dock-height` variable was tried first and would have been
   exactly that: the fallback would have won every time while the comment
   beside it claimed to be reading the real value. */
.music-banner {
    position: fixed;
    bottom: 12px;
    right: 12px;
    z-index: 9000;
    display: flex;
    align-items: center;
    gap: 10px;
    max-width: 340px;
    padding: 8px 10px;
    background: var(--panel);
    box-shadow: var(--raise-1);
    cursor: pointer;
}

.music-banner-text { flex: 1; line-height: 1.35; }

.music-banner-close {
    flex: none;
    border: 0;
    background: transparent;
    cursor: pointer;
    font: inherit;
    line-height: 1;
    padding: 2px 4px;
}

.music-row.is-playing .prefs-row-label { font-weight: bold; }
.music-volume { flex: none; width: 140px; }
