/* ============================================================================
   desktop-portal — two skins, one DOM.

   SKIN A (Windows XP)   applies when the visitor has a mouse and room to use it.
   SKIN B (Holo Android) applies to touch devices and narrow windows.

   The switch is `pointer: coarse` PLUS width, never width alone — a portrait
   1080x1920 desktop monitor would otherwise be served the phone UI.
   A manual override sets data-skin on <html>, which beats both queries.
   ============================================================================ */

/* Wine Tahoma — metric-compatible with the real thing, based on Bitstream Vera
   Sans, freely redistributable. Microsoft's Tahoma is not, so this is the one
   that can actually be served. XP used Tahoma 8/9/11pt for nearly all UI. */
@font-face {
  font-family: "XP Tahoma";
  src: url("/static/fonts/tahoma.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "XP Tahoma";
  src: url("/static/fonts/tahoma-bold.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body { overflow: hidden; -webkit-font-smoothing: antialiased; }
button { font: inherit; color: inherit; cursor: pointer; }
:focus-visible { outline: 2px solid #ffb300; outline-offset: 2px; }

/* Display scale. `zoom` (not `transform: scale`) because it scales LAYOUT — so
   XP.css's hardcoded pixel sizes, the 21px title bars, the taskbar and the
   fonts all grow together. The height is divided back out so the scaled screen
   still fills the viewport exactly. */
.screen {
  position: relative;
  zoom: var(--ui-scale, 1);
  height: calc(100dvh / var(--ui-scale, 1));
  display: flex; flex-direction: column; overflow: hidden;
}
.surface { flex: 1; position: relative; overflow: hidden; }

/* state lamps — shared meaning, restyled per skin */
.lamp { width: 8px; height: 8px; border-radius: 50%; background: #4caf50; flex: none; }
.lamp[data-state="down"]    { background: #d64541; }
.lamp[data-state="warn"]    { background: #e0a72c; }
.lamp[data-state="unknown"] { background: #8a8a8a; }

.icon { width: 32px; height: 32px; flex: none; }
.stale { opacity: .45; }

.nojs { color: #fff; background: rgba(0,0,0,.6); padding: 8px 10px; margin: 12px 0 0; font: 13px system-ui; max-width: 46ch; }

/* ---- context menu: one element, both skins ---- */
.ctxmenu { position: fixed; z-index: 999; min-width: 190px; padding: 2px; }
.ctxmenu[hidden] { display: none; }
.ctxmenu button, .ctxmenu .ctx-label {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  width: 100%; padding: 5px 10px; border: 0; background: none; text-align: left;
  white-space: nowrap;
}
.ctxmenu hr { margin: 3px 6px; border: 0; }
.ctxmenu .ctx-label { font-size: 11px; opacity: .6; cursor: default; }
.ctxmenu button[aria-checked="true"]::after { content: "✓"; }
.ctxmenu button[disabled] { opacity: .4; cursor: default; }

/* ==========================================================================
   SKIN A — Windows XP
   ========================================================================== */
@media (pointer: fine) and (min-width: 700px) {
  /* Two typographic modes, because "XP" means different things depending on
     which XP you remember:
       smooth  — Tahoma outlines, what XP looked like with ClearType on
       pixel   — MS Sans Serif bitmap art, what small UI text looked like
                 aliased at 96 DPI. Stays blocky at any display scale. */
  html:not([data-skin="mobile"]) body {
    font-family: "XP Tahoma", Tahoma, Verdana, sans-serif;
    font-size: 11px;
  }
  html[data-font="pixel"]:not([data-skin="mobile"]) body,
  html[data-font="pixel"]:not([data-skin="mobile"]) .title-bar,
  html[data-font="pixel"]:not([data-skin="mobile"]) .startpanel,
  html[data-font="pixel"]:not([data-skin="mobile"]) .ctxmenu {
    font-family: "Pixelated MS Sans Serif", "XP Tahoma", Tahoma, sans-serif;
    -webkit-font-smoothing: none;
    font-smooth: never;
  }
  /* The bitmap art is drawn for 11px; whole-number multiples keep it crisp
     instead of resampling it into mush. */
  html[data-font="pixel"]:not([data-skin="mobile"]) body { font-size: 11px; }
  html[data-font="pixel"]:not([data-skin="mobile"]) .title-bar { font-size: 11px; }
  html:not([data-skin="mobile"]) .statusbar { display: none; }

  /* Icons are absolutely positioned so they can be dragged anywhere, the way a
     real desktop works. JS lays out a default column for anything unplaced. */
  /* Icons sit UNDER windows. Both are absolutely positioned inside .surface and
     the icon list comes later in the DOM, so without this it paints on top of
     every window. */
  html:not([data-skin="mobile"]) .shortcuts {
    position: absolute; inset: 0; width: auto; display: block; z-index: 1;
  }
  /* The window layer spans the whole surface, ignoring its 14px padding —
     otherwise a maximized window starts inside the padding and leaves a gap at
     the top and left while overflowing bottom-right. */
  html:not([data-skin="mobile"]) .widgets { position: absolute; inset: 0; z-index: 5; }
  /* The layer covers the whole desktop, so it must be transparent to clicks —
     otherwise it swallows every icon click and drag beneath it. Only the
     windows themselves take input. */
  html:not([data-skin="mobile"]) .widgets { pointer-events: none; }
  html:not([data-skin="mobile"]) .widgets .win { pointer-events: auto; }

  /* Maximized geometry is CSS, not pixel arithmetic: 100% of the layer is
     exactly right at any display scale and survives a window resize. */
  html:not([data-skin="mobile"]) .win.maxed {
    left: 0; top: 0; width: 100%; height: 100%;
    border-radius: 0;
  }
  html:not([data-skin="mobile"]) .shortcuts > li { position: absolute; margin: 0; }
  html:not([data-skin="mobile"]) .shortcut { cursor: default; user-select: none; }
  html:not([data-skin="mobile"]) .shortcut.dragging { opacity: .7; }

  /* Resize grip, bottom-right, like the real thing. */
  html:not([data-skin="mobile"]) .win-resize {
    position: absolute; right: 0; bottom: 0; width: 15px; height: 15px;
    cursor: nwse-resize;
    background:
      linear-gradient(135deg, transparent 45%, #8a9199 45%, #8a9199 55%, transparent 55%),
      linear-gradient(135deg, transparent 65%, #8a9199 65%, #8a9199 75%, transparent 75%);
  }
  html:not([data-skin="mobile"]) .win { display: flex; flex-direction: column; }
  html:not([data-skin="mobile"]) .win-body { flex: 1; overflow: auto; }

  /* The wallpaper is referenced HERE, inside the desktop media query, and never
     as an <img> in the markup. A hidden <img> still downloads — this way a phone
     never fetches the 21:9 desktop wallpaper it will never show.
     The gradient stays underneath as the fallback if the file 404s. */
  html:not([data-skin="mobile"]) .surface {
    background-color: #2f6fb5;
    background-image:
      var(--wallpaper, url("/static/wallpapers/bliss-ultrawide.webp")),
      linear-gradient(#2f6fb5 0%, #63a6de 62%, #9fd0ef 100%);
    background-size: cover, auto;
    background-position: center center;
    background-repeat: no-repeat;
    padding: 14px;
  }

  /* ---- authentic XP cursors (32px PNGs from the WinXp pack) ---- */
  html:not([data-skin="mobile"]) .screen,
  html:not([data-skin="mobile"]) .surface {
    cursor: url("/static/cursors/arrow.png") 0 0, default;
  }
  html:not([data-skin="mobile"]) .shortcut,
  html:not([data-skin="mobile"]) .dock-item,
  html:not([data-skin="mobile"]) .dock-start,
  html:not([data-skin="mobile"]) .ctxmenu button,
  html:not([data-skin="mobile"]) .sp-cols button,
  html:not([data-skin="mobile"]) .sp-foot button,
  html:not([data-skin="mobile"]) .sp-all,
  html:not([data-skin="mobile"]) .title-bar-controls button,
  html:not([data-skin="mobile"]) .window-body button,
  html:not([data-skin="mobile"]) a {
    cursor: url("/static/cursors/link.png") 6 0, pointer;
  }
  html:not([data-skin="mobile"]) .win-title { cursor: url("/static/cursors/move.png") 12 12, move; }
  html:not([data-skin="mobile"]) .win-resize { cursor: url("/static/cursors/size1.png") 12 12, nwse-resize; }
  html:not([data-skin="mobile"]) input, html:not([data-skin="mobile"]) .icq-body {
    cursor: url("/static/cursors/ibeam.png") 12 12, text;
  }
  html:not([data-skin="mobile"]) button[disabled] {
    cursor: url("/static/cursors/no.png") 12 12, not-allowed;
  }

  /* The real Windows flag on the Start button. */
  html:not([data-skin="mobile"]) .dock-start img { height: 16px; width: auto; }

  html:not([data-skin="mobile"]) .shortcuts {
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
    width: var(--icon-cell, 92px);
  }
  html:not([data-skin="mobile"]) .shortcut {
    position: relative; width: var(--icon-cell, 92px);
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    padding: 5px 3px; background: none; border: 1px solid transparent;
    color: #fff; font-size: var(--icon-font, 11px); line-height: 1.25; text-align: center;
    text-decoration: none; text-shadow: 0 1px 2px rgba(0,0,0,.85);
  }
  html:not([data-skin="mobile"]) .shortcut .icon { width: var(--icon-size, 32px); height: var(--icon-size, 32px); }
  html:not([data-skin="mobile"]) .shortcut:hover,
  html:not([data-skin="mobile"]) .shortcut:focus-visible {
    background: rgba(49,106,197,.45); border-color: rgba(255,255,255,.45);
  }
  html:not([data-skin="mobile"]) .shortcut.selected { background: rgba(49,106,197,.6); border-color: rgba(255,255,255,.6); }
  html:not([data-skin="mobile"]) .shortcut .lamp {
    position: absolute; left: 50%; top: 4px; margin-left: 6px;
    box-shadow: 0 0 0 1.5px rgba(0,0,0,.55);
  }

  /* Window chrome comes from XP.css. Only the things it can't know about —
     absolute positioning, drag affordance, sizing — live here. */
  html:not([data-skin="mobile"]) .widgets { margin: 0; padding: 0; }
  html:not([data-skin="mobile"]) .win {
    position: absolute; width: 262px; font-size: 11px;
  }
  /* XP.css draws the frame with inset box-shadows, so a drop shadow has to be
     added without replacing them — hence the extra layer, not `box-shadow:`. */
  html:not([data-skin="mobile"]) .win { filter: drop-shadow(3px 3px 6px rgba(0,0,0,.45)); }

  html:not([data-skin="mobile"]) .win-title {
    cursor: move; user-select: none;
    flex: none;                     /* the column flex must not squash the 21px bar */
  }
  /* A title that doesn't fit must clip, never wrap — .title-bar is a fixed
     21px tall, so a second line lands outside the window entirely. */
  html:not([data-skin="mobile"]) .title-bar-text {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    min-width: 0; flex: 1;
  }
  html:not([data-skin="mobile"]) .title-bar-controls { flex: none; }

  /* The body is a flex column so scrollable regions inside a window can grow
     with it. Without this, resizing a window just adds dead space under a
     fixed-height list. */
  html:not([data-skin="mobile"]) .win-body {
    padding: 8px 9px 10px; min-width: 0;
    display: flex; flex-direction: column; min-height: 0;
  }
  html:not([data-skin="mobile"]) .tm-scroll,
  html:not([data-skin="mobile"]) .icq-body,
  html:not([data-skin="mobile"]) .wa-list,
  html:not([data-skin="mobile"]) .dp-panel {
    flex: 1 1 auto; min-height: 0; max-height: none;
  }
  /* Everything that shouldn't absorb the slack. */
  html:not([data-skin="mobile"]) .win-age,
  html:not([data-skin="mobile"]) .tm-head,
  html:not([data-skin="mobile"]) .icq-head,
  html:not([data-skin="mobile"]) .icq-foot,
  html:not([data-skin="mobile"]) .wa-display,
  html:not([data-skin="mobile"]) .wa-controls,
  html:not([data-skin="mobile"]) menu[role="tablist"] { flex: none; }
  /* Safety net: the window is resizable, so any fixed width is only ever a
     good guess. Wrapping is ugly; a clipped tab is broken. */
  html:not([data-skin="mobile"]) .win-display menu[role="tablist"] { flex-wrap: wrap; }

  /* Default heights so list windows open at a sensible size and the flex
     fill has something to divide up. */
  html:not([data-skin="mobile"]) .win-containers { height: 340px; }
  html:not([data-skin="mobile"]) .win-defrag { height: 260px; }
  html:not([data-skin="mobile"]) .win-contacts { height: 260px; }
  /* The library is a small chooser, not a main window — the actual player is
     Webamp, mounted separately. It was sized like a content window and looked
     absurd holding a two-line list. */
  html:not([data-skin="mobile"]) .win-music { height: 200px; }
  html:not([data-skin="mobile"]) .win-display { height: 420px; }

  /* Per-window widths — one flat width made the wider tables unreadable. */
  html:not([data-skin="mobile"]) .win-system     { width: 300px; }
  html:not([data-skin="mobile"]) .win-contacts   { width: 250px; }
  html:not([data-skin="mobile"]) .win-power      { width: 240px; }
  html:not([data-skin="mobile"]) .win-music      { width: 265px; }
  /* 320px was ~4px too narrow for the four tabs, so whichever tab was selected
     last got its right border clipped by the frame. XP.css gives the selected
     tab `margin-left:-3px; margin-right:-1px`, i.e. it is WIDER than an
     unselected one — so the row only overflowed once "Settings" was picked,
     which is why it looked intermittent. */
  html:not([data-skin="mobile"]) .win-display    { width: 366px; }
  html:not([data-skin="mobile"]) .stat { display: flex; justify-content: space-between; gap: 10px; padding: 2px 0; }
  html:not([data-skin="mobile"]) .stat dt { color: #3b3b3b; }
  html:not([data-skin="mobile"]) .stat dd { margin: 0; font-variant-numeric: tabular-nums; }
  html:not([data-skin="mobile"]) .screen .bar { height: 11px; background: #fff; border: 1px solid #7f9db9; margin-top: 6px; padding: 1px; }
  html:not([data-skin="mobile"]) .screen .bar > i { display: block; height: 100%; background: repeating-linear-gradient(90deg,#2f9e2f 0 5px,#ece9d8 5px 7px); }
  html:not([data-skin="mobile"]) .win-age { font-size: 10px; color: #6a6a6a; margin-top: 6px; }

  html:not([data-skin="mobile"]) .dock {
    display: flex; align-items: stretch; height: 30px;
    background: linear-gradient(#245edb,#3f8cf3 9%,#245edb 18%,#1f57cd 92%,#1849b8 100%);
    border-top: 1px solid #4d92f5;
  }
  html:not([data-skin="mobile"]) .dock-items { display: flex; align-items: center; gap: 3px; padding-left: 4px; overflow: hidden; }
  html:not([data-skin="mobile"]) .dock-start {
    display: flex; align-items: center; padding: 0 16px 0 9px; border: 0;
    background: linear-gradient(#4a973d,#71bb5e 8%,#3f8b32 42%,#2e7a26 100%);
    color: #fff; font-weight: bold; font-style: italic; font-size: 13px;
    border-radius: 0 8px 8px 0; text-shadow: 1px 1px 1px rgba(0,0,0,.5);
  }
  html:not([data-skin="mobile"]) .dock-item {
    display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 9px;
    background: #3f8cf3; border: 1px solid #5a9ff5; color: #fff; font-size: 11px; white-space: nowrap;
  }
  html:not([data-skin="mobile"]) .dock-item .icon { width: 14px; height: 14px; }
  html:not([data-skin="mobile"]) .dock-tray {
    margin-left: auto; display: flex; align-items: center; gap: 8px; padding: 0 10px;
    background: linear-gradient(#149ae4,#17b9ee 10%,#0e8ed6 90%);
    border-left: 1px solid #16a7e8; color: #fff; font-size: 11px; font-variant-numeric: tabular-nums;
  }

  /* ---- the XP Start panel: two columns, user header, footer bar ---- */
  html:not([data-skin="mobile"]) .startpanel {
    position: fixed; z-index: 1000; width: 400px;
    border: 1px solid #0831d9; border-radius: 8px 8px 0 0;
    box-shadow: 3px 0 14px rgba(0,0,0,.45);
    overflow: hidden; color: #000;
    font-family: "XP Tahoma", Tahoma, Verdana, sans-serif;
  }
  html:not([data-skin="mobile"]) .startpanel[hidden] { display: none; }

  html:not([data-skin="mobile"]) .sp-user {
    display: flex; align-items: center; gap: 10px; padding: 7px 10px;
    background: linear-gradient(#1f5fc4, #3f83e0 45%, #1c56b8);
    border-bottom: 2px solid #ec9b3b;
  }
  html:not([data-skin="mobile"]) .sp-avatar {
    width: 44px; height: 44px; border-radius: 5px; border: 2px solid #fff;
    background: #7aa6de center/cover no-repeat;
    display: flex; align-items: center; justify-content: center;
    color: #fff; font-weight: bold; font-size: 18px;
  }
  html:not([data-skin="mobile"]) .sp-name { color: #fff; font-weight: bold; font-size: 14px; text-shadow: 1px 1px 2px rgba(0,0,0,.5); }
  html:not([data-skin="mobile"]) .sp-role { color: #cfe0f7; font-size: 10px; display: block; font-weight: normal; }

  /* Two columns: white programs list left, pale-blue "places" right, with the
     blue divider rule between them — as in the real Start menu. */
  html:not([data-skin="mobile"]) .sp-cols { display: flex; background: #fff; }
  html:not([data-skin="mobile"]) .sp-left  { width: 54%; background: #fff; padding: 6px 0; }
  html:not([data-skin="mobile"]) .sp-right {
    width: 46%; padding: 6px 0;
    background: linear-gradient(#d3e5fa, #c2dbf7);
    border-left: 1px solid #a8c8ee;
  }
  html:not([data-skin="mobile"]) .sp-cols button {
    display: flex; align-items: center; gap: 9px; width: 100%;
    padding: 5px 11px; border: 0; background: none; text-align: left; font-size: 11px;
    color: #000; border-radius: 0;
  }
  html:not([data-skin="mobile"]) .sp-cols button:hover:not([disabled]) { background: #2f6fb5; color: #fff; }
  html:not([data-skin="mobile"]) .sp-cols button[aria-checked="true"] { font-weight: bold; }
  html:not([data-skin="mobile"]) .sp-cols .icon { width: 24px; height: 24px; flex: none; }
  html:not([data-skin="mobile"]) .sp-right button { font-weight: bold; color: #0a2c66; }
  html:not([data-skin="mobile"]) .sp-right button:hover { color: #fff; }

  /* "All Programs" bar, right-aligned with the green chevron. */
  html:not([data-skin="mobile"]) .sp-all {
    display: flex; align-items: center; justify-content: flex-end; gap: 7px;
    margin: 5px 0 0; padding: 5px 11px; border: 0; width: 100%;
    background: none; font-weight: bold; font-size: 11px;
    border-top: 1px solid #c3d8f0;
  }
  html:not([data-skin="mobile"]) .sp-all span {
    display: inline-flex; align-items: center; justify-content: center;
    width: 17px; height: 17px; border-radius: 50%;
    background: linear-gradient(#6cd06a, #1c9e1a); color: #fff; font-size: 9px;
  }
  html:not([data-skin="mobile"]) .sp-sep { height: 1px; background: #c3d8f0; margin: 4px 8px; }
  html:not([data-skin="mobile"]) .sp-head { padding: 4px 10px 2px; font-size: 10px; color: #6a6a6a; }

  html:not([data-skin="mobile"]) .sp-foot {
    display: flex; justify-content: flex-end; gap: 14px; padding: 6px 12px;
    background: linear-gradient(#3f83e0, #1c56b8);
    border-top: 1px solid #5c9bea;
  }
  html:not([data-skin="mobile"]) .sp-foot button {
    display: flex; align-items: center; gap: 6px; border: 0; background: none;
    color: #fff; font-size: 11px; text-shadow: 1px 1px 1px rgba(0,0,0,.4);
  }
  html:not([data-skin="mobile"]) .sp-foot button:hover { text-decoration: underline; }

  html:not([data-skin="mobile"]) .ctxmenu {
    background: #fff; border: 1px solid #7f9db9; box-shadow: 2px 2px 6px rgba(0,0,0,.35);
    font-size: 11px; color: #000;
  }
  html:not([data-skin="mobile"]) .ctxmenu button:hover:not([disabled]) { background: #316ac5; color: #fff; }
  html:not([data-skin="mobile"]) .ctxmenu hr { border-top: 1px solid #d5d5d5; }
}

/* ==========================================================================
   SKIN B — Android, Holo era, green accent
   ========================================================================== */
@media not all and (pointer: fine), (max-width: 699px) {
  html:not([data-skin="desktop"]) body { font-family: Roboto, "Droid Sans", system-ui, sans-serif; }
  html:not([data-skin="desktop"]) .screen { background: #0a0a0a; color: #f1f1f1; }

  html:not([data-skin="desktop"]) .statusbar {
    display: flex; align-items: center; gap: 10px; height: 26px; padding: 0 10px;
    background: #000; color: #d8d8d8; font-size: 12px; border-bottom: 1px solid #1c1c1c;
    font-variant-numeric: tabular-nums;
  }
  html:not([data-skin="desktop"]) .statusbar .clock { margin-left: auto; }

  html:not([data-skin="desktop"]) .surface {
    background: radial-gradient(140% 60% at 50% 0%, #10231a 0%, #0a0a0a 70%);
    padding: 14px 12px 8px; overflow-y: auto;
    display: flex; flex-direction: column; gap: 16px;
  }

  html:not([data-skin="desktop"]) .widgets { display: grid; gap: 10px; margin: 0; padding: 0; }
  html:not([data-skin="desktop"]) .win { background: #141414; border: 1px solid #262626; border-radius: 2px; }
  html:not([data-skin="desktop"]) .win-title {
    display: flex; align-items: center; gap: 8px; padding: 9px 12px 7px;
    font-size: 11px; font-weight: 500; letter-spacing: .11em; text-transform: uppercase;
    color: #63e08a; border-bottom: 1px solid #262626;
  }
  html:not([data-skin="desktop"]) .win-title span.t { flex: 1; }
  html:not([data-skin="desktop"]) .win-close { display: none; }
  html:not([data-skin="desktop"]) .win-body { padding: 10px 12px 12px; }
  html:not([data-skin="desktop"]) .stat {
    display: flex; justify-content: space-between; gap: 12px; padding: 5px 0;
    font-size: 14px; border-bottom: 1px solid #1a1a1a;
  }
  html:not([data-skin="desktop"]) .stat:last-of-type { border-bottom: 0; }
  html:not([data-skin="desktop"]) .stat dt { color: #8b8b8b; }
  html:not([data-skin="desktop"]) .stat dd { margin: 0; color: #f1f1f1; font-variant-numeric: tabular-nums; }
  html:not([data-skin="desktop"]) .screen .bar { height: 3px; background: #262626; margin-top: 10px; }
  html:not([data-skin="desktop"]) .screen .bar > i { display: block; height: 100%; background: #63e08a; }
  html:not([data-skin="desktop"]) .win-age { font-size: 10px; color: #6f6f6f; margin-top: 8px; }

  html:not([data-skin="desktop"]) .shortcuts {
    list-style: none; margin: 0; padding: 0;
    display: grid; grid-template-columns: repeat(var(--grid-cols, 4), 1fr); gap: 14px 6px;
  }
  html:not([data-skin="desktop"]) .shortcut {
    position: relative; width: 100%;
    display: flex; flex-direction: column; align-items: center; gap: 7px;
    padding: 6px 2px; background: none; border: 0; border-radius: 2px;
    color: #ededed; font-size: var(--icon-font, 11px); line-height: 1.3;
    text-align: center; text-decoration: none;
  }
  html:not([data-skin="desktop"]) .shortcut .icon { width: var(--icon-size-m, 40px); height: var(--icon-size-m, 40px); }
  html:not([data-skin="desktop"]) .shortcut:active { background: #1d1d1d; }
  html:not([data-skin="desktop"]) .shortcut .lamp {
    position: absolute; top: 4px; left: 50%; margin-left: 12px; box-shadow: 0 0 0 2px #0a0a0a;
  }

  html:not([data-skin="desktop"]) .dock {
    display: flex; align-items: center; background: #000;
    border-top: 1px solid #1c1c1c; padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
  }
  html:not([data-skin="desktop"]) .dock-start { display: none; }
  html:not([data-skin="desktop"]) .dock-items { display: flex; flex: 1; }
  html:not([data-skin="desktop"]) .dock-item {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
    padding: 5px 2px; border: 0; background: none; color: #9a9a9a; font-size: 10px;
  }
  html:not([data-skin="desktop"]) .dock-item .icon { width: 22px; height: 22px; }
  html:not([data-skin="desktop"]) .dock-tray { display: none; }

  html:not([data-skin="desktop"]) .ctxmenu {
    background: #1b1b1b; border: 1px solid #333; border-radius: 2px;
    box-shadow: 0 6px 22px rgba(0,0,0,.6); color: #ededed; font-size: 14px;
  }
  html:not([data-skin="desktop"]) .ctxmenu button:hover:not([disabled]) { background: #262626; color: #63e08a; }
  html:not([data-skin="desktop"]) .ctxmenu hr { border-top: 1px solid #2a2a2a; }
}

/* ==========================================================================
   Widget internals — shared structure, minimal skin-specific colour.
   Design polish is deferred by decision; these are built to work first.
   ========================================================================== */
.empty { margin: 6px 0 0; opacity: .75; line-height: 1.45; }

/* ---- Display Properties ---- */
.dp-panel { padding: 10px 12px 12px; }
/* XP.css sizes tabs from their text; a two-word label wraps and makes that one
   tab taller than the rest, which breaks the strip. */
menu[role="tablist"] button { white-space: nowrap; }
.dp-preview { display: flex; flex-direction: column; align-items: center; margin-bottom: 10px; }
.dp-screen {
  width: 168px; height: 126px; padding: 7px 7px 14px;
  background: #d6d2c2; border-radius: 8px 8px 3px 3px;
  box-shadow: inset -1px -1px #6f6b5e, inset 1px 1px #fff, inset -2px -2px #a6a292, inset 2px 2px #efeee6;
}
.dp-screen img { width: 100%; height: 100%; object-fit: cover; display: block; border: 1px solid #4a4a44; }
.dp-stand { width: 54px; height: 9px; background: #c8c4b4; border-radius: 0 0 5px 5px; box-shadow: inset -1px -1px #6f6b5e, inset 1px 1px #fff; }
.dp-panel .field-row-stacked { margin-bottom: 10px; }
.dp-panel label { display: block; margin-bottom: 3px; }
.dp-panel select { width: 100%; }
.dp-note { margin: 4px 0 0; color: #555; }
.dp-panel { overflow-y: auto; }

/* Screen Saver tab: the little monitor shows a dark screen instead of the
   wallpaper, since that is what the saver actually looks like. */
.dp-screen-black {
  display: flex; align-items: center; justify-content: center;
  background: #d6d2c2;
}
.dp-screen-black::before {
  content: ""; position: absolute; inset: 0;
}
.dp-screen.dp-screen-black { position: relative; }
.dp-screen.dp-screen-black > * { position: relative; z-index: 1; }
.dp-saver-hint {
  display: block; width: calc(100% - 14px); height: calc(100% - 21px);
  position: absolute; left: 7px; top: 7px;
  background: #000; border: 1px solid #4a4a44; color: #4bd07a;
  font-size: 10px; letter-spacing: .5px;
  display: flex; align-items: center; justify-content: center;
}
/* Screen Saver tab keeps the Wait row on one line, unlike the stacked rows. */
.dp-panel .field-row { display: flex; align-items: center; gap: 8px; }
.dp-panel .field-row label { margin: 0; white-space: nowrap; }
.dp-panel .field-row select { width: auto; flex: 1; }


/* System Properties dialog */
.sysprop { display: flex; gap: 10px; align-items: flex-start; }
.sysprop-logo .icon { width: 40px; height: 40px; }
.sysprop-text { flex: 1; min-width: 0; }
.sysprop-text h3 { margin: 5px 0 1px; font-size: 1em; font-weight: bold; }
.sysprop-text h3:first-child { margin-top: 0; }
.sysprop-text p { margin: 0; line-height: 1.35; word-break: break-word; }
.sysprop-rule { border: 0; border-top: 1px solid #aca899; margin: 8px 0; }
.disk { display: flex; align-items: center; gap: 7px; margin-top: 5px; }
.disk .bar { flex: 1; margin-top: 0; }
.disk span { font-variant-numeric: tabular-nums; white-space: nowrap; }
.tm-head { margin: 0 0 6px; font-weight: bold; }
.tm-scroll { max-height: 190px; overflow-y: auto; overflow-x: auto; }
table.tm { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
table.tm th { text-align: left; font-weight: bold; position: sticky; top: 0; }
table.tm td, table.tm th { padding: 2px 6px 2px 0; white-space: nowrap; }

/* ---- ICQ contact list ---- */
.flower { width: 13px; height: 13px; flex: none; }
.icq { display: flex; flex-direction: column; min-height: 0; }
.icq-head {
  display: flex; align-items: center; gap: 7px; padding: 5px 7px;
  background: linear-gradient(#f4f4ef, #dcdcd2); border: 1px solid #9a9a90;
  border-bottom: 0;
}
.icq-me { font-weight: bold; }
.icq-status { margin-left: auto; color: #3fae2a; font-weight: bold; font-size: .92em; }
.icq-body {
  background: #fff; border: 1px solid #9a9a90; padding: 3px 0;
  max-height: 190px; overflow-y: auto; flex: 1;
}
.icq-grp {
  padding: 3px 7px; background: #ecebe3; border-bottom: 1px solid #dcdcd2;
  font-weight: bold; color: #3a3a3a;
}
.icq-grp em { font-style: normal; font-weight: normal; opacity: .6; }
.icq-body ul { list-style: none; margin: 0; padding: 2px 0 4px; }
.icq-body li { display: flex; align-items: center; gap: 7px; padding: 2px 9px; }
.icq-body li.off, .icq-body li.anon { color: #7a7a7a; font-style: italic; }
.icq-foot { display: flex; gap: 5px; margin-top: 6px; }
.icq-foot button { flex: 1; font-size: .95em; }

/* XP icons are smooth 128px artwork, not pixel art — so they scale with normal
   interpolation. (The 98-era 32px set needed `image-rendering: pixelated`;
   these do not, and it would only make them look chewed.) */
img.icon { object-fit: contain; }

.defrag-grid { display: grid; grid-template-columns: repeat(20, 1fr); gap: 1px; margin-top: 6px; }
.defrag-grid i { display: block; aspect-ratio: 1; }
.defrag-grid i.u { background: #d64541; }
.defrag-grid i.f { background: #4f7fd6; }

.wa-display { display: flex; justify-content: space-between; gap: 10px; padding: 4px 6px; font-variant-numeric: tabular-nums; }
.wa-controls { display: flex; align-items: center; gap: 3px; margin-top: 5px; }
.wa-controls button { padding: 2px 7px; line-height: 1.2; }
.wa-controls input[type="range"] { flex: 1; min-width: 60px; margin-left: 6px; }
.wa-list { list-style: none; margin: 7px 0 0; padding: 0; max-height: 132px; overflow-y: auto; }
.wa-list li { padding: 2px 5px; cursor: pointer; }

.saver { position: fixed; inset: 0; z-index: 9998; background: #000; }

@media (pointer: fine) and (min-width: 700px) {
  html:not([data-skin="mobile"]) .win-containers { width: 360px; }
  html:not([data-skin="mobile"]) .win-defrag { width: 330px; }
  html:not([data-skin="mobile"]) table.tm th { background: #ece9d8; border-bottom: 1px solid #aca899; }
  html:not([data-skin="mobile"]) .wa-display { background: #000; color: #63e08a; font-family: ui-monospace, monospace; font-size: 10px; border: 1px inset #9a9a9a; }
  html:not([data-skin="mobile"]) .wa-list { background: #000; color: #63e08a; font-family: ui-monospace, monospace; font-size: 10px; }
  html:not([data-skin="mobile"]) .wa-list li.on { background: #10306b; }
  html:not([data-skin="mobile"]) .defrag-grid { grid-template-columns: repeat(24, 1fr); }
}

@media not all and (pointer: fine), (max-width: 699px) {
  html:not([data-skin="desktop"]) table.tm th { background: #141414; color: #8b8b8b; border-bottom: 1px solid #262626; }
  html:not([data-skin="desktop"]) .wa-display { background: #000; color: #63e08a; font-family: ui-monospace, monospace; border: 1px solid #262626; }
  html:not([data-skin="desktop"]) .wa-list { font-size: 13px; }
  html:not([data-skin="desktop"]) .wa-list li.on { background: #1d1d1d; color: #63e08a; }
  html:not([data-skin="desktop"]) .wa-controls button { background: #1b1b1b; border: 1px solid #333; color: #ededed; border-radius: 2px; padding: 6px 10px; }
  html:not([data-skin="desktop"]) .icq-list li { border-bottom: 1px solid #1a1a1a; padding: 7px 0; }
}

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

/* ---- keep our class names off Webamp ----
   Webamp roots itself on <body> as #webamp, a SIBLING of .screen, and its
   markup uses plenty of ordinary class names of its own. `.bar` collided with
   the CPU/disk meters here and painted stray strips above the playlist's
   ADD/REM/SEL/MISC buttons; `.window` collided with XP.css the same way.
   Anything styled by a generic class name gets scoped under .screen. */
/* ---- Webamp host ----
   Webamp lives outside the scaled desktop and paints its own chrome. Two things
   matter here: the host must not block clicks on the desktop underneath, and
   XP.css must not repaint Webamp's windows — it also uses the class `.window`. */
#webamp-host { position: fixed; inset: 0; z-index: 900; pointer-events: none; }
#webamp-host #webamp { pointer-events: none; }
#webamp-host #webamp > * { pointer-events: auto; }
#webamp-host .window {
  box-shadow: none;
  background: transparent;
  padding: 0;
  border-radius: 0;
  border: 0;
}

/* Library list inside the Winamp window — a normal XP list, not the black
   pseudo-Winamp panel left over from the old hand-rolled player. */
.lib-list { list-style: none; margin: 6px 0 0; padding: 2px 0; background: #fff;
  box-shadow: inset -1px -1px #fff, inset 1px 1px grey, inset -2px -2px #dfdfdf, inset 2px 2px #0a0a0a;
  overflow-y: auto; }
.lib-list li { padding: 3px 8px; cursor: pointer; display: flex; gap: 8px; }
.lib-list li em { margin-left: auto; font-style: normal; opacity: .6; }
.lib-list li.on { background: #316ac5; color: #fff; }
.lib-list li.on em { opacity: .85; }
.wa-error { margin: 6px 0; padding: 6px 8px; background: #ffe9e9; border: 1px solid #d64541; line-height: 1.4; }
.wa-error button { margin-top: 5px; }

/* ---- Explorer (§13) — menu bar, toolbar, address bar, blue tree + icons ----
   Redesigned 2026-08-21: v1 shipped a toggleable tree/Details-table pane,
   which is real XP behaviour but not the recognisable "XP" look fanix's
   reference screenshot showed (task pane + Large Icons). Rather than build
   both states, the tree stays (it's genuinely useful) but permanently, and
   it borrows the task pane's blue gradient instead of a second white pane —
   the Rename/Delete/Properties actions that would have lived in the task
   pane's "File and Folder Tasks" list moved to the icon's right-click menu. */
html:not([data-skin="mobile"]) .win-explorer {
  width: 520px; height: 380px;
}
html:not([data-skin="mobile"]) .win-explorer .win-body {
  padding: 0; overflow: hidden; position: relative;  /* anchors XPUI.dialog */
}
.exp-menubar {
  flex: none; padding: 3px 8px; font-size: 11px; display: flex; gap: 14px;
  border-bottom: 1px solid #d3d1c3;
}
.exp-toolbar {
  flex: none; padding: 4px 6px; display: flex; align-items: center; gap: 4px;
  border-bottom: 1px solid #d3d1c3; background: #ece9d8;
}
.exp-toolbar button { font-size: 11px; padding: 2px 8px; }
.exp-addressbar {
  flex: none; padding: 4px 6px; display: flex; align-items: center; gap: 6px;
  border-bottom: 1px solid #d3d1c3;
}
.exp-addr-label { display: flex; align-items: center; gap: 4px; font-size: 11px; white-space: nowrap; }
.exp-addr-label .icon { width: 14px; height: 14px; }
.exp-addr-box {
  flex: 1; background: #fff; border: 1px solid #7f9db9; padding: 2px 6px;
  font-size: 11px; white-space: nowrap; overflow-x: auto; min-width: 0;
}
.exp-crumb { cursor: pointer; }
.exp-crumb:hover { text-decoration: underline; color: #0a3faa; }

.exp-split { flex: 1 1 auto; min-height: 0; display: flex; }

/* The task pane's own Luna blue, just carrying the tree instead of task
   links — same family of gradient as the real "Common Tasks" sidebar. */
.exp-tree-pane {
  flex: none; width: 190px; overflow: auto; border-right: 1px solid #0a3a8c;
  background: linear-gradient(180deg, #7dabe8 0%, #5486d6 12%, #3f6fc9 55%, #2f59ad 100%);
  color: #fff; padding: 6px 4px;
}
.exp-tree { border: none; padding: 0; }
.exp-tree a { color: #fff; }
/* The expand/collapse box is XP.css's own `summary::before` (content:"+"/"-",
   its own white background, no color set) — it inherits `color` from
   `.exp-tree-pane`'s white text, which paints the glyph white ON white,
   i.e. invisible. The box itself (grey border) still shows and still
   toggles on click — it just looked dead because the +/- was never there
   to see. Give it back a dark glyph against its own white square. */
/* `ul.tree-view details>summary:before` is XP.css's own selector — 4 type
   selectors + 1 class, specificity (0,1,4). `.exp-tree details>summary:before`
   is only (0,1,3) and silently lost the width/height fight (confirmed via
   computed style: stayed 8x9px). Matching XP.css's own `ul.tree-view` prefix
   plus `.exp-tree` beats it outright, same family of trap the project's own
   notes already document for the Minecraft window's fixed-size rule. */
ul.tree-view.exp-tree details > summary:before {
  color: #222;
  /* XP.css ships this box at a bare 8x9px — technically clickable (the
     native <details> toggle fires on any click that lands on it, verified
     directly against the live page), but that is a genuinely tiny target
     to land a real mouse on, especially through a scaled/zoomed display.
     Enlarged rather than left at spec size — visual authenticity loses to
     "the button actually works for a human" here. */
  width: 13px; height: 13px; line-height: 13px; font-size: 11px;
}
.exp-tree .icon { width: 15px; height: 15px; margin-right: 4px; vertical-align: -3px; }
.exp-tree summary, .exp-tree a {
  border-radius: 3px;
}
.exp-tree summary:hover, .exp-tree a:hover { background: rgba(255,255,255,.16); }
/* "You are here" — inverted from v1's white-on-blue, since the whole pane
   is blue now: a light pill reads as selected the way the row highlight did
   on the old white tree. */
.exp-tree a.exp-tree-cur, .exp-tree a.exp-tree-cur:hover {
  background: #fff; color: #12356e; font-weight: bold;
}
.exp-tree-msg { color: #e2ebfc; font-style: italic; font-size: 10px; }

.exp-main-pane { flex: 1 1 auto; min-width: 0; overflow: auto; background: #fff; padding: 6px; }
.exp-loading { margin: 4px 8px; color: #555; }

/* Large Icons — the default XP view this project's reference screenshot
   actually showed, replacing v1's Details table entirely (no more column
   headers or per-row text; a folder/file is now a tile, like the desktop). */
.exp-icongrid {
  display: flex; flex-wrap: wrap; align-content: flex-start; gap: 2px;
}
.exp-icon {
  width: 76px; display: flex; flex-direction: column; align-items: center;
  gap: 3px; padding: 6px 2px; border: 1px dotted transparent; border-radius: 2px;
  cursor: default; -webkit-user-select: none; user-select: none;
}
.exp-icon .icon { width: 32px; height: 32px; }
.exp-icon-label {
  font-size: 11px; text-align: center; line-height: 1.25; max-height: 2.5em;
  overflow: hidden; word-break: break-word; color: #000;
}
.exp-icon:hover { background: #e6f0fb; border-color: #a9c8ec; }
.exp-icon-sel, .exp-icon-sel:hover {
  background: #316ac5; border-color: #10318f;
}
.exp-icon-sel .exp-icon-label { color: #fff; }

.exp-statusbar {
  flex: none; display: flex; font-size: 11px; border-top: 1px solid #d3d1c3;
}
.exp-status-field {
  padding: 2px 8px; border-right: 1px solid #d3d1c3;
  box-shadow: inset 1px 1px #dfdfdf; flex: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 260px;
}

/* Rename / Properties dialog bodies (XPUI.dialog hosted inside the Explorer
   window — see explorerStartRename/explorerShowProperties in app.js). */
.exp-rename-row label { display: block; width: 100%; }
.exp-rename-input { width: 100%; box-sizing: border-box; margin-top: 4px; font: inherit; }
.exp-rename-err { color: #b00000; font-size: 11px; min-height: 14px; margin-top: 2px; }
.exp-prop-icon { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.exp-prop-icon .icon { width: 28px; height: 28px; }
.exp-prop-k { display: inline-block; width: 70px; opacity: .75; }
