/* ============================================================
   Browser OS — shell, window manager and app styles
   ============================================================ */

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  font-family: var(--font);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

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

.hidden { display: none !important; }

.os { position: fixed; inset: 0; }

/* ---------- wallpaper ---------- */
.wallpaper {
  position: absolute; inset: 0;
  background: var(--wallpaper);
  background-size: cover;
  background-position: center;
}
.wallpaper::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(120% 90% at 50% 0%, rgba(255,255,255,.07), transparent 60%);
  pointer-events: none;
}
/* The animated layer (src/core/wallpaper.js) sits under the vignette and above
   the CSS gradient, and is hidden entirely when motion is off. */
.wallpaper-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* Arriving at a desktop that looks different should feel like arriving: the new
   wallpaper fades in over the switch instead of cutting. src/core/theme.js adds
   this class only when the picture actually changed. */
.wallpaper.swap { animation: wallpaper-swap .42s cubic-bezier(.2, .8, .2, 1); }
@keyframes wallpaper-swap {
  from { opacity: .18; transform: scale(1.045); }
  to { opacity: 1; transform: none; }
}
/* The time-of-day wash (src/core/daylight.js). It goes on the layer that is
   actually painting the desktop: when the animated canvas is drawing, the tint is
   mixed into its palette instead and this stays empty — the same paint twice would
   just be a darker desktop. */
.daylight-tint {
  position: absolute; inset: 0; pointer-events: none;
  background: none; opacity: 0; transition: opacity .9s ease;
}
.daylight-tint.on { opacity: 1; }
/* A preview of the desktop wears the same wash as the desktop, so a taskbar chip,
   a task-view card or a Settings row is never a picture of a different hour.
   `::before` on purpose: it sits above the background and below the windows drawn
   inside a task-view card, exactly like the real wash does. */
.ws-swatch, .ws-look-swatch { position: relative; }
.ws-swatch::before, .ws-look-swatch::before, .tv-preview::before {
  content: ""; position: absolute; inset: 0; background: var(--daylight-tint); pointer-events: none;
}
@media (prefers-reduced-motion: reduce) { .daylight-tint { transition: none; } }

/* ---------- desktop + icons ---------- */
.desktop { position: absolute; inset: 0 0 var(--taskbar-h) 0; overflow: hidden; outline: none; }
/* A finger on the worktop belongs to the desktop, not to the browser's pan-and-pinch.
   Without this Chromium cancels the pointer as soon as a swipe starts, and a swipe is
   the whole point of src/core/gestures.js. */
.desktop { touch-action: none; }

/* Icons are positioned by the shell on a loose grid (see src/core/shell.js: CELL/PAD). */
.desktop-icons { position: absolute; inset: 0; }

.dicon {
  position: absolute; width: 96px;
  border: 0; background: transparent; color: var(--text);
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 8px 4px; border-radius: var(--radius-sm); cursor: grab;
  user-select: none; -webkit-user-select: none; touch-action: none;
  transition: background .12s ease, box-shadow .12s ease, transform .12s ease;
}
.dicon:hover { background: var(--hover); }
.dicon.selected { background: var(--accent-soft); outline: 2px solid var(--accent); outline-offset: -2px; }
.dicon.selected .glyph { border-color: var(--accent); box-shadow: 0 6px 16px rgba(0,0,0,.28), 0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent); }
/* A tick so a multi-selection reads as selected, not as "focused window". */
.dicon.selected::after {
  content: "✓"; position: absolute; top: 2px; right: 4px; width: 16px; height: 16px;
  display: grid; place-items: center; font-size: 11px; line-height: 1; border-radius: 50%;
  background: var(--accent); color: #fff; pointer-events: none;
}
.dicon:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; outline-style: dashed; }
.dicon.dragging {
  z-index: 4; cursor: grabbing; background: var(--accent-soft);
  transform: scale(1.06); box-shadow: 0 16px 34px rgba(0,0,0,.42);
}
/* The grid cell a dragged icon is about to land in. */
.icon-slot {
  position: absolute; pointer-events: none; z-index: 3; border-radius: var(--radius-sm);
  border: 2px dashed color-mix(in srgb, var(--accent) 70%, transparent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
/* Rubber-band selection. */
.marquee {
  position: absolute; pointer-events: none; z-index: 2; border-radius: 4px;
  border: 1px solid var(--accent); background: var(--accent-soft);
}
/* The worktop's selection bar (Shell.#renderSelectionBar): it exists only while icons
   are selected, and it is the one place the *group* actions are reachable without a
   right-click. It rises from the bottom of the desk like the gesture note does. */
.desk-selection {
  position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%);
  z-index: 6; display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  justify-content: center; padding: 8px 10px; max-width: min(760px, calc(100vw - 28px));
  border: 1px solid var(--border); border-radius: 14px;
  background: var(--surface); backdrop-filter: blur(18px) saturate(140%);
  box-shadow: var(--shadow-window); animation: gesture-rise .16s cubic-bezier(.2,.9,.3,1);
}
.dsel-count {
  font-size: 12px; font-weight: 700; letter-spacing: .1px; color: var(--text);
  padding: 4px 8px; border-radius: 999px; background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); white-space: nowrap;
}
.desk-selection .btn { white-space: nowrap; }
/* A shortcut cannot be deleted, and the bar should say why its Delete is dark. */
.desk-selection .btn[disabled] { opacity: .45; }
@media (prefers-reduced-motion: reduce) { .desk-selection { animation: none; } }
.dicon .glyph {
  width: 46px; height: 46px; display: grid; place-items: center;
  font-size: 26px; border-radius: 10px;
  background: linear-gradient(160deg, var(--surface-2), var(--surface-solid));
  border: 1px solid var(--border);
  box-shadow: 0 6px 16px rgba(0,0,0,.28);
}
.dicon .label {
  font-size: 12px; line-height: 1.25; text-align: center; max-width: 92px;
  color: var(--desk-ink); text-shadow: var(--desk-ink-shadow);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* ---------- sticky notes on the desktop ---------- */
/* A pinned note lives on the worktop, under the windows (Shell.renderStickies).
   The layer itself must never eat a desktop click or a rubber-band drag. */
.stickies { position: absolute; inset: 0; pointer-events: none; }
.sticky {
  position: absolute; pointer-events: auto; display: flex; flex-direction: column;
  min-width: 120px; min-height: 90px;
  background: var(--sticky-bg, #f2d34e); color: var(--sticky-ink, #3a2f06);
  border: 1px solid rgb(0 0 0 / .18); border-radius: 4px;
  box-shadow: 0 10px 22px rgb(0 0 0 / .35), 0 1px 0 rgb(255 255 255 / .35) inset;
  transition: box-shadow .14s ease, transform .14s ease;
}
.sticky:hover { box-shadow: 0 14px 28px rgb(0 0 0 / .42); }
.sticky.dragging { transform: rotate(-1.2deg) scale(1.02); box-shadow: 0 22px 40px rgb(0 0 0 / .5); }
.sticky-head {
  display: flex; align-items: center; gap: 6px; padding: 5px 6px 4px;
  cursor: grab; user-select: none; -webkit-user-select: none; touch-action: none;
  border-bottom: 1px solid rgb(0 0 0 / .14);
}
.sticky-grip { font-size: 12px; opacity: .5; letter-spacing: -2px; }
.sticky-title { flex: 1; min-width: 0; font-size: 12px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sticky-btn {
  width: 20px; height: 20px; flex: 0 0 auto; display: grid; place-items: center;
  border: 1px solid transparent; border-radius: 4px; background: rgb(0 0 0 / .08);
  color: inherit; font-size: 11px; line-height: 1; cursor: pointer;
}
.sticky-btn:hover { background: rgb(0 0 0 / .2); }
.sticky-btn.danger:hover { background: var(--danger); color: #fff; }
.sticky-body {
  flex: 1; min-height: 0; padding: 8px 9px; border: 0; background: transparent; color: inherit;
  font-family: var(--font); font-size: 13px; line-height: 1.45; resize: none; outline: none;
  /* A note longer than its sticky is scrollable rather than silently cut off. */
  overflow: auto; overscroll-behavior: contain;
}
.sticky-body::-webkit-scrollbar { width: 8px; height: 8px; }
.sticky-body::-webkit-scrollbar-thumb { background: rgb(0 0 0 / .22); border-radius: 8px; }
.sticky-body::placeholder { color: rgb(0 0 0 / .38); }
.sticky-rz { position: absolute; right: 0; bottom: 0; width: 15px; height: 15px; cursor: nwse-resize; touch-action: none; }
.sticky-rz::after {
  content: ""; position: absolute; right: 3px; bottom: 3px; width: 8px; height: 8px;
  border-right: 2px solid rgb(0 0 0 / .3); border-bottom: 2px solid rgb(0 0 0 / .3); border-radius: 0 0 3px 0;
}

/* ---------- the desktop clock widget (src/core/desk-clock.js) ---------- */
/* Drawn straight onto the worktop, like an icon label: no panel of its own, so it
   uses --desk-ink / --desk-ink-shadow and stays readable on a pale wallpaper in the
   dark theme. The layer must never eat a desktop click or a rubber-band drag. */
.desk-clock-layer { position: absolute; inset: 0; pointer-events: none; }
.desk-clock {
  position: absolute; pointer-events: auto; width: var(--dc-w, 260px);
  display: flex; flex-direction: column; gap: 7px;
  padding: 10px 12px 12px; border-radius: 14px;
  color: var(--desk-ink); text-shadow: var(--desk-ink-shadow);
  user-select: none; -webkit-user-select: none; touch-action: none; cursor: grab;
  transition: background .14s ease, box-shadow .14s ease, transform .14s ease;
}
.desk-clock:hover {
  background: color-mix(in srgb, var(--desk-ink) 9%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--desk-ink) 16%, transparent);
}
/* The worktop is focusable, so it has to look focused: a control you can only reach
   with Ctrl+Alt+C is a control you need to see when you get there. `data-kbd` is set
   by the shell putting the keyboard on it — a focus nobody typed their way to still
   has to look like a focus. */
.desk-clock:focus-visible, .desk-clock[data-kbd] {
  outline: 2px solid var(--accent); outline-offset: 3px;
  background: color-mix(in srgb, var(--desk-ink) 9%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--desk-ink) 16%, transparent);
}
.desk-clock.dragging { cursor: grabbing; transform: scale(1.015); }
.dc-face { display: flex; align-items: center; gap: 14px; }
.dc-face-digital { display: block; }

/* The dial. One 100×100 drawing scaled by --dc-dial, so every size is the same clock. */
.dc-dial { width: var(--dc-dial); height: var(--dc-dial); display: block; flex: 0 0 auto; }
.dc-dial-face {
  fill: color-mix(in srgb, var(--desk-ink) 14%, transparent);
  stroke: color-mix(in srgb, var(--desk-ink) 30%, transparent); stroke-width: 1;
}
.dc-ticks line { stroke: var(--desk-ink); }
.dc-ticks .major { stroke-width: 1.7; opacity: .8; }
.dc-ticks .minor { stroke-width: .6; opacity: .32; }
.dc-numerals text {
  fill: var(--desk-ink); font-family: var(--font); font-size: 11px; font-weight: 700; opacity: .72;
}
.dc-hand { stroke: var(--desk-ink); stroke-linecap: round; }
.dc-hour { stroke-width: 3.4; }
.dc-minute { stroke-width: 2.1; }
/* The second hand, the centre pin and the ring of the day are the accent: the one
   place on the worktop that is clearly the machine's, not the wallpaper's. */
.dc-second { stroke: var(--accent); stroke-width: 1.1; }
.dc-cap { fill: var(--accent); }
.dc-day-arc { fill: none; stroke: var(--accent); stroke-width: 2.6; stroke-linecap: round; opacity: .85; }

/* The read-out. Numerals are tabular so a ticking clock does not shuffle its own width. */
.dc-digital { display: flex; align-items: baseline; gap: 5px; min-width: 0; }
.dc-time {
  font-weight: 700; font-size: var(--dc-fs, 44px); line-height: 1.02;
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.dc-seconds { font-weight: 600; font-size: calc(var(--dc-fs, 44px) * .4); opacity: .6; font-variant-numeric: tabular-nums; }
.dc-suffix { font-weight: 700; font-size: calc(var(--dc-fs, 44px) * .34); opacity: .72; letter-spacing: .06em; }
.dc-size-small { --dc-fs: 40px; }
.dc-size-medium { --dc-fs: 52px; }
.dc-size-large { --dc-fs: 68px; }
/* A split face writes the time in the column beside the dial, which is narrower. */
.dc-face-split { --dc-fs: 34px; }
.dc-face-split.dc-size-medium { --dc-fs: 44px; }
.dc-face-split.dc-size-large { --dc-fs: 56px; }

.dc-date {
  font-size: 11.5px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  opacity: .7; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* How much of today has gone — the same fact the dial draws as a ring. */
.dc-day { height: 3px; border-radius: 3px; overflow: hidden; background: color-mix(in srgb, var(--desk-ink) 18%, transparent); }
.dc-day-fill { display: block; height: 100%; background: var(--accent); border-radius: 3px; }

.dc-upnext { display: flex; flex-direction: column; gap: 4px; }
.dc-row { display: grid; grid-template-columns: 15px minmax(0, 1fr) auto; gap: 7px; align-items: baseline; font-size: 12.5px; }
.dc-row-glyph { opacity: .8; }
.dc-row-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: .82; }
.dc-row-time { font-weight: 700; font-variant-numeric: tabular-nums; }
.dc-row-bar { grid-column: 1 / -1; display: block; height: 2px; border-radius: 2px; background: color-mix(in srgb, var(--desk-ink) 20%, transparent); }
.dc-row-bar b { display: block; height: 100%; border-radius: 2px; background: var(--accent); }
.dc-row-stopwatch .dc-row-time { color: var(--accent); }
.dc-empty { font-size: 11.5px; opacity: .48; font-style: italic; }

/* A row is something running, so hovering it offers the thing you can do to it. The
   button takes the glyph's exact cell: the row never changes shape, and the action
   appears out of the symbol it was. */
.dc-row { grid-template-columns: 20px minmax(0, 1fr) auto; }
.dc-row-glyph, .dc-row-act { grid-column: 1; grid-row: 1; }
/* Each cell is named, so a row that drops its label (a narrow dial) does not shove the
   countdown into the name's place. */
.dc-row-label { grid-column: 2; grid-row: 1; }
.dc-row-time { grid-column: 3; grid-row: 1; }
.dc-row-glyph { transition: opacity .12s ease; }
.dc-row-act {
  width: 20px; height: 18px; min-width: 20px; padding: 0; font-size: 10px; align-self: center;
  opacity: 0; transition: opacity .12s ease;
}
.dc-row:hover .dc-row-glyph, .dc-row:focus-within .dc-row-glyph { opacity: 0; }
.dc-row:hover .dc-row-act, .dc-row:focus-within .dc-row-act, .dc-row-act:focus { opacity: 1; }

/* An alarm that rang and nobody answered. It is the only part of the worktop that
   asks for something, so it is drawn above the list, in the accent, and the whole
   clock breathes while it is waiting. */
.dc-ring { display: flex; flex-direction: column; gap: 4px; }
.dc-ring[hidden] { display: none; }
.dc-ring-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  padding: 4px 6px; border-radius: 9px; font-size: 12.5px;
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
}
.dc-ring-when { font-weight: 700; font-variant-numeric: tabular-nums; }
.dc-ring-row .dc-row-label { flex: 1 1 90px; min-width: 0; opacity: 1; }
.dc-ring-ago { font-size: 11px; opacity: .72; margin-left: auto; }
/* The two answers belong together: they are one decision, not two loose buttons. */
.dc-ring-acts { display: inline-flex; gap: 4px; }
.desk-clock.ringing {
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 55%, transparent);
  animation: desk-clock-ring 2.6s ease-in-out infinite;
}
@keyframes desk-clock-ring {
  0%, 100% { background: color-mix(in srgb, var(--accent) 4%, transparent); }
  50% { background: color-mix(in srgb, var(--accent) 14%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .desk-clock.ringing { animation: none; } }
.dc-world { display: flex; flex-direction: column; gap: 2px; border-top: 1px solid color-mix(in srgb, var(--desk-ink) 18%, transparent); padding-top: 5px; }
.dc-city { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 8px; font-size: 12px; }
.dc-city-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: .82; }
.dc-city-day { font-size: 10.5px; opacity: .55; }
.dc-city-time { font-weight: 700; font-variant-numeric: tabular-nums; }

/* The tools only appear when you are pointing at the clock or standing on it with the keyboard. */
.dc-tools {
  position: absolute; top: 4px; right: 6px; display: flex; gap: 3px;
  opacity: 0; transition: opacity .14s ease;
}
.desk-clock:hover .dc-tools, .desk-clock:focus-within .dc-tools, .desk-clock:focus-visible .dc-tools, .desk-clock[data-kbd] .dc-tools { opacity: 1; }
.dc-tool {
  width: 22px; height: 22px; display: grid; place-items: center; font-size: 12px; line-height: 1;
  border: 1px solid color-mix(in srgb, var(--desk-ink) 26%, transparent); border-radius: 6px;
  background: color-mix(in srgb, var(--desk-ink) 12%, transparent); color: var(--desk-ink); cursor: pointer;
}
.dc-tool:hover { background: var(--accent); border-color: var(--accent); color: #fff; text-shadow: none; }

/* The controls. They are always on the clock and quiet until you point at it or stand
   on it: a control you cannot see is a control nobody knows the clock has. */
.dc-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  opacity: .46; transition: opacity .14s ease;
}
.desk-clock:hover .dc-actions, .desk-clock:focus-within .dc-actions, .desk-clock:focus-visible .dc-actions, .desk-clock[data-kbd] .dc-actions { opacity: 1; }
.dc-ctl {
  min-width: 30px; height: 22px; padding: 0 7px; display: inline-grid; place-items: center;
  font: inherit; font-size: 11.5px; font-weight: 700; line-height: 1; letter-spacing: .02em;
  border: 1px solid color-mix(in srgb, var(--desk-ink) 26%, transparent); border-radius: 7px;
  background: color-mix(in srgb, var(--desk-ink) 10%, transparent); color: var(--desk-ink);
  text-shadow: none; cursor: pointer;
}
.dc-ctl:hover { background: var(--accent); border-color: var(--accent); color: #fff; }
.dc-sw { min-width: 26px; padding: 0 5px; }
.dc-sw.running { background: color-mix(in srgb, var(--accent) 34%, transparent); border-color: var(--accent); }
.dc-act { min-width: 18px; }

/* One paragraph a screen reader reads and nobody sees. */
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* A face preview in Settings: the real widget, scaled, with no gestures. It uses the
   window's own ink rather than the worktop's, because it is standing in a window. */
.dc-preview {
  position: relative; overflow: hidden;
  --desk-ink: var(--text); --desk-ink-shadow: none;
}
.dc-preview .desk-clock { transform: scale(var(--dc-scale, 1)); transform-origin: top left; cursor: default; }

/* ---------- windows ---------- */
.windows-layer { position: absolute; inset: 0 0 var(--taskbar-h) 0; pointer-events: none; }

.window {
  position: absolute; pointer-events: auto;
  display: flex; flex-direction: column;
  min-width: 240px; min-height: 140px;
  background: var(--surface); backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-window);
  overflow: hidden;
  animation: win-in .16s cubic-bezier(.2,.9,.3,1);
  contain: layout paint;
}
@keyframes win-in { from { opacity: 0; transform: scale(.97) translateY(6px); } to { opacity: 1; transform: none; } }
.window.focused { border-color: color-mix(in srgb, var(--accent) 55%, var(--border)); }
.window.minimized { display: none; }
.window.maximized { border-radius: 0; border-color: transparent; }
.window.closing { animation: win-out .12s ease forwards; }
@keyframes win-out { to { opacity: 0; transform: scale(.96); } }
.window.minimizing { animation: win-min .17s cubic-bezier(.4,0,.6,1) forwards; transform-origin: 50% 100%; }
@keyframes win-min { to { opacity: 0; transform: scale(.55) translateY(46px); } }
.window.restoring { animation: win-restore .2s cubic-bezier(.2,.9,.3,1); transform-origin: 50% 100%; }
@keyframes win-restore { from { opacity: 0; transform: scale(.55) translateY(46px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .window, .window.closing, .window.minimizing, .window.restoring, .window.ws-enter,
  .launcher-panel, .context-menu, .toast, .snap-preview, .tray-badge, .ws-btn.flash,
  .ws-btn.drop, .workspaces.armed::before, .notifications, .titem.attention,
  .wallpaper.swap, .desk-look, .carry-zone, .carry-hint, .snap-zone, .snap-hint,
  .notify-btn.has-unread .nb-glyph {
    animation: none !important; transition: none !important;
  }
}

.titlebar {
  height: var(--titlebar-h); flex: 0 0 auto;
  display: flex; align-items: center; gap: 8px;
  padding: 0 6px 0 10px;
  background: linear-gradient(180deg, var(--surface-2), transparent);
  border-bottom: 1px solid var(--border);
  cursor: move; touch-action: none; user-select: none;
}
.window:not(.focused) .titlebar { opacity: .72; }
.titlebar .wicon { font-size: 15px; }
.titlebar .wtitle {
  flex: 1; font-size: 13px; font-weight: 600; letter-spacing: .1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wcontrols { display: flex; gap: 2px; }
.wbtn {
  width: 26px; height: 24px; border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--text-dim); cursor: pointer;
  display: grid; place-items: center; font-size: 13px;
}
.wbtn:hover { background: var(--hover); color: var(--text); }
.wbtn.close:hover { background: var(--danger); color: #fff; }

.wbody { flex: 1; min-height: 0; position: relative; overflow: auto; }
.window.maximized .wbody { border-radius: 0; }

.rz { position: absolute; z-index: 5; }
.rz-n { top: -3px; left: 8px; right: 8px; height: 7px; cursor: ns-resize; }
.rz-s { bottom: -3px; left: 8px; right: 8px; height: 7px; cursor: ns-resize; }
.rz-w { left: -3px; top: 8px; bottom: 8px; width: 7px; cursor: ew-resize; }
.rz-e { right: -3px; top: 8px; bottom: 8px; width: 7px; cursor: ew-resize; }
.rz-nw { left: -4px; top: -4px; width: 14px; height: 14px; cursor: nwse-resize; }
.rz-ne { right: -4px; top: -4px; width: 14px; height: 14px; cursor: nesw-resize; }
.rz-sw { left: -4px; bottom: -4px; width: 14px; height: 14px; cursor: nesw-resize; }
.rz-se { right: -4px; bottom: -4px; width: 14px; height: 14px; cursor: nwse-resize; }
.window.maximized .rz { display: none; }

.snap-preview {
  position: absolute; z-index: 99999; pointer-events: none;
  border: 2px solid var(--accent); border-radius: var(--radius);
  background: var(--accent-soft);
  transition: all .09s linear;
}

/* ---------- the tiling guide ---------- */
/* The tiles themselves, drawn on the desktop at the two moments they are worth seeing:
   while a window is held by its title bar (the tile it would land in is lit), and while
   Alt is held (every tile labelled with the key that claims it). It never takes a click
   and it never moves a window — it is the half of tiling that used to live only in the
   right-click menu. The carry guide below is the same idea for a keyboard drag. */
.snap-guide {
  position: absolute; inset: 0 0 var(--taskbar-h) 0; z-index: 99997; pointer-events: none;
}
.snap-zone {
  position: absolute; padding: 8px 11px; display: flex; align-items: flex-start; gap: 8px;
  border: 1.5px dashed color-mix(in srgb, var(--accent) 55%, transparent);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 6%, transparent);
  color: var(--text-dim); opacity: .62;
  transition: opacity .12s linear, border-color .12s linear, background .12s linear;
}
.snap-zone > * { text-shadow: 0 1px 3px rgb(0 0 0 / .55); }
.snap-zone .sz-glyph { font-size: 15px; line-height: 1; }
.snap-zone .sz-label {
  font-size: 10.5px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
}
.snap-zone .sz-chord {
  font: inherit; font-size: 10.5px; padding: 1px 5px; border-radius: 5px;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text);
}
/* A key with no Alt in it cannot be pressed while Alt is held — the guide draws it
   dashed and dimmer so it reads as "after this one", not as a mistake. */
.snap-zone .sz-chord.needs-release { border-style: dashed; opacity: .62; }
.snap-zone.active {
  opacity: 1; border-style: solid; border-width: 2px; border-color: var(--accent);
  background: var(--accent-soft); color: var(--text);
  box-shadow: inset 0 0 46px color-mix(in srgb, var(--accent) 22%, transparent);
}
.snap-zone.active .sz-glyph { font-size: 19px; }
/* The lit tile is usually behind the window that is about to fill it, so the one part
   of it still visible — its name — has to say "this one" in the loudest way available. */
.snap-zone.active .sz-label { color: var(--accent); }
.snap-zone.active .sz-chord { border-color: var(--accent); color: var(--text); }
/* A tile that is not in question is still drawn — the point of the guide is the whole
   grid, and a grid you cannot see teaches nothing. */
.snap-zone.dimmed { opacity: .34; }
/* Each label goes to the part of the border that belongs to it and to nothing else:
   a half names its outer edge, a quarter names its outer corner, the whole desktop
   names the top centre. Anchored any other way they land on top of each other, since
   every tile shares a border with two others. */
.snap-zone[data-zone="left"] { align-items: center; }
.snap-zone[data-zone="right"] { align-items: center; justify-content: flex-end; }
.snap-zone[data-zone="tl"] { align-items: flex-start; justify-content: flex-start; }
.snap-zone[data-zone="tr"] { align-items: flex-start; justify-content: flex-end; }
.snap-zone[data-zone="bl"] { align-items: flex-end; justify-content: flex-start; }
.snap-zone[data-zone="br"] { align-items: flex-end; justify-content: flex-end; }
/* Full screen is not a seventh tile: it is the whole desktop, so it is drawn as a band
   around everything else and named at the top centre, out of the way of the quarters. */
.snap-zone.full {
  border-style: dotted; background: transparent; opacity: .2;
  justify-content: center; align-items: flex-start; padding: 6px 11px;
}
.snap-zone.full.active { opacity: 1; background: color-mix(in srgb, var(--accent) 14%, transparent); }
.snap-hint {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: 12px; max-width: min(720px, calc(100% - 32px));
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 8px 14px; border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface); backdrop-filter: blur(18px) saturate(140%);
  box-shadow: var(--shadow-window); text-align: center;
}
.snap-hint .sh-text { font-size: 12.5px; font-weight: 700; }
.snap-hint .sh-keys { display: flex; flex-wrap: wrap; justify-content: center; gap: 3px 12px; }
.snap-hint .sh-key { display: inline-flex; align-items: baseline; gap: 5px; font-size: 11px; color: var(--text-dim); }
.snap-hint .sh-key kbd {
  font: inherit; font-size: 10.5px; padding: 1px 5px; border-radius: 5px;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text);
}
/* Both hints live above the taskbar strip, so during a drag they would print on top of
   each other. The tiling guide is the one explaining the gesture in hand; the desktop
   drop hint steps up above it rather than fighting it for the same line. */
.snap-guide:not(.hidden) ~ #taskbar .workspaces.armed::before { bottom: calc(100% + 62px); }

/* ---------- carrying a window with the keyboard ---------- */
/* The guide a carry draws: the six tiles a pointer drag would have offered, and one
   line saying where the window is and what the keys do. It never takes a click. */
.carry-guide {
  position: absolute; inset: 0 0 var(--taskbar-h) 0; z-index: 99998; pointer-events: none;
}
.carry-zone {
  position: absolute; padding: 7px 10px;
  border: 1.5px dashed color-mix(in srgb, var(--accent) 42%, transparent);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 5%, transparent);
  display: flex; align-items: center; gap: 7px;
  color: var(--text-dim); opacity: .5;
  transition: opacity .1s linear, border-color .1s linear, background .1s linear;
}
.carry-zone .cz-glyph { font-size: 14px; line-height: 1; }
.carry-zone .cz-label {
  font-size: 10.5px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
}
.carry-zone.active {
  opacity: 1; border-style: solid; border-color: var(--accent);
  background: var(--accent-soft); color: var(--text);
}
/* Labels hug the outer edge of the screen, so a tile is never mistaken for its
   neighbour across the seam. */
.carry-zone[data-zone="right"], .carry-zone[data-zone="tr"], .carry-zone[data-zone="br"] { justify-content: flex-end; }
.carry-hint {
  /* Placed by the window manager just outside the window being held, so the keys are
     written next to the thing they move. It follows the window. */
  position: absolute; left: 0; top: 0;
  width: max-content; max-width: min(600px, calc(100% - 24px));
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px;
  padding: 8px 13px; border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface); backdrop-filter: blur(18px) saturate(140%);
  box-shadow: var(--shadow-window);
  transition: top .12s cubic-bezier(.2,.9,.3,1), left .12s cubic-bezier(.2,.9,.3,1);
}
.ch-status { font-size: 12.5px; font-weight: 700; flex: 1 0 100%; }
.ch-keys { display: flex; flex-wrap: wrap; gap: 3px 12px; }
.ch-key { display: inline-flex; align-items: baseline; gap: 5px; font-size: 11px; color: var(--text-dim); }
.ch-key kbd {
  font: inherit; font-size: 10.5px; padding: 1px 5px; border-radius: 5px;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text);
}

/* The window being held: outlined rather than shadowed, so it reads as *picked up*
   instead of merely in front. */
.window.carrying {
  outline: 2px dashed var(--accent); outline-offset: 3px;
  border-color: color-mix(in srgb, var(--accent) 70%, var(--border));
  box-shadow: 0 26px 64px rgba(0,0,0,.45), 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
}
.window.carrying .titlebar { background: linear-gradient(180deg, var(--accent-soft), transparent); }

/* ---------- gestures on the worktop ---------- */
/* What a finger, a trackpad or a held mouse button looks like while it is happening.
   The rules are in `src/core/gestures-core.js`; this is only the feedback: a ring that
   fills while you hold, a wash on the edge you are swiping towards, and a guide that
   names the desktop a swipe is heading for. It never takes a click and it never moves
   a window — the tiling and carry guides above are the same idea for other inputs. */
.desk-gestures {
  position: absolute; inset: 0 0 var(--taskbar-h) 0; z-index: 99996; pointer-events: none;
}

/* The ring a held press fills. It completes exactly when the menu opens, so "how long
   is a hold" is something you can see rather than something you have to trust. */
.gesture-hold {
  position: absolute; width: 58px; height: 58px; margin: -29px 0 0 -29px; border-radius: 50%;
  /* A dark backing first: the ring has to read against a bright wallpaper as well as
     a dark one, and a mask clips box-shadows. */
  background: radial-gradient(closest-side, rgb(0 0 0 / .38), rgb(0 0 0 / .16) 74%, transparent);
  animation: gesture-pop .18s cubic-bezier(.2,.9,.3,1);
}
.gesture-hold::before {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from -90deg,
    var(--accent) calc(var(--hold, 0) * 1turn),
    color-mix(in srgb, var(--text) 34%, transparent) 0);
  mask: radial-gradient(closest-side, transparent 66%, #000 67%);
  -webkit-mask: radial-gradient(closest-side, transparent 66%, #000 67%);
  filter: drop-shadow(0 0 10px color-mix(in srgb, var(--accent) 35%, transparent));
}
@keyframes gesture-pop { from { transform: scale(.55); opacity: 0; } to { transform: scale(1); opacity: 1; } }

/* A wash on the edge the finger is travelling towards, so a swipe has a direction even
   before the guide has finished drawing itself. */
.desk-gestures::before, .desk-gestures::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 190px; opacity: 0;
  transition: opacity .14s linear;
}
.desk-gestures::before { left: 0; background: linear-gradient(90deg, var(--accent-soft), transparent); }
.desk-gestures::after { right: 0; background: linear-gradient(270deg, var(--accent-soft), transparent); }
.desk-gestures[data-axis="x"][data-gesture="swipe-left"]::before { opacity: .85; }
.desk-gestures[data-axis="x"][data-gesture="swipe-right"]::after { opacity: .85; }

.gesture-guide {
  position: absolute; left: 50%; bottom: 16px; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 12px 15px 13px; max-width: min(760px, calc(100vw - 28px));
  border: 1px solid var(--border); border-radius: 14px;
  background: var(--surface); backdrop-filter: blur(18px) saturate(140%);
  box-shadow: var(--shadow-window);
  animation: gesture-rise .16s cubic-bezier(.2,.9,.3,1);
}
@keyframes gesture-rise { from { transform: translate(-50%, 12px); opacity: 0; } to { transform: translate(-50%, 0); opacity: 1; } }

.gesture-note { display: flex; align-items: center; gap: 10px; }
.gesture-arrow {
  font-size: 19px; line-height: 1; color: var(--accent);
  text-shadow: 0 0 14px color-mix(in srgb, var(--accent) 45%, transparent);
}
.gesture-text { font-size: 13px; font-weight: 700; letter-spacing: .1px; }

/* How far through the gesture you are: the same number the recogniser uses to decide
   whether it is a swipe at all. */
.gesture-meter { width: 100%; height: 3px; border-radius: 3px; background: var(--surface-2); overflow: hidden; }
.gesture-meter i {
  display: block; height: 100%; background: var(--accent);
  transform-origin: left center; transform: scaleX(0);
}

/* The desktops, in the order a swipe would take you through them, each wearing its own
   wallpaper — the same previews the taskbar strip and the task view draw. */
.gesture-rail { display: flex; align-items: stretch; gap: 8px; flex-wrap: wrap; justify-content: center; }
.gesture-card {
  display: flex; flex-direction: column; gap: 3px; width: 138px; padding: 7px 9px 8px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface-2);
  opacity: .42; transition: opacity .12s linear, border-color .12s linear, background .12s linear;
}
.gesture-card.current {
  opacity: 1; border-color: var(--border-strong); background: var(--surface-3);
}
.gesture-card.current .gc-n {
  background: var(--accent); color: var(--surface-solid); border-radius: 5px;
  padding: 1px 5px; box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent);
}
.gesture-card.current .gc-name { color: var(--text); }
.gesture-card.target {
  opacity: 1; border-color: var(--accent); background: var(--accent-soft);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
}
.gc-swatch {
  position: relative; display: block; height: 30px; border-radius: 6px; border: 1px solid var(--border-strong);
  /* A desktop that inherits wears the real wallpaper, exactly as the taskbar chips and
     the task view do; one that has its own look wears that instead. */
  background: var(--wallpaper-default);
  background-image: var(--gc-swatch, var(--wallpaper-default));
  background-size: cover; background-position: center;
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / .22);
}
.gc-swatch::before {
  content: ''; position: absolute; inset: 0; border-radius: 6px;
  background: var(--daylight-tint); pointer-events: none;
}
.gc-row { display: flex; align-items: baseline; gap: 6px; }
.gc-n { font-size: 11px; font-weight: 800; color: var(--accent); }
.gc-name { font-size: 11.5px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gc-w { margin-left: auto; font-size: 10px; color: var(--text-dim); white-space: nowrap; }

/* A gesture that is not a journey between desktops: one card saying what it does. */
.gesture-action { display: flex; align-items: center; gap: 11px; }
.ga-glyph {
  font-size: 22px; line-height: 1; color: var(--accent);
  text-shadow: 0 0 16px color-mix(in srgb, var(--accent) 40%, transparent);
}
.ga-label { font-size: 14px; font-weight: 800; }
.ga-hint { font-size: 11.5px; color: var(--text-dim); }

/* ---------- taskbar ---------- */
.taskbar {
  position: absolute; left: 0; right: 0; bottom: 0; height: var(--taskbar-h);
  display: flex; align-items: center; gap: 8px; padding: 0 8px;
  background: var(--surface); backdrop-filter: blur(20px) saturate(150%);
  border-top: 1px solid var(--border);
  z-index: 100000;
}
.start-btn {
  display: flex; align-items: center; gap: 8px;
  height: 34px; padding: 0 12px; border-radius: var(--radius-sm);
  border: 1px solid transparent; background: transparent; color: var(--text);
  cursor: pointer; font-weight: 600; font-size: 13px;
}
.start-btn:hover, .start-btn.open { background: var(--accent-soft); border-color: var(--accent); }
.start-logo {
  width: 18px; height: 18px; border-radius: 5px;
  background: conic-gradient(from 20deg, var(--accent), var(--accent-2), var(--accent));
  box-shadow: 0 0 12px var(--accent-soft);
}
.taskbar-items { flex: 1; display: flex; gap: 4px; overflow: hidden; }
.titem {
  display: flex; align-items: center; gap: 7px; max-width: 220px;
  height: 34px; padding: 0 10px; border-radius: var(--radius-sm);
  border: 1px solid transparent; background: var(--hover); color: var(--text);
  cursor: pointer; font-size: 12.5px;
}
.titem:hover { background: var(--active); }
.titem.focused { background: var(--accent-soft); border-color: var(--accent); }
.titem.minimized { opacity: .6; }
.titem .glyph { font-size: 15px; }
.titem .t { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.tray { display: flex; align-items: center; gap: 10px; padding-right: 6px; }
.tray-badges { display: flex; align-items: center; gap: 6px; }
.tray-badges:empty { display: none; }
.tray-badge {
  width: 28px; height: 28px; border-radius: 7px; display: grid; place-items: center;
  font-size: 14px; border: 1px solid var(--accent); background: var(--accent-soft); color: var(--accent);
  animation: badge-in 220ms cubic-bezier(.2, .9, .3, 1);
}
@keyframes badge-in { from { transform: scale(.6); opacity: 0; } to { transform: none; opacity: 1; } }
.tray-status { font-size: 12px; color: var(--text-dim); }
.tray-btn {
  width: 30px; height: 30px; border-radius: 7px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-dim);
  display: grid; place-items: center; font-size: 13px;
}
.tray-btn:hover { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }
.clock {
  font-size: 12.5px; text-align: right; line-height: 1.15; cursor: pointer;
  background: transparent; border: 0; color: var(--text); border-radius: 7px; padding: 2px 6px;
}
.clock:hover { background: var(--hover); }
.clock .time { font-variant-numeric: tabular-nums; font-weight: 600; }
.clock .date { color: var(--text-dim); font-size: 11px; }
/* Live countdowns in the tray: whatever the machine is timing, wherever you are. */
.tray-timers { display: flex; align-items: center; gap: 6px; max-width: 44vw; overflow: hidden; }
/* Countdowns are the first thing to give way: the clock, the launcher and the
   workspace chips have to stay reachable whatever someone has running. */
.tray-timers:empty { display: none; }
.tray-timer {
  display: flex; align-items: center; gap: 5px; height: 28px; padding: 0 9px; border-radius: 7px;
  border: 1px solid var(--accent); background: var(--accent-soft); color: var(--accent);
  font-family: var(--mono); font-size: 12px; font-variant-numeric: tabular-nums; cursor: pointer;
  animation: badge-in 220ms cubic-bezier(.2, .9, .3, 1);
}
.tray-timer:hover { background: var(--accent); color: #fff; }
.tray-timer-stopwatch { border-style: dashed; }
/* What a countdown is *for* — the tray is the only place you see it without opening
   the app, so an anonymous number would be a worse feature than a wide one. */
.tray-timer .tt-label { max-width: 14ch; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; opacity: .72; }

/* ---------- workspaces ---------- */
/* A window on another workspace is out of the layout entirely (src/core/wm.js
   toggles this class when the workspace model changes). */
.window.ws-hidden { display: none; }
/* A desktop switch slides what arrived in from the side it came from. */
.window.ws-enter { animation: ws-in .28s cubic-bezier(.2, .9, .3, 1); }
@keyframes ws-in {
  from { opacity: 0; transform: translateX(var(--ws-from, 40px)) scale(.985); }
  to { opacity: 1; transform: none; }
}

.workspaces { display: flex; align-items: center; gap: 4px; padding: 0 2px; position: relative; }
.ws-overview, .ws-add {
  width: 30px; height: 30px; border-radius: var(--radius-sm); flex: 0 0 auto;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-dim);
  display: grid; place-items: center; font-size: 14px; cursor: pointer;
}
.ws-overview:hover, .ws-add:hover { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }
.ws-add:disabled { opacity: .35; cursor: not-allowed; }
.ws-btn {
  position: relative;
  display: flex; align-items: center; gap: 6px; flex: 0 0 auto;
  min-width: 44px; max-width: 158px; height: 30px; padding: 0 8px;
  border-radius: var(--radius-sm); border: 1px solid transparent;
  background: var(--hover); color: var(--text-dim); cursor: pointer; font-size: 12px;
}
.ws-btn:hover { background: var(--active); color: var(--text); }
.ws-btn.current { background: var(--accent-soft); border-color: var(--accent); color: var(--text); }
.ws-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ws-btn.flash { animation: ws-flash .4s cubic-bezier(.2,.9,.3,1); }
@keyframes ws-flash { from { transform: translateY(4px) scale(.96); } to { transform: none; } }
.ws-n { font-variant-numeric: tabular-nums; font-weight: 700; opacity: .75; }
.ws-btn.current .ws-n { color: var(--accent); opacity: 1; }
.ws-name { max-width: 76px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ws-dots { display: flex; align-items: center; gap: 3px; }

/* A chip paints the desktop it stands for: the wallpaper that desktop has, edged
   with the accent it has. Inheriting desktops all show the default look, so a
   desktop with its own is the only one that stands out — and it gets a dot. */
.ws-swatch {
  width: 14px; height: 14px; border-radius: 4px; flex: 0 0 auto;
  border: 1px solid var(--border-strong); background: var(--wallpaper-default);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .22);
}
.ws-btn.has-look .ws-swatch { border-width: 2px; border-color: var(--ws-accent, var(--accent)); }
.ws-btn.has-look::after {
  content: ''; position: absolute; top: 2px; right: 2px; width: 6px; height: 6px;
  border-radius: 50%; background: var(--ws-accent, var(--accent)); box-shadow: 0 0 0 1px var(--surface-solid);
}
.workspaces.armed .ws-swatch { width: 18px; height: 18px; }
.ws-dot { font-size: 12px; opacity: .7; }
.ws-btn.current .ws-dot { opacity: 1; }
.ws-more { font-size: 11px; color: var(--text-faint); }

/* Dragging a window onto a desktop. While a drag is alive the strip *arms*: the
   chips grow, names show, and a hint says what the gesture is for. */
.workspaces.armed .ws-btn {
  max-width: 210px; height: 34px; border-color: var(--border-strong);
  background: var(--surface-2); color: var(--text);
}
.workspaces.armed .ws-add { border-color: var(--border-strong); color: var(--text); }
.workspaces.armed::before {
  content: "drop it on a desktop";
  position: absolute; right: calc(100% + 10px); bottom: calc(100% + 12px);
  padding: 5px 9px; border-radius: var(--radius-sm);
  border: 1px solid var(--accent); background: var(--surface); color: var(--text-dim);
  font-size: 11.5px; white-space: nowrap; box-shadow: var(--shadow-pop);
  animation: hint-in .18s cubic-bezier(.2, .9, .3, 1);
}
@keyframes hint-in { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }
.ws-btn.drop-target, .tv-card.drop-target {
  border-color: var(--accent) !important; background: var(--accent-soft) !important; color: var(--text) !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 28%, transparent);
}
.ws-btn.drop-target { transform: translateY(-3px) scale(1.04); }
.tv-card.drop-target { transform: translateY(-4px); }
.ws-btn.drop { animation: ws-drop .55s cubic-bezier(.2, .9, .3, 1); }
@keyframes ws-drop {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 60%, transparent); }
  55% { box-shadow: 0 0 0 9px color-mix(in srgb, var(--accent) 12%, transparent); }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* The chip that follows the pointer while you drag a window. It rides above and
   to the right of the cursor so the desktop you are aiming at stays visible. */
.drag-chip {
  position: fixed; z-index: 100006; pointer-events: none;
  transform: translate(-25%, -175%) rotate(-2deg);
  display: flex; align-items: center; gap: 7px; max-width: 240px;
  padding: 6px 10px; border-radius: var(--radius-sm);
  border: 1px solid var(--accent); background: var(--surface-2); color: var(--text);
  font-size: 12.5px; box-shadow: var(--shadow-pop);
}
.drag-chip .glyph { font-size: 15px; }
.drag-chip .t { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.titem.dragging, .tv-win.dragging { opacity: .35; }
.titem, .tv-win { touch-action: none; }

/* ---------- task view (every workspace at a glance) ---------- */
.task-view {
  position: absolute; inset: 0; z-index: 100002;
  background: rgb(6 8 14 / .66); backdrop-filter: blur(7px);
  display: flex; flex-direction: column; gap: 14px; padding: 26px 22px 22px;
  animation: pop-in .18s cubic-bezier(.2,.9,.3,1);
}
[data-theme='light'] .task-view { background: rgb(20 24 34 / .45); }
.tv-head { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.tv-title { font-size: 16px; font-weight: 700; color: var(--text); }
.tv-hint { font-size: 12px; color: var(--text-dim); }
.tv-grid { display: flex; gap: 14px; align-items: flex-start; overflow: auto; flex: 1; padding-bottom: 4px; }
.tv-card {
  flex: 0 0 300px; display: flex; flex-direction: column; gap: 8px;
  border: 1px solid var(--border); border-radius: var(--radius); padding: 10px;
  background: var(--surface); backdrop-filter: blur(18px) saturate(140%);
  box-shadow: var(--shadow-pop); cursor: pointer;
}
.tv-card.current { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft), var(--shadow-pop); }
.tv-card:hover { background: var(--surface-2); }
.tv-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.tv-card-head { display: flex; align-items: center; gap: 8px; padding: 2px 2px 7px; border-bottom: 1px solid var(--border); }
.tv-n { width: 20px; height: 20px; flex: 0 0 auto; border-radius: 5px; display: grid; place-items: center; background: var(--surface-3); font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums; }
.tv-card.current .tv-n { background: var(--accent); color: #fff; }
.tv-name { flex: 1 1 40px; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text); min-width: 0; }
/* A desktop with its own look says what it is, in the card, not just by colour. */
.tv-look {
  flex: 0 0 auto; max-width: 152px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 10px; padding: 2px 6px; border-radius: 999px;
  border: 1px solid var(--accent); color: var(--accent); background: var(--accent-soft);
}
.tv-count { font-size: 11px; color: var(--text-dim); flex: 0 0 auto; }
/* A to-scale miniature of the desktop, so the overview looks like the desktop. */
.tv-preview {
  position: relative; flex: 0 0 auto; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  /* The default, unless the card overrides it inline: an overview of four desktops
     must not be four pictures of whichever one you are standing on. */
  background-color: var(--surface-2); background-image: var(--wallpaper-default);
}
.tv-box {
  position: absolute; border: 1px solid var(--border-strong); border-radius: 3px;
  background: rgb(255 255 255 / .12); box-shadow: 0 1px 3px rgb(0 0 0 / .35);
}
.tv-box.focused { border-color: var(--accent); background: var(--accent-soft); }
.tv-box.minimized { opacity: .35; }
/* A window in the overview is a shrunken copy of the window, at the same scale as the
   desk's icons — see `miniature.js`. The outline above is what is left for a window
   whose element is gone. */
.tv-mini.focused { outline: 1px solid var(--accent); outline-offset: 1px; }
.tv-mini.minimized { opacity: .4; }
/* The desk, in the miniature: every item `desk-plan-core.js` says is on this desktop is
   drawn where the plan says it is, at the plan's scale — an icon this desktop draws, a
   sticky this desktop owns, the clock standing on it. A desktop that has taken items off
   it shows fewer of them, and a desktop with no clock draws no clock. */
.tv-item {
  position: absolute; pointer-events: auto; box-shadow: 0 1px 2px rgb(0 0 0 / .35);
  display: flex; align-items: center; justify-content: center; line-height: 1;
}
.tv-icon {
  min-width: 7px; min-height: 7px; border-radius: 3px;
  background: var(--accent-soft); border: 1px solid var(--accent);
}
.tv-sticky {
  min-width: 5px; min-height: 5px; border-radius: 2px;
  background: rgb(255 214 92 / .55); border: 1px solid rgb(0 0 0 / .35);
}
/* A clock on a card is the widget, not a dot. The dial keeps its own height so it stays
   round inside a wide face, and a read-out face is drawn as the bars of digits it is. */
.tv-clock {
  min-width: 8px; min-height: 8px; border-radius: 4px; overflow: hidden;
  background: var(--surface-2); border: 1px solid var(--border-strong);
}
/* A clock is one of the few things drawn on the desktop itself, so the card has to draw
   it as a clock: a round dial with a hand, or digits. A darker stripe on a dark panel is
   not a picture of anything. */
.tv-clock[data-face='analogue']::before, .tv-clock[data-face='split']::before {
  content: ''; position: absolute; top: 50%; translate: 0 -50%;
  width: var(--tv-dial, 100%); height: var(--tv-dial, 100%);
  border-radius: 50%; border: 1px solid var(--text-dim); background: var(--surface-1);
  background-image:
    radial-gradient(circle at 50% 50%, var(--text) 0 11%, transparent 12%),
    linear-gradient(90deg, transparent calc(50% - 1px), var(--text) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px));
}
.tv-clock[data-face='analogue']::before { left: 50%; translate: -50% -50%; }
/* The split clock is a dial and a date panel side by side. */
.tv-clock[data-face='split']::before { left: 0; }
.tv-clock[data-face='split']::after {
  content: ''; position: absolute; left: calc(var(--tv-dial, 0px) + 4px); right: 4px;
  top: 30%; bottom: 30%; border-radius: 2px; background: var(--text-dim);
}
.tv-clock[data-face='digital']::before {
  content: ''; position: absolute; left: 12%; right: 12%; top: 26%; bottom: 26%;
  background:
    linear-gradient(var(--text-dim), var(--text-dim)) left / 34% 100% no-repeat,
    linear-gradient(var(--text-dim), var(--text-dim)) right / 34% 100% no-repeat,
    linear-gradient(var(--text), var(--text)) center / 8% 44% no-repeat;
}
/* "this desktop has items taken off it" — a count, not a mystery. */
.tv-off {
  flex: 0 0 auto; font-size: 10px; padding: 2px 6px; border-radius: 999px;
  border: 1px dashed var(--border-strong); color: var(--text-dim);
}
.tv-wins { display: flex; flex-direction: column; gap: 6px; }
.tv-win {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: 6px 8px; border-radius: var(--radius-sm); border: 1px solid transparent;
  background: var(--hover); color: var(--text); cursor: pointer; font-size: 12.5px;
}
.tv-win:hover { background: var(--active); }
.tv-win.focused { border-color: var(--accent); background: var(--accent-soft); }
.tv-win.minimized { opacity: .62; }
.tv-win .glyph { font-size: 14px; flex: 0 0 auto; }
.tv-win .t { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tv-empty {
  padding: 14px 12px; color: var(--text-faint); font-size: 12px; text-align: center;
  border: 1px dashed var(--border); border-radius: var(--radius-sm);
}
.tv-new { align-items: center; justify-content: center; gap: 8px; min-height: 120px; background: transparent; border-style: dashed; color: var(--text-dim); }
.tv-new:hover { color: var(--accent); border-color: var(--accent); background: transparent; }
.tv-plus { font-size: 22px; line-height: 1; }

/* ---------- a window, drawn small ----------
   Used by the switcher and by the task view, so the picture of a window in one is the
   picture of it in the other. `miniature.js` clones the window's own element and scales
   it; these rules keep the clone honest: it is not a window any more, nothing inside it
   can be reached, and it never replays the animation its real one played on open. */
.miniature { position: absolute; overflow: hidden; pointer-events: none; }
.miniature > .window { animation: none !important; transition: none !important; }
.miniature-none {
  display: grid; place-items: center; background: var(--surface-2);
  border: 1px dashed var(--border-strong); border-radius: var(--radius-sm);
}
.miniature-glyph { font-size: 18px; opacity: .55; }
/* A cloned `<iframe>` is a box, not a second request for the same page. */
.mini-frame { display: block; background: var(--surface-2); }

/* ---------- the window switcher (Alt+Tab) ----------
   Above the task view: Alt+Tab is the way *out* of looking at all the desktops. */
.win-switch {
  position: absolute; inset: 0; z-index: 100004;
  background: rgb(6 8 14 / .62); backdrop-filter: blur(9px) saturate(120%);
  display: grid; place-items: center; padding: 20px;
  animation: pop-in .14s cubic-bezier(.2,.9,.3,1);
}
[data-theme='light'] .win-switch { background: rgb(20 24 34 / .42); }
.wsw-panel { display: flex; flex-direction: column; gap: 10px; max-width: 100%; max-height: 100%; }
.wsw-grid { position: relative; margin: 0 auto; }
.wsw-card {
  position: absolute; display: flex; flex-direction: column; gap: 6px; padding: 8px;
  text-align: left; cursor: pointer; color: var(--text);
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); backdrop-filter: blur(18px) saturate(140%);
  box-shadow: var(--shadow-pop);
  transition: border-color .12s, transform .12s, box-shadow .12s;
}
.wsw-card.selected {
  border-color: var(--accent); transform: translateY(-3px);
  box-shadow: 0 0 0 2px var(--accent-soft), var(--shadow-pop);
}
.wsw-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.wsw-preview {
  position: relative; flex: 0 0 auto; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
/* A minimised window is shown as itself, dimmed: the switcher is where you find the one
   you hid, so hiding it here would be the same mistake the taskbar used to make. */
.wsw-card.minimized .wsw-preview { opacity: .52; }
.wsw-foot { display: flex; align-items: center; gap: 7px; min-width: 0; flex: 1 1 auto; }
.wsw-icon { font-size: 14px; flex: 0 0 auto; }
.wsw-title {
  flex: 1 1 auto; min-width: 0; font-size: 12.5px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wsw-where {
  flex: 0 0 auto; max-width: 118px; padding: 2px 6px; border-radius: 999px; font-size: 10px;
  border: 1px solid var(--border-strong); color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.wsw-card.offdesk .wsw-where { border-style: dashed; color: var(--accent); border-color: var(--accent); }
.wsw-line { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; justify-content: center; }
.wsw-status { font-size: 12.5px; font-weight: 700; color: var(--text); }
.wsw-hint { font-size: 11.5px; color: var(--text-dim); }

/* ---------- the per-desktop look picker ----------
   Edits one desktop's wallpaper, motion and accent. No scrim: the desktop behind it
   is the thing you are changing, so it has to stay visible while you click. */
.desk-look {
  position: absolute; z-index: 100002; width: 424px; max-width: calc(100vw - 24px);
  max-height: calc(100vh - var(--taskbar-h) - 24px); overflow: auto;
  padding: 12px 14px 14px;
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--surface); backdrop-filter: blur(18px) saturate(1.2);
  box-shadow: var(--shadow-pop); color: var(--text);
  animation: pop-in .18s cubic-bezier(.2, .9, .3, 1);
}
.desk-look:focus { outline: none; }
.desk-look:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dl-head { display: flex; align-items: center; gap: 8px; }
.dl-title { font-size: 13px; font-weight: 700; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dl-close {
  width: 24px; height: 24px; flex: 0 0 auto; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--hover); color: var(--text-dim); cursor: pointer;
}
.dl-close:hover { background: var(--active); color: var(--text); }
.dl-hint { margin: 4px 0 10px; font-size: 11px; line-height: 1.45; color: var(--text-faint); }
.dl-section { display: flex; align-items: center; gap: 8px; margin: 10px 0 6px; }
.dl-label { font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint); flex: 1; }
.dl-now {
  font-size: 10px; padding: 2px 7px; border-radius: 999px;
  border: 1px solid var(--border); color: var(--text-faint); background: var(--hover);
}
.dl-now.chosen { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.dl-inherit {
  font-size: 11px; padding: 3px 8px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--text-dim);
}
.dl-inherit:hover:not([disabled]) { background: var(--active); color: var(--text); }
.dl-inherit[disabled] { opacity: .45; cursor: default; }
.dl-row { display: flex; flex-wrap: wrap; gap: 6px; }
.dl-tile {
  position: relative; width: 44px; height: 40px; padding: 0; cursor: pointer;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background-size: cover; background-position: center; overflow: hidden;
}
.dl-tile:hover { border-color: var(--text-faint); }
.dl-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dl-tile.active { box-shadow: 0 0 0 2px var(--surface-solid), 0 0 0 3px var(--text-faint); }
.dl-tile.active.chosen { box-shadow: 0 0 0 2px var(--surface-solid), 0 0 0 4px var(--accent); }
.dl-tile-label {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 2px 4px;
  font-size: 9px; text-align: center; color: #fff; background: rgb(0 0 0 / .55);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dl-tile.dl-tile-accent { width: 30px; height: 30px; border-radius: 50%; align-self: center; }
.dl-tile.dl-tile-pattern {
  width: 60px; height: 52px; background: none; padding: 4px 2px 5px;
  display: flex; flex-direction: column; align-items: center; justify-content: space-between;
}
.dl-tile.dl-tile-pattern canvas, .dl-tile.dl-tile-pattern .dl-static {
  display: block; width: 54px; height: 28px; border-radius: 3px; background-size: cover; flex: 0 0 auto;
}
.dl-tile.dl-tile-pattern .dl-tile-label {
  position: static; transform: none; padding: 0; font-size: 9px; line-height: 1.3; color: var(--text-dim); text-shadow: none; background: none;
}
.dl-foot { display: flex; align-items: center; gap: 8px; margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--border); }
.dl-note { flex: 1; min-width: 0; font-size: 11px; color: var(--text-faint); }

/* ---------- launcher (Start button / Ctrl+Space) ---------- */
/* The host is a full-screen, click-through layer: a click anywhere else still reaches
   the desktop, and the launcher closes on that click. */
.launcher { position: absolute; inset: 0; z-index: 100001; pointer-events: none; }
/* A scrim says "the desktop is waiting" — click-through, so an outside click still closes it. */
.launcher:not(.hidden)::before {
  content: ''; position: absolute; inset: 0;
  background: rgb(6 8 14 / .34);
}
[data-theme='light'] .launcher:not(.hidden)::before { background: rgb(20 24 34 / .18); }
.launcher-panel {
  position: absolute; left: 8px; bottom: calc(var(--taskbar-h) + 8px);
  width: 540px; max-width: calc(100vw - 16px); max-height: min(640px, calc(100vh - var(--taskbar-h) - 24px));
  background: var(--surface); backdrop-filter: blur(24px) saturate(150%);
  border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow-pop);
  display: flex; flex-direction: column; overflow: hidden; pointer-events: auto;
  animation: pop-in .16s cubic-bezier(.2,.9,.3,1);
}
@keyframes pop-in { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
.launcher-query { display: flex; align-items: center; gap: 10px; padding: 12px; border-bottom: 1px solid var(--border); }
.launcher-glyph { font-size: 16px; color: var(--text-faint); flex: 0 0 auto; }
.launcher-input {
  flex: 1; min-width: 0; height: 38px; padding: 0 10px; border-radius: 9px;
  background: var(--surface-2); border: 1px solid var(--border); outline: none; font-size: 15px;
}
.launcher-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.launcher-input::placeholder { color: var(--text-faint); }
.launcher-clear {
  width: 28px; height: 28px; flex: 0 0 auto; border-radius: 7px; cursor: pointer;
  border: 1px solid transparent; background: transparent; color: var(--text-dim); font-size: 12px;
}
.launcher-clear:hover { background: var(--hover); color: var(--text); }
.launcher-results { flex: 1; overflow: auto; padding: 6px 8px 10px; }
/* When the list is cut off, fade the last row: a clipped row should read as "more below". */
.launcher-results.more-below { mask-image: linear-gradient(to bottom, #000 calc(100% - 22px), transparent); }
.launcher-group { margin: 4px 0 2px; }
.launcher-group-head {
  display: flex; align-items: center; gap: 8px; padding: 8px 6px 4px;
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint);
}
.launcher-group-count { margin-left: auto; font-variant-numeric: tabular-nums; }
.lrow {
  width: 100%; display: flex; align-items: center; gap: 10px; text-align: left;
  padding: 7px 9px; margin: 2px 0; border: 1px solid transparent; border-radius: 9px;
  background: transparent; color: var(--text); cursor: pointer; font-size: 13px;
}
.lrow:hover { background: var(--hover); }
.lrow.selected { background: var(--accent-soft); border-color: var(--accent); }
.lrow .glyph { width: 26px; height: 26px; flex: 0 0 auto; display: grid; place-items: center; font-size: 17px; }
.lrow-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.lrow-title { font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lrow-title mark { background: color-mix(in srgb, var(--accent) 38%, transparent); color: inherit; border-radius: 3px; padding: 0 1px; }
.lrow-detail { font-size: 11.5px; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lrow-kind {
  margin-left: auto; flex: 0 0 auto; padding: 2px 4px; border: 0; border-radius: 0;
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.lrow.selected .lrow-kind, .lrow:hover .lrow-kind { color: var(--text-dim); }
/* A chord printed on the row it belongs to: the same string Settings and `keys`
   print, so the launcher is a keyboard reference as well as a mouse one. */
.lrow-kbd {
  margin-left: auto; flex: 0 0 auto; padding: 2px 6px; border: 1px solid var(--border); border-radius: 5px;
  font-family: var(--mono); font-size: 10.5px; color: var(--text-dim); background: var(--surface-2);
}
/* ---------- the launcher's modes: `>` a command, `?` a web search ---------- */
/* A mode is a promise about what Enter will do, so it is printed, not implied. */
.launcher-mode {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 9px; border-radius: 8px; font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  background: var(--accent-soft); color: var(--accent); border: 1px solid var(--accent);
}
.launcher-mode-prefix { font-family: var(--mono); font-size: 13px; text-transform: none; }
.launcher-input.launcher-mode-on { font-family: var(--mono); font-size: 14px; }
/* A command row prints the usage under the name: what you are about to run. */
.lrow-usage {
  font-family: var(--mono); font-size: 11px; color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---------- a command's output, shown in the launcher itself ---------- */
.shell-result { display: flex; flex-direction: column; gap: 8px; padding: 6px 4px 2px; }
.shell-head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 6px 8px; border: 1px solid var(--border); border-radius: 9px; background: var(--surface-2);
}
.shell-cwd { font-family: var(--mono); font-size: 11px; color: var(--accent); opacity: .8; }
.shell-line-text { flex: 1; min-width: 0; font-family: var(--mono); font-size: 13px; word-break: break-all; }
.shell-status {
  margin-left: auto; flex: 0 0 auto; padding: 2px 8px; border-radius: 999px;
  font-family: var(--mono); font-size: 11px; border: 1px solid var(--border); color: var(--text-dim);
}
.shell-status.ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.shell-status.err { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.shell-out {
  padding: 10px 12px; border-radius: 9px; background: var(--surface-2); border: 1px solid var(--border);
  font-family: var(--mono); font-size: 12.5px; line-height: 1.55; white-space: pre-wrap; word-break: break-word;
  max-height: 46vh; overflow: auto;
}
.shell-line { white-space: pre-wrap; word-break: break-word; }
.shell-line.err { color: var(--danger); }
.shell-line.ok { color: var(--ok); }
.shell-line.acc { color: var(--accent); }
.shell-line.dim { color: var(--text-faint); }
.shell-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.shell-btn {
  padding: 6px 10px; border: 1px solid var(--border); border-radius: 8px; background: transparent;
  color: var(--text-dim); font-size: 12px; cursor: pointer;
}
.shell-btn:hover { background: var(--hover); color: var(--text); border-color: var(--accent); }

.launcher-foot {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 8px 12px; border-top: 1px solid var(--border); font-size: 11px; color: var(--text-dim);
}
.launcher-status { color: var(--text-faint); }
.launcher-keys { margin-left: auto; white-space: nowrap; }
.start-section { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint); margin: 8px 2px 6px; }
.app-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 6px; }
.app-tile {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 6px; border: 1px solid transparent; border-radius: 10px;
  background: transparent; cursor: pointer; color: var(--text);
}
.app-tile:hover { background: var(--hover); border-color: var(--border); }
/* Keyboard selection in the launcher's app grid. */
.app-tile.selected { background: var(--accent-soft); border-color: var(--accent); outline: none; }
.app-tile .glyph { font-size: 24px; }
.app-tile .name { font-size: 12px; }

/* ---------- context menu ---------- */
.context-menu {
  position: absolute; z-index: 100002; min-width: 210px;
  background: var(--surface); backdrop-filter: blur(20px) saturate(150%);
  border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow-pop);
  padding: 6px; animation: pop-in .1s ease;
  /* The desktop menu is long, and a selection makes it longer. It belongs on the screen:
     a menu whose first rows are off the top is a menu whose first rows do not exist — and
     “on the screen” means above the taskbar, not merely above the bottom edge. */
  max-height: calc(100vh - var(--taskbar-h) - 20px); overflow: auto; overscroll-behavior: contain;
}
.cmenu-item {
  width: 100%; text-align: left; display: flex; gap: 10px; align-items: center;
  padding: 8px 10px; border: 0; background: transparent; color: var(--text);
  border-radius: 7px; cursor: pointer; font-size: 13px;
}
.cmenu-item:hover { background: var(--accent-soft); }
.cmenu-item .glyph { width: 18px; text-align: center; }
/* A menu you can walk with the keyboard (↑ ↓, Home/End, type-ahead, Enter, Esc).
   `:focus-visible` on purpose: a menu opened by a right-click must not draw a selection
   ring under a pointer that has not moved, while a menu opened with the Menu key or walked
   with the arrows always shows where you are. */
.cmenu-item:focus { outline: none; }
.cmenu-item:focus-visible { background: var(--accent-soft); box-shadow: inset 0 0 0 2px var(--accent); }
/* A row that cannot be run says so. "Undo the last stroke" with nothing to undo is a row
   the menu offers honestly and must not look like one you can click. */
.cmenu-item:disabled { color: var(--text-faint); cursor: default; }
.cmenu-item:disabled:hover { background: transparent; }
.cmenu-item:disabled .cmenu-hint { color: var(--text-faint); }
.context-menu:focus { outline: none; }
.cmenu-sep { height: 1px; background: var(--border); margin: 5px 4px; }
/* A separator with a label is a heading for the group under it. */
.cmenu-head {
  height: auto; background: none; margin: 4px 4px 3px;
  font-size: 11px; font-weight: 700; letter-spacing: .4px; color: var(--text-faint);
}
.cmenu-head span { text-transform: none; }
.cmenu-hint { font-size: 11px; color: var(--text-faint); margin-left: auto; flex: 0 0 auto; white-space: nowrap; padding-left: 16px; }

/* ---------- notifications: pop-ups ---------- */
/* The stack is the transient half of the notification system; the centre (below) is
   the durable half. A pop-up is deliberately *not* a button — the row you can act on
   is the one in the centre — except when the message names a path, in which case the
   pop-up itself carries the action. */
.toasts { position: absolute; right: 12px; bottom: calc(var(--taskbar-h) + 12px); display: flex; flex-direction: column; gap: 8px; z-index: 100003; }
.toast {
  display: flex; align-items: flex-start; gap: 8px;
  min-width: 220px; max-width: 340px; padding: 10px 12px;
  background: var(--surface); border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: 10px; box-shadow: var(--shadow-pop); font-size: 13px;
  animation: pop-in .16s ease;
}
.toast.err { border-left-color: var(--danger); }
.toast.ok { border-left-color: var(--ok); }
.toast.warn { border-left-color: var(--warn); }
.toast .t { font-weight: 600; margin-bottom: 2px; overflow-wrap: anywhere; }
.toast .d { color: var(--text-dim); font-size: 12px; overflow-wrap: anywhere; }
.toast .t-body { flex: 1 1 auto; min-width: 0; }
.toast .t-count { color: var(--accent); font-weight: 700; font-size: 11px; }
.toast .t-glyph { flex: 0 0 auto; width: 16px; text-align: center; color: var(--text-dim); font-size: 13px; padding-top: 1px; }
.toast.ok .t-glyph { color: var(--ok); }
.toast.warn .t-glyph { color: var(--warn); }
.toast.err .t-glyph { color: var(--danger); }
.toast .t-action, .toast .t-x {
  flex: 0 0 auto; border: 1px solid var(--border); background: var(--surface-2); color: var(--text-dim);
  border-radius: var(--radius-sm); font: inherit; font-size: 11px; padding: 3px 7px; cursor: pointer;
}
.toast .t-action { color: var(--accent); border-color: var(--accent); }
.toast .t-action:hover { background: var(--accent-soft); }
.toast .t-x { padding: 3px 5px; }
.toast .t-x:hover { color: var(--text); background: var(--hover); }
.toast.fading { opacity: 0; transform: translateX(12px); transition: opacity .3s, transform .3s; }

/* ---------- notifications: the tray bell ---------- */
.notify-tray { display: flex; align-items: center; }
.notify-btn { position: relative; display: flex; align-items: center; gap: 5px; }
.notify-btn .nb-glyph { display: flex; color: var(--text-dim); }
.notify-btn:hover .nb-glyph { color: var(--accent); }
.notify-btn.is-open { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.notify-btn.is-open .nb-glyph { color: var(--accent); }
/* The count is the whole point of the bell: it is the only way to know something is
   waiting without opening anything. It is never 0 — an empty bell is silence. */
.notify-btn .nb-count {
  display: none; min-width: 16px; padding: 0 4px; border-radius: 8px;
  background: var(--accent); color: var(--surface-solid); font-size: 10px; font-weight: 700;
  line-height: 16px; text-align: center;
}
.notify-btn.has-unread .nb-count { display: block; }
.notify-btn.has-unread { border-color: var(--accent); }
.notify-btn.has-unread .nb-glyph { color: var(--accent); animation: bell-ring 2.6s ease; }
/* Do not disturb is a state you should be able to see from across the room. */
.notify-btn.is-quiet .nb-glyph { color: var(--text-faint); }
.notify-btn.is-quiet::after {
  content: ''; position: absolute; left: 50%; top: 50%; width: 20px; height: 1.5px;
  background: var(--danger); border-radius: 2px; transform: translate(-50%, -50%) rotate(-38deg);
  opacity: .8;
}
@keyframes bell-ring {
  0%, 55%, 100% { transform: rotate(0); }
  8% { transform: rotate(13deg); }
  16% { transform: rotate(-11deg); }
  24% { transform: rotate(7deg); }
  32% { transform: rotate(-4deg); }
  40% { transform: rotate(2deg); }
}

/* ---------- notifications: the centre ---------- */
/* Anchored to the same corner as the pop-up stack, so opening the centre is reading
   the same pile, not finding a new place for it. */
.notifications {
  position: absolute; right: 12px; bottom: calc(var(--taskbar-h) + 12px); z-index: 100002;
  width: min(370px, calc(100vw - 24px));
  max-height: min(62vh, 560px);
  display: flex; flex-direction: column;
  background: var(--surface); backdrop-filter: blur(20px) saturate(150%);
  border: 1px solid var(--border-strong); border-radius: 12px;
  box-shadow: var(--shadow-pop); overflow: hidden;
  animation: pop-in .18s ease;
}
.notifications.hidden { display: none; }
/* The panel itself is focusable so a keyboard user lands inside the dialog; it is the
   rows inside that should look focused, not the frame. */
.np-panel:focus { outline: none; }
.np-panel { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.np-head {
  display: flex; align-items: center; gap: 6px; flex: 0 0 auto;
  padding: 9px 10px; border-bottom: 1px solid var(--border);
}
.np-title { font-size: 13px; font-weight: 700; }
.np-count { font-size: 11px; color: var(--accent); font-weight: 600; }
.np-action {
  border: 1px solid transparent; background: none; color: var(--text-dim); font: inherit; font-size: 11px;
  padding: 3px 7px; border-radius: var(--radius-sm); cursor: pointer;
}
.np-action:hover { color: var(--text); background: var(--hover); }
.np-action:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.np-dnd { border-color: var(--border); }
.np-dnd.on { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
.np-close { margin-left: auto; }
.np-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 6px 8px 10px; }
.np-group { margin-bottom: 4px; }
.np-day {
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-faint); padding: 8px 4px 4px; position: sticky; top: 0;
  background: var(--surface); backdrop-filter: blur(6px);
}
.np-item {
  display: flex; align-items: flex-start; gap: 7px; padding: 6px 4px;
  border-radius: var(--radius-sm); border-left: 3px solid transparent;
}
.np-item:hover { background: var(--hover); }
.np-item.unread { background: var(--accent-soft); border-left-color: var(--accent); }
.np-item.np-warn { border-left-color: var(--warn); }
.np-item.np-err { border-left-color: var(--danger); }
.np-item.np-ok.unread { border-left-color: var(--ok); }
.np-glyph { flex: 0 0 auto; width: 16px; text-align: center; color: var(--text-dim); font-size: 13px; padding-top: 2px; }
.np-ok .np-glyph { color: var(--ok); }
.np-warn .np-glyph { color: var(--warn); }
.np-err .np-glyph { color: var(--danger); }
.np-main {
  flex: 1 1 auto; min-width: 0; display: block; text-align: left;
  border: 0; background: none; color: inherit; font: inherit; cursor: pointer; padding: 0;
}
.np-main:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.np-t { display: block; font-size: 13px; font-weight: 600; overflow-wrap: anywhere; }
.np-d { display: block; font-size: 12px; color: var(--text-dim); overflow-wrap: anywhere; }
.np-meta { display: flex; flex-wrap: wrap; gap: 5px; font-size: 11px; color: var(--text-faint); margin-top: 2px; }
.np-repeat { color: var(--accent); font-weight: 600; }
.np-btn {
  flex: 0 0 auto; border: 1px solid var(--border); background: var(--surface-2); color: var(--text-dim);
  font: inherit; font-size: 11px; padding: 3px 7px; border-radius: var(--radius-sm); cursor: pointer;
}
.np-btn:hover { color: var(--text); background: var(--hover); }
.np-btn-open { color: var(--accent); border-color: var(--accent); }
.np-btn-open:hover { background: var(--accent-soft); }
.np-btn-x { padding: 3px 5px; }
.np-empty { text-align: center; padding: 34px 22px; color: var(--text-dim); }
.np-empty-glyph { color: var(--text-faint); opacity: .55; margin-bottom: 8px; }
.np-empty-t { font-size: 13px; font-weight: 600; color: var(--text); margin-bottom: 6px; }
.np-empty p { font-size: 12px; line-height: 1.5; margin: 0; }
.np-foot {
  display: flex; align-items: center; gap: 8px; flex: 0 0 auto;
  padding: 7px 10px; border-top: 1px solid var(--border); font-size: 11px; color: var(--text-faint);
}
.np-status { flex: 1 1 auto; min-width: 0; }
.np-keys { flex: 0 0 auto; }

/* ---------- notifications: asking for attention ---------- */
/* The taskbar button of an app you are *not* looking at, with something you have not
   seen. It is a request, not an alarm: it stops the moment you look at the app. */
.titem.attention { position: relative; border-color: var(--accent); animation: titem-ask 1.9s ease-in-out infinite; }
.titem.attention .glyph { position: relative; }
.titem.attention::after {
  content: ''; position: absolute; top: 2px; right: 2px; width: 7px; height: 7px;
  border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 2px var(--surface-solid);
}
@keyframes titem-ask {
  0%, 100% { box-shadow: 0 0 0 0 var(--accent-soft); }
  50% { box-shadow: 0 0 0 4px var(--accent-soft); }
}

/* Settings' notification card reads the same list the centre draws. */
.notify-list { display: flex; flex-direction: column; gap: 3px; }
.notify-row {
  display: flex; align-items: center; gap: 8px; padding: 5px 7px; font-size: 12px;
  border: 1px solid var(--border); border-left: 3px solid var(--border);
  border-radius: var(--radius-sm); background: var(--surface-2);
}
.notify-row.unread { border-left-color: var(--accent); }
.notify-row.np-warn { border-left-color: var(--warn); }
.notify-row.np-err { border-left-color: var(--danger); }
.nr-kind { flex: 0 0 auto; font-family: var(--mono); font-size: 10px; text-transform: uppercase; color: var(--text-faint); }
.nr-t { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nr-age { flex: 0 0 auto; color: var(--text-faint); font-size: 11px; }
.btn.small { padding: 2px 6px; font-size: 11px; }


/* ---------- screensaver ---------- */
/* A full-screen layer over everything except the sign-in screen. The pattern is
   drawn on a canvas inside .saver-art (src/core/screensaver.js reuses the
   wallpaper engine); everything below is the clock that sits on top of it.
   `[data-tone]` comes from the palette the pattern was drawn with, so the clock
   stays readable on a light theme too. */
.screensaver {
  position: absolute; inset: 0; z-index: 100010;
  background: var(--bg);
  color: var(--saver-ink, #eef3ff);
  opacity: 0; transition: opacity .7s ease;
  user-select: none; cursor: none;
}
.screensaver.on { opacity: 1; }
.screensaver .saver-art { position: absolute; inset: 0; }
.screensaver .saver-veil {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 95% at 50% 42%, transparent 38%, rgba(3, 5, 10, .62) 100%);
}
.screensaver .saver-panel {
  position: absolute; left: 0; right: 0; bottom: 14vh;
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  text-align: center; text-shadow: 0 2px 22px rgba(0, 0, 0, .55);
}
.saver-time {
  font-size: clamp(58px, 11vw, 150px); font-weight: 250; line-height: 1;
  letter-spacing: .01em; font-variant-numeric: tabular-nums;
}
.saver-date { font-size: clamp(13px, 1.5vw, 19px); margin-top: -4px; color: var(--saver-dim, currentColor); opacity: .85; }
.saver-mode {
  font-size: 11.5px; letter-spacing: .16em; text-transform: uppercase; opacity: .5;
  color: var(--saver-dim, currentColor);
}
.saver-hint {
  position: absolute; left: 0; right: 0; bottom: 6vh; text-align: center;
  font-size: 12.5px; color: var(--saver-dim, currentColor);
  /* The hint waits a moment, then fades in. It is a transition rather than an
     animation so the strength can follow the palette it is sitting on: the same
     grey is invisible over a pale pattern and loud over a dark one. (A var() in
     @keyframes would be read once, at page load, before any palette exists.) */
  opacity: 0; --hint-o: .55;
  transition: opacity .35s ease;
}
.screensaver.on .saver-hint { opacity: var(--hint-o); transition: opacity 1.2s ease 2.4s; }
.screensaver.no-clock .saver-clock { display: none; }
.screensaver[data-tone="light"] .saver-veil {
  /* A white vignette is what makes a pale clock readable, but the hint sits in
     the thickest part of it: too strong and the hint vanishes into it. */
  background: radial-gradient(120% 95% at 50% 42%, transparent 42%, rgba(255, 255, 255, .3) 100%);
}
.screensaver[data-tone="light"] .saver-panel { text-shadow: 0 2px 18px rgba(255, 255, 255, .6); }
.screensaver[data-tone="light"] .saver-hint { --hint-o: .82; }
.screensaver[data-tone="light"] .saver-mode { opacity: .72; }
.screensaver[data-tone="light"] .saver-date { opacity: .95; }

/* ---------- the photo screensaver ---------- */
/* The picture layer is a sibling of the canvas layer, never inside it: the runtime
   hides one or the other, so a pattern can never be drawn under a photograph. */
.screensaver > .saver-photos { position: absolute; inset: 0; overflow: hidden; }
.screensaver .saver-photos[hidden], .screensaver .saver-photo-tint[hidden], .screensaver .saver-caption[hidden] { display: none; }
/* One slide is a full-bleed image that fades in over the one before it. The image
   itself is sized and moved by `photoFrame()` in the runtime — the only thing CSS
   decides here is the fade. */
.saver-photo { position: absolute; inset: 0; opacity: 0; transition: opacity .9s ease; }
.saver-photo.in { opacity: 1; }
.saver-photo.out { opacity: 0; }
.saver-photo-img {
  position: absolute; left: 50%; top: 50%; max-width: none; max-height: none;
  transform: translate(-50%, -50%); will-change: transform;
  -webkit-user-drag: none; user-select: none;
}
/* A file that does not say its own size, and has not been measured yet: the browser
   covers the screen instead, and nothing drifts. */
.saver-photo-cover .saver-photo-img { width: 100%; height: 100%; object-fit: cover; }
/* The same time-of-day wash the desktop wears, at half strength: a screensaver at
   2am should not be the 2pm slideshow it was at 2pm, but the picture is the point. */
.saver-photo-tint {
  position: absolute; inset: 0; pointer-events: none; opacity: .55;
  background: var(--daylight-tint, none);
}
/* A photograph can be any brightness, and the clock and the caption sit on top of it.
   The vignette a pattern uses is too even for that: over a photo the darkening has to be
   where the words are. `[data-tone]` is the tone the runtime measured from the picture, so
   a pale photograph gets a pale scrim and the ink stays the opposite of it. */
.screensaver.saver-photos .saver-veil {
  background:
    linear-gradient(to top, rgba(4, 6, 12, .74) 0%, rgba(4, 6, 12, .38) 13%, transparent 34%),
    radial-gradient(120% 95% at 50% 42%, transparent 46%, rgba(3, 5, 10, .45) 100%);
}
.screensaver[data-tone="light"].saver-photos .saver-veil {
  background:
    linear-gradient(to top, rgba(255, 255, 255, .8) 0%, rgba(255, 255, 255, .4) 13%, transparent 34%),
    radial-gradient(120% 95% at 50% 42%, transparent 46%, rgba(255, 255, 255, .26) 100%);
}
/* The caption is the picture's own facts — the sentence `photos show` prints — so a
   screensaver you wake from is something you can find again. */
.saver-caption {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: baseline; gap: 4px 10px;
  max-width: min(760px, 88vw); font-size: 12px; color: var(--saver-dim, currentColor);
  opacity: .82; letter-spacing: .01em;
}
.saver-caption-name { font-weight: 650; color: var(--saver-ink, currentColor); opacity: .95; }
.saver-caption-count {
  font-variant-numeric: tabular-nums; padding: 1px 7px; border-radius: 6px;
  border: 1px solid color-mix(in srgb, currentColor 28%, transparent);
}
.saver-caption-note { flex: 1 0 100%; opacity: .75; font-style: italic; }
.screensaver[data-tone="light"] .saver-caption { opacity: .9; }

@media (prefers-reduced-motion: reduce) {
  .screensaver { transition: none; }
  .saver-hint, .screensaver.on .saver-hint { transition: none; }
  .saver-photo { transition: none; }
  .saver-photo-img { transition: none !important; }
}

/* ---------- shared app UI ---------- */
.app { height: 100%; display: flex; flex-direction: column; background: var(--surface-solid); }
.toolbar {
  display: flex; align-items: center; gap: 6px; padding: 7px 9px; flex: 0 0 auto;
  flex-wrap: nowrap; border-bottom: 1px solid var(--border); background: var(--surface-2);
}
.toolbar .spacer { flex: 1 1 8px; min-width: 4px; }
.btn {
  height: 28px; padding: 0 10px; border-radius: 7px; cursor: pointer; flex: 0 0 auto;
  white-space: nowrap; border: 1px solid var(--border); background: var(--surface-3); color: var(--text); font-size: 12.5px;
}
.btn:hover { background: var(--active); }
.btn.primary { background: var(--accent); border-color: transparent; color: #fff; font-weight: 600; }
.btn.primary:hover { filter: brightness(1.08); }
.btn.ghost { background: transparent; }
.btn.danger { background: var(--danger); border-color: transparent; color: #fff; }
.field {
  height: 28px; padding: 0 9px; border-radius: 7px; min-width: 0;
  background: var(--surface-solid); border: 1px solid var(--border); outline: none;
}
.field:focus { border-color: var(--accent); }
.statusbar {
  flex: 0 0 auto; display: flex; gap: 14px; align-items: center;
  padding: 5px 10px; font-size: 11.5px; color: var(--text-dim);
  border-top: 1px solid var(--border); background: var(--surface-2);
}
.statusbar .spacer { flex: 1 1 8px; min-width: 4px; }
.pad { padding: 14px; }
.muted { color: var(--text-dim); }
.mono { font-family: var(--mono); }

/* ---------- terminal ---------- */
.term { height: 100%; display: flex; flex-direction: column; background: #080c16; }
html[data-theme="light"] .term { background: #0f172a; }
.term-out {
  flex: 1; overflow: auto; padding: 10px 12px;
  font-family: var(--mono); font-size: 13px; line-height: 1.5; white-space: pre-wrap; word-break: break-word;
}
.term-out .err { color: var(--danger); }
.term-out .dim { color: var(--text-faint); }
.term-out .acc { color: var(--accent); }
.term-out .ok { color: var(--ok); }
/* The echo of the line you typed: prompt in the accent, the shell's operators picked out. */
.term-out .cmd { color: var(--text); word-break: normal; }
.term-out .cmd .term-echo-prompt { color: var(--accent); opacity: .75; }
.term-out .cmd .op { color: var(--accent); font-weight: 700; }
/* `$NAME`, `$?` and `$( … )` are the shell's own syntax: coloured apart from the
   operators next to them, because they mean something different — a value, not a join. */
.term-out .cmd .var { color: var(--ok); font-style: italic; }
.term-out a { color: var(--accent); }
.term-out .neof { color: var(--accent); font-weight: 600; }
.term-row { flex: 0 0 auto; display: flex; gap: 8px; align-items: center; padding: 8px 12px; border-top: 1px solid var(--border); background: rgba(255,255,255,.03); }
.term-cwd { font-family: var(--mono); font-size: 12.5px; color: var(--accent); white-space: nowrap; }
.term-input { flex: 1; min-width: 0; background: transparent; border: 0; outline: none; font-family: var(--mono); font-size: 13px; }
.term-input::placeholder { color: var(--text-faint); }

/* ---------- files ---------- */
/* Files is a column of toolbar / tools / body, like every other app: the side-by-side part
   is `.files-body`, so the folder and the inspector can be split instead of stacked. */
.files-side { width: 172px; flex: 0 0 auto; border-right: 1px solid var(--border); background: var(--surface-2); padding: 8px; overflow: auto; }
.side-item {
  width: 100%; display: flex; gap: 8px; align-items: center; padding: 7px 8px;
  border: 0; background: transparent; color: var(--text); border-radius: 7px; cursor: pointer; font-size: 12.5px; text-align: left;
}
.side-item:hover { background: var(--hover); }
.side-item.active { background: var(--accent-soft); color: var(--accent); }
.crumbs { display: flex; gap: 2px; align-items: center; font-size: 12px; color: var(--text-dim); overflow: hidden; min-width: 0; flex: 0 1 auto; }
.crumbs button { background: none; border: 0; color: var(--text); cursor: pointer; padding: 4px 6px; border-radius: 5px; font-size: 12px; white-space: nowrap; }
.crumbs button:last-child { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; max-width: 160px; }
.crumbs button:hover { background: var(--hover); }
.filegrid {
  flex: 1; overflow: auto; align-content: start;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 6px; padding: 12px;
}
.filecell {
  display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 10px 6px;
  border: 1px solid transparent; border-radius: 9px; cursor: default; background: transparent; color: var(--text);
}
.filecell:hover { background: var(--hover); border-color: var(--border); }
.filecell.selected { background: var(--accent-soft); border-color: var(--accent); }
.filecell .glyph { font-size: 28px; }
.filecell .name { font-size: 11.5px; text-align: center; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.filecell .meta { font-size: 10px; color: var(--text-faint); }
.empty-state { padding: 28px; text-align: center; color: var(--text-faint); font-size: 13px; }

/* The second row: the tools that decide *what of this folder you are looking at* —
 * a search, an order, a view. It is a row of its own because it is allowed to wrap,
 * which the navigation toolbar is not. */
.files-tools { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding: 6px 9px; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.files-tools .spacer { flex: 1 1 8px; min-width: 4px; }
.files-search { flex: 1 1 190px; min-width: 120px; }
.files-sort { height: 28px; padding: 0 6px; }
.files-viewseg button { padding: 5px 9px; }
.btn.active { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }

.files-body { flex: 1; min-height: 0; display: flex; container-type: inline-size; }
.files-content { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.files-side-trash { margin-top: 12px; }

/* The list view. One grid template for the whole table, so the header and the rows
   line up by construction; the Trash adds the column that answers "where from". */
.filetable { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.ft-rows { flex: 1; overflow: auto; }
.ft-row {
  display: grid; gap: 10px; padding: 6px 12px; align-items: center; cursor: default;
  grid-template-columns: minmax(120px, 1.8fr) 74px 78px 104px;
  border-bottom: 1px solid var(--border); color: var(--text);
}
.ft-row.ft-trash, .ft-head.ft-trash { grid-template-columns: minmax(110px, 1.6fr) 66px 70px 92px minmax(110px, 1fr); }
.ft-head { position: sticky; top: 0; z-index: 1; background: var(--surface-2); border-bottom: 1px solid var(--border); }
.ft-head .ft-cell { font-size: 11px; letter-spacing: .04em; color: var(--text-dim); text-transform: uppercase; }
.ft-sort { background: none; border: 0; cursor: pointer; color: inherit; font: inherit; letter-spacing: inherit; text-transform: inherit; padding: 2px 0; }
.ft-sort:hover { color: var(--accent); }
.ft-cell.sorted { color: var(--accent); }
.ft-cell { font-size: 12.5px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ft-size, .ft-modified, .ft-trashed { font-family: var(--mono); font-size: 11.5px; color: var(--text-dim); }
.ft-size { text-align: right; }
.ft-from { color: var(--text-faint); font-size: 11.5px; }
.ft-name { display: flex; gap: 8px; align-items: center; min-width: 0; }
.ft-name .glyph { font-size: 16px; flex: 0 0 auto; }
.ft-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ft-row:hover { background: var(--hover); }
.ft-row.selected { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--accent); }

/* The inspector: what the selected file *is*. Hidden when the window is too narrow to
   show a folder and a description at once — a container query, not a guess. */
.file-inspector {
  flex: 0 0 272px; border-left: 1px solid var(--border); background: var(--surface-2);
  padding: 12px; overflow: auto;
}
@container (max-width: 620px) { .file-inspector { display: none; } }

/* A narrow window has to decide which columns matter. The glyph on each row already says
   what a file is; where a trashed file came from is the one thing a Trash cannot lose. */
@container (max-width: 640px) {
  .ft-cell.ft-kind { display: none; }
  .ft-row, .ft-head { grid-template-columns: minmax(120px, 1.8fr) 78px 104px; }
  .ft-row.ft-trash, .ft-head.ft-trash { grid-template-columns: minmax(110px, 1.6fr) 70px 92px minmax(100px, 1fr); }
}

/* Narrower still: the Places list becomes an icon rail, and the dates go last. */
@container (max-width: 600px) {
  .files-side { width: 46px; padding: 6px 4px; }
  .files-side .start-section { display: none; }
  .files-side .side-item { justify-content: center; padding: 7px 2px; }
  .files-side .side-item span:last-child { display: none; }
  .ft-cell.ft-modified, .ft-cell.ft-trashed { display: none; }
  .ft-row, .ft-head { grid-template-columns: minmax(120px, 1fr) 78px; }
  .ft-row.ft-trash, .ft-head.ft-trash { grid-template-columns: minmax(110px, 1fr) 70px minmax(90px, 1fr); }
}
.insp { display: flex; flex-direction: column; gap: 8px; }
.insp-head { display: flex; gap: 8px; align-items: center; }
.insp-glyph { font-size: 24px; }
.insp-title { font-weight: 650; font-size: 13.5px; word-break: break-word; }
.insp-row { display: grid; grid-template-columns: 62px 1fr; gap: 8px; }
.insp-key { color: var(--text-faint); text-transform: uppercase; letter-spacing: .06em; font-size: 10px; padding-top: 2px; }
.insp-val { color: var(--text); font-size: 11.5px; word-break: break-word; }
.insp-preview { margin-top: 4px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface-solid); max-height: 240px; overflow: auto; }
.insp-preview-text { padding: 8px 10px; font-family: var(--mono); font-size: 11px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
.insp-preview-image { padding: 8px; display: grid; place-items: center; }
.insp-preview-image img { max-width: 100%; max-height: 210px; border-radius: 6px; }
.insp-preview-note { padding: 10px; color: var(--text-faint); font-size: 11.5px; }
.insp-more { color: var(--text-faint); }
.insp-list { max-height: 132px; overflow: auto; font-size: 11.5px; }
.insp-item { padding: 2px 0; }
.insp-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.insp-hint, .insp-note { font-size: 11px; color: var(--text-faint); }

.files-status-selection { color: var(--text-dim); }
.files-status-selection.ok { color: var(--ok); }
.files-status-hint { color: var(--text-faint); }
.files-undo { height: 24px; padding: 0 9px; font-size: 11.5px; }

/* ---------- editor ---------- */
.editor-area {
  flex: 1; min-height: 0; width: 100%; resize: none; border: 0; outline: none;
  padding: 14px 16px; background: var(--surface-solid); color: var(--text);
  font-family: var(--mono); font-size: 13.5px; line-height: 1.6; tab-size: 2;
}

/* ---------- viewer ---------- */
.viewer-main { flex: 1; min-height: 0; display: grid; place-items: center; padding: 14px; overflow: auto; background:
  repeating-conic-gradient(var(--surface-2) 0% 25%, var(--surface-solid) 0% 50%) 50% / 22px 22px; }
.viewer-main img { max-width: 100%; max-height: 100%; border-radius: 8px; box-shadow: var(--shadow-pop); }
.viewer-text { align-items: stretch; justify-content: stretch; display: block; overflow: auto; background: var(--surface-solid); padding: 16px; font-family: var(--mono); font-size: 13px; white-space: pre-wrap; }

/* ---------- paint ---------- */
.paint-main { flex: 1; min-height: 0; position: relative; overflow: hidden; }
.paint-canvas { position: absolute; inset: 0; width: 100%; height: 100%; cursor: crosshair; touch-action: none; }
.swatch { width: 26px; height: 26px; border-radius: 6px; border: 1px solid var(--border); padding: 0; background: transparent; cursor: pointer; }
input[type="color"].swatch { padding: 0; }
input[type="color"].swatch::-webkit-color-swatch-wrapper { padding: 3px; }
input[type="color"].swatch::-webkit-color-swatch { border: none; border-radius: 4px; }
.seg { display: inline-flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
.seg button { border: 0; background: transparent; color: var(--text-dim); padding: 5px 10px; cursor: pointer; font-size: 12.5px; }
.seg button.active { background: var(--accent); color: #fff; }

/* ---------- calculator ---------- */
.calc { max-width: 340px; margin: 0 auto; width: 100%; height: 100%; display: flex; flex-direction: column; }
.calc-display {
  margin: 12px; padding: 14px; border-radius: 10px; background: var(--surface-2);
  border: 1px solid var(--border); text-align: right; font-family: var(--mono); flex: 0 0 auto;
}
.calc-display .expr { font-size: 12px; color: var(--text-faint); min-height: 16px; }
.calc-display .val { font-size: 28px; font-weight: 600; word-break: break-all; }
/* The keypad flexes so a short window (a quarter tile) still shows every row. */
.calc-pad { display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 1fr; gap: 6px; padding: 0 12px 12px; flex: 1 1 auto; min-height: 0; }
.calc-key {
  min-height: 30px; height: 100%; border-radius: 10px; border: 1px solid var(--border);
  background: var(--surface-3); color: var(--text); font-size: 17px; cursor: pointer;
}
.calc-key:hover { background: var(--active); }
.calc-key.op { background: var(--accent-soft); color: var(--accent); }
.calc-key.eq { background: var(--accent); color: #fff; border-color: transparent; font-weight: 700; }

/* ---------- clock ---------- */
/* The Clock app is four panels behind one tab strip. The numbers are the interface,
   so every read-out is tabular monospace: a countdown must not wiggle as it ticks. */
.clock-tabs {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap; flex: 0 0 auto;
  padding: 7px 9px; border-bottom: 1px solid var(--border); background: var(--surface-2);
}
.clock-tab {
  display: flex; align-items: center; gap: 6px; height: 28px; padding: 0 10px; border-radius: 7px;
  border: 1px solid transparent; background: transparent; color: var(--text-dim);
  cursor: pointer; font-size: 12.5px; white-space: nowrap;
}
.clock-tab:hover { background: var(--hover); color: var(--text); }
.clock-tab.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.clock-tab .ct-glyph { font-size: 14px; }
.ct-badge {
  min-width: 17px; padding: 1px 5px; border-radius: 9px; background: var(--accent); color: #fff;
  font-size: 10.5px; font-weight: 700; text-align: center;
}
.clock-panel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
.clock-read { font-family: var(--mono); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.clock-huge { font-size: 42px; font-weight: 700; line-height: 1.05; }
.clock-big { font-size: 21px; font-weight: 600; }
.chip {
  border: 1px solid var(--border); background: var(--surface-3); color: var(--text);
  border-radius: 999px; padding: 4px 11px; font-size: 11.5px; cursor: pointer; white-space: nowrap;
}
.chip:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }

/* world clock */
.wc, .tm, .sw, .al { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.wc-here { flex: 0 0 auto; padding: 14px 16px 12px; display: flex; flex-direction: column; gap: 4px; border-bottom: 1px solid var(--border); }
.wc-here-meta { display: flex; gap: 12px; flex-wrap: wrap; font-size: 12px; }
.wc-here-actions { display: flex; gap: 6px; margin-top: 8px; }
.wc-add { flex: 0 0 auto; padding: 10px 16px; display: flex; flex-direction: column; gap: 8px; }
.wc-add .wc-input { width: 100%; }
.wc-suggest { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; font-size: 11.5px; }
.wc-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 0 16px 12px; }
.wc-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; align-items: center; gap: 14px;
  padding: 9px 2px; border-bottom: 1px solid var(--border);
}
.wc-city { display: flex; flex-direction: column; min-width: 0; font-size: 12px; }
.wc-city-name { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wc-meta { display: flex; flex-direction: column; gap: 2px; font-size: 11px; text-align: right; }
.wc-day { color: var(--text-dim); }
.wc-day.off { color: var(--accent); font-weight: 600; }

/* timers */
.tm-new { flex: 0 0 auto; display: flex; gap: 8px; padding: 12px 16px 8px; }
.tm-duration { width: 212px; min-width: 212px; font-family: var(--mono); }
.tm-label { flex: 1 1 120px; min-width: 90px; }
.tm-presets { flex: 0 0 auto; display: flex; gap: 6px; flex-wrap: wrap; padding: 0 16px 10px; }
.tm-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 0 16px 12px; display: flex; flex-direction: column; gap: 8px; }
.tm-row { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; background: var(--surface-2); }
.tm-row-top { display: flex; align-items: center; gap: 12px; }
.tm-label-text { flex: 1 1 auto; min-width: 0; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tm-bar { height: 5px; border-radius: 3px; background: var(--hover); overflow: hidden; margin-top: 8px; }
.tm-bar-fill { height: 100%; background: var(--accent); transition: width .3s linear; }
.tm-row-meta { font-size: 11px; margin-top: 6px; }

/* stopwatch */
.sw-read { text-align: center; padding: 20px 16px 4px; flex: 0 0 auto; }
.sw-actions { flex: 0 0 auto; display: flex; gap: 8px; justify-content: center; padding: 10px 16px; }
.sw-laps { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 6px 16px 12px; }
.sw-laps-head, .sw-lap { display: grid; grid-template-columns: 44px 1fr 1fr; gap: 10px; padding: 6px 4px; border-bottom: 1px solid var(--border); font-size: 12.5px; }
.sw-laps-head { color: var(--text-faint); font-size: 11px; border-bottom-color: var(--border); }
.sw-lap.best .mono:first-of-type { color: var(--ok); }
.sw-lap.worst .mono:first-of-type { color: var(--danger); }

/* alarms */
.al-new { flex: 0 0 auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; padding: 12px 16px; }
.al-time { width: 128px; font-family: var(--mono); }
.al-label { flex: 1 1 140px; min-width: 90px; }
.al-zone { max-width: 240px; }
.al-repeat { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-dim); cursor: pointer; }
.al-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 0 16px 12px; display: flex; flex-direction: column; gap: 6px; }
.al-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto auto; align-items: center; gap: 12px;
  padding: 9px 12px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface-2);
}
.al-row.off { opacity: .55; }
.al-info { display: flex; flex-direction: column; min-width: 0; font-size: 11.5px; }
.al-name, .al-label-text { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.al-countdown { font-family: var(--mono); font-size: 12px; color: var(--accent); white-space: nowrap; }
.al-countdown.off { color: var(--text-faint); }

/* ---------- calendar ---------- */
/* A month on the left, the day you picked on the right. The month is the only
   thing that can show a whole week at a glance, so it keeps a fixed share of the
   window and every day in it is a button the arrow keys can reach. The dots on a
   day answer "is this month busy?" without opening anything. */
.calendar { flex-direction: row; }
.cal-side {
  /* A month needs seven columns; below this they stop being readable, so the day
     panel gives up width instead of the grid. A big window gives the grid more, and
     the day cells start naming what is on them — see the .cal-day container query. */
  width: min(620px, 46%); flex: 0 0 min(620px, 46%); min-width: 268px;
  display: flex; flex-direction: column;
  border-right: 1px solid var(--border); background: var(--surface-2);
}
.cal-nav { display: flex; align-items: center; gap: 6px; padding: 8px; border-bottom: 1px solid var(--border); }
.cal-nav .btn { padding: 0 8px; }
.cal-month {
  flex: 1 1 auto; min-width: 0; text-align: center; font-size: 14px; font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cal-weekdays { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; padding: 7px 8px 3px; }
.cal-weekday { text-align: center; font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); }
.cal-weekday.weekend { color: var(--accent); }
.cal-grid { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: 3px; padding: 0 8px 8px; }
/* The weeks share the panel height, so a five-row month and a six-row month are
   both a grid that fills the space instead of a grid with a hole in it. */
.cal-week { flex: 1 1 0; min-height: 26px; display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.cal-day {
  position: relative; min-width: 0; min-height: 0; padding: 4px 5px; text-align: left; cursor: pointer;
  display: flex; flex-direction: column; gap: 3px; overflow: hidden;
  border: 1px solid transparent; border-radius: var(--radius-sm); background: transparent; color: var(--text); font: inherit;
}
.cal-day:hover { background: var(--hover); }
.cal-day:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.cal-day-num { font-size: 12.5px; font-variant-numeric: tabular-nums; }
.cal-day-out { color: var(--text-faint); }
.cal-day-out .cal-day-num { font-size: 11.5px; }
.cal-day-weekend { background: rgb(0 0 0 / .14); }
html[data-theme="light"] .cal-day-weekend { background: rgb(0 0 0 / .05); }
.cal-day-today { border-color: var(--accent); }
.cal-day-today .cal-day-num { font-weight: 800; color: var(--accent); }
.cal-day.selected { background: var(--accent-soft); border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
/* The marks sit under the number, not in a corner of the cell: a tall cell is a
   tall target, and the dots have to stay attached to the day they describe. */
.cal-day-marks { display: flex; gap: 3px; align-items: center; min-height: 6px; }
.cal-mark { width: 5px; height: 5px; border-radius: 50%; background: var(--accent); }
.cal-mark.more { width: auto; height: auto; background: none; font-size: 9.5px; color: var(--text-dim); }
/* What is on the day, written in the day. The left edge wears the event's colour.
   A 40px cell cannot say anything readable, so the lines only appear in a cell wide
   enough to read them — a container query, not a guess about the window size. */
.cal-day { container-type: inline-size; }
.cal-day-events { display: none; flex-direction: column; gap: 2px; min-height: 0; overflow: hidden; }
@container (min-width: 64px) {
  .cal-day-events { display: flex; }
  .cal-day-marks { min-height: 0; }
}
.cal-day-event {
  font-size: 10.5px; line-height: 1.25; color: var(--text-dim); padding-left: 4px;
  border-left: 2px solid var(--accent); min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cal-day-more { font-family: var(--mono); font-size: 9.5px; color: var(--text-faint); padding-left: 4px; }

.cal-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
/* The header wraps instead of squeezing the date into three lines: in a narrow day
   panel the badge and the count move to their own line. */
.cal-day-title { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 9px; padding: 9px 12px 7px; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.cal-day-name { font-size: 15px; font-weight: 700; flex: 1 1 auto; min-width: 0; }
.cal-day-when { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-dim); }
.cal-day-when.now { color: var(--accent); font-weight: 700; }
.cal-day-title .spacer { flex: 1; }
.cal-day-count { font-size: 11.5px; color: var(--text-dim); }
/* The add box never collapses: the title field has a floor, and the row wraps when
   the day panel is narrow rather than shrinking "Add an event…" to nothing. */
.cal-new { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 12px; border-bottom: 1px solid var(--border); }
.cal-new-title { flex: 1 1 150px; min-width: 118px; }
.cal-new-when { flex: 1 1 90px; min-width: 74px; }
.cal-new-time { flex: 0 1 74px; min-width: 62px; }
.cal-agenda { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 8px 12px 14px; display: flex; flex-direction: column; gap: 6px; }
/* An event wears its own colour on the left edge and on the time, which is how a
   day of them reads as a schedule rather than a list of rows. */
.cal-event {
  --ev-bg: var(--surface-3); --ev-ink: var(--text);
  display: flex; align-items: stretch; gap: 6px; border: 1px solid var(--border);
  border-left: 4px solid var(--ev-bg); border-radius: var(--radius-sm); background: var(--surface-3);
}
.cal-event-main {
  flex: 1 1 auto; min-width: 0; display: flex; gap: 10px; align-items: baseline; text-align: left;
  padding: 8px 10px; border: 0; background: transparent; color: inherit; font: inherit; cursor: pointer;
}
.cal-event-main:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.cal-event-when {
  flex: 0 0 auto; font-family: var(--mono); font-size: 11.5px; padding: 2px 6px; border-radius: 5px;
  background: var(--ev-bg); color: var(--ev-ink);
}
.cal-event-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cal-event-title { font-size: 13.5px; font-weight: 600; }
.cal-event-notes { font-size: 11.5px; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-event.is-past { opacity: .55; }
.cal-event.is-now { box-shadow: 0 0 0 1px var(--accent); }
.cal-event-actions { flex: 0 0 auto; display: flex; gap: 4px; align-items: center; padding-right: 8px; }
.cal-event-actions .btn { height: 24px; padding: 0 7px; }
/* Editing an event in place, because an event is a file and the form is its header. */
.cal-edit { flex-direction: column; align-items: stretch; gap: 7px; padding: 9px 10px; background: var(--surface-2); }
.cal-form-row { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
/* The three short fields share one row; the colour and the buttons take the next.
   A form that wraps one control per line is a stack, not a form. */
.cal-form-row .field { flex: 1 1 110px; min-width: 84px; }
.cal-form-row .cal-title-field { flex: 1 1 220px; }
.cal-form-row input.cal-date-field { flex: 0 1 118px; }
.cal-form-row input.cal-time-field, .cal-form-row input.cal-duration-field { flex: 0 0 78px; }
.cal-form-actions { display: flex; gap: 6px; align-items: center; }
.cal-form-hint { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cal-swatches { display: flex; gap: 4px; }
.cal-swatch { width: 20px; height: 20px; border-radius: 5px; border: 2px solid transparent; opacity: .5; cursor: pointer; }
.cal-swatch:hover { opacity: .85; }
.cal-swatch.selected { opacity: 1; box-shadow: 0 0 0 2px var(--accent); }
.cal-swatch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; opacity: 1; }
.cal-hint { padding: 6px 12px; font-size: 11.5px; color: var(--text-dim); border-top: 1px solid var(--border); }

/* ---------- synth ---------- */
.synth-main { flex: 1; min-height: 0; overflow: auto; padding: 12px; display: flex; flex-direction: column; gap: 12px; }
.synth-viz {
  width: 100%; height: 82px; flex: 0 0 auto; border-radius: 10px;
  background: var(--surface-2); border: 1px solid var(--border);
}
.synth-keys {
  position: relative; flex: 0 0 auto; height: 128px; display: flex; overflow: hidden;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface-2);
  user-select: none; -webkit-user-select: none; touch-action: none;
}
.wkey {
  flex: 1 1 0; min-width: 0; cursor: pointer; color: #1b2333;
  border: 1px solid rgba(0, 0, 0, .35); border-radius: 0 0 6px 6px;
  background: linear-gradient(180deg, #fbfcff, #dde3f0);
  display: flex; align-items: flex-end; justify-content: center; padding-bottom: 6px;
}
.wkey:hover { background: linear-gradient(180deg, #fff, #e6ebf6); }
.wkey.down { background: linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #ffffff)); color: #fff; }
.wkey .keyname { font-family: var(--mono); font-size: 10px; opacity: .5; pointer-events: none; }
.bkey {
  position: absolute; top: 0; height: 62%; width: 4.4%; z-index: 2; cursor: pointer;
  border: 1px solid #05070d; border-radius: 0 0 5px 5px;
  background: linear-gradient(180deg, #2a3247, #0d1220);
}
.bkey:hover { background: linear-gradient(180deg, #39435d, #141b2b); }
.bkey.down { background: linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent) 60%, #000000)); }

.synth-seq {
  --seq-cols: 16;
  flex: 0 0 auto; display: flex; flex-direction: column; gap: 2px;
  border: 1px solid var(--border); border-radius: 10px; padding: 8px; background: var(--surface-2);
}
.seq-row { display: grid; grid-template-columns: 44px repeat(var(--seq-cols), minmax(0, 1fr)); gap: 2px; }
.seq-label {
  font-family: var(--mono); font-size: 10px; color: var(--text-faint);
  display: flex; align-items: center; justify-content: flex-end; padding-right: 5px; user-select: none;
}
.seq-label.root { color: var(--text-dim); font-weight: 600; }
.seq-cell {
  height: 15px; min-width: 0; padding: 0; cursor: pointer;
  border: 1px solid var(--border); border-radius: 3px; background: var(--surface-solid);
}
.seq-cell.beat { border-color: var(--border-strong); }
.seq-cell:hover { background: var(--active); }
.seq-cell.on { background: var(--accent); border-color: transparent; }
.seq-cell.live { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-2) 70%, transparent); }
.seq-head .seq-step { font-family: var(--mono); font-size: 10px; color: var(--text-faint); text-align: center; }
.seq-head .seq-step.active { color: var(--accent); font-weight: 700; }

.synth-library { border: 1px solid var(--border); border-radius: 10px; padding: 10px; background: var(--surface-2); display: flex; flex-direction: column; min-height: 0; }
.synth-library .start-section { margin: 0 0 8px; }
.synth-bottom { display: grid; grid-template-columns: minmax(0, 1fr) 264px; gap: 12px; flex: 0 0 auto; }
.synth-save-row { display: flex; gap: 8px; }
.synth-name { flex: 1 1 auto; min-width: 0; }
.song-list { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; flex: 1 1 auto; min-height: 0; overflow: auto; }
.song-row {
  display: grid; grid-template-columns: 18px minmax(0, 1fr) auto; gap: 8px; align-items: center;
  padding: 6px 8px; font-size: 12.5px;
  border: 1px solid var(--border); border-radius: 8px; background: var(--surface-solid);
}
.song-row .glyph { font-size: 16px; }
.song-text { display: flex; flex-direction: column; min-width: 0; }
.song-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.song-meta { color: var(--text-faint); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.song-actions { display: flex; gap: 4px; }

.synth-preset { width: 100px; flex: 0 1 auto; }
.synth-wave button { font-size: 11.5px; padding: 5px 8px; }
.synth-octave { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; }
.synth-octave-label { font-family: var(--mono); font-size: 11px; color: var(--text-dim); min-width: 44px; text-align: center; }
.synth-bpm { width: 84px; flex: 0 1 84px; accent-color: var(--accent); }
.synth-bpm-value { font-size: 11.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.synth-transport.playing { background: var(--ok); border-color: transparent; color: #08130d; }
.statusbar .acc { color: var(--accent); font-weight: 600; }
.synth-status { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; min-width: 0; }
.btn.tiny { height: 24px; padding: 0 8px; font-size: 11.5px; }
@media (max-width: 780px) {
  .synth-bottom { grid-template-columns: minmax(0, 1fr); }
  .song-list { max-height: 150px; }
}

/* ---------- notes ---------- */
.notes { flex-direction: row; }
.notes-side {
  width: 262px; flex: 0 0 262px; display: flex; flex-direction: column;
  border-right: 1px solid var(--border); background: var(--surface-2);
}
.notes-tools { display: flex; gap: 6px; padding: 8px; border-bottom: 1px solid var(--border); }
.notes-search { flex: 1; min-width: 0; }
.notes-list { flex: 1; overflow: auto; padding: 6px; display: flex; flex-direction: column; gap: 4px; }
.note-item {
  display: flex; gap: 8px; align-items: flex-start; width: 100%; text-align: left;
  padding: 8px; border: 1px solid transparent; border-radius: var(--radius-sm);
  background: transparent; color: var(--text); cursor: pointer;
}
.note-item:hover { background: var(--hover); }
.note-item.selected { background: var(--accent-soft); border-color: var(--accent); }
.note-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.note-dot { width: 12px; height: 12px; flex: 0 0 auto; margin-top: 3px; border-radius: 3px; border: 1px solid; box-shadow: 0 1px 2px rgb(0 0 0 / .3); }
.note-item-main { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.note-item-title { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.note-item-meta { font-size: 11px; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.notes-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.note-colors { display: flex; gap: 5px; align-items: center; }
.swatch { width: 22px; height: 22px; border-radius: 5px; border: 2px solid; cursor: pointer; opacity: .5; }
.swatch:hover { opacity: .85; }
.swatch.on { opacity: 1; box-shadow: 0 0 0 2px var(--accent); }
.swatch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; opacity: 1; }
/* Which desktop a pinned sticky belongs to: a chip per desktop, the same shape as the
   colour swatches, so the toolbar reads as one row of choices. */
.note-desks { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; }
.note-desks:empty { display: none; }
.note-desk {
  font: inherit; font-size: 11px; padding: 4px 9px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--border-strong); background: transparent; color: var(--text-dim);
  max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.note-desk:hover { background: var(--hover); color: var(--text); }
.note-desk.on { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 600; }
.note-desk.every { border-style: dashed; }
.note-desk:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.note-body {
  flex: 1; min-height: 0; padding: 14px 16px; border: 0; outline: none; resize: none;
  background: var(--note-bg, var(--surface-solid)); color: var(--note-ink, var(--text));
  font-family: var(--font); font-size: 14px; line-height: 1.55;
}
.note-body:disabled { background: var(--surface-2); color: var(--text-faint); }

/* ---------- tasks ---------- */
/* A task list, not a form: the row is the thing you look at, the checkbox is the thing
   you press, and everything else about a task (when it is due, how far through it is,
   which list it lives in) is written beside it in one line. */
/* The wrap is what the layout rules move about: .app.tasks is the container they measure,
   and a container query can never restyle the element that defines it. */
.tasks-wrap { display: flex; flex: 1; min-height: 0; }
.task-side {
  width: 232px; flex: 0 0 232px; display: flex; flex-direction: column; gap: 10px;
  border-right: 1px solid var(--border); background: var(--surface-2); padding: 8px 0 0;
}
.task-filters { display: flex; flex-direction: column; gap: 2px; padding: 0 8px; }
.task-filter {
  display: flex; align-items: center; gap: 8px; padding: 7px 10px; border: 1px solid transparent;
  border-radius: var(--radius-sm); background: transparent; color: var(--text); font: inherit;
  font-size: 13px; text-align: left; cursor: pointer;
}
.task-filter:hover { background: var(--hover); }
.task-filter.active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); font-weight: 600; }
.task-filter:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.task-filter-count { margin-left: auto; font-size: 11.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.task-filter.active .task-filter-count { color: var(--accent); }
.task-side-head {
  padding: 4px 18px 2px; font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-faint);
}
.task-lists { display: flex; flex-direction: column; gap: 1px; padding: 0 8px; max-height: 34%; overflow: auto; }
.task-list {
  display: flex; align-items: center; gap: 8px; padding: 5px 10px; border-radius: var(--radius-sm);
  border: 1px solid transparent; background: transparent; color: var(--text-dim); font: inherit;
  font-size: 12.5px; text-align: left; cursor: pointer;
}
.task-list:hover { background: var(--hover); color: var(--text); }
.task-list.active { background: var(--surface-3); border-color: var(--border-strong); color: var(--text); }
.task-list:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.task-list-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-list-count { margin-left: auto; font-size: 11px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
/* The progress bar is the only decoration in this app, so it is the one thing allowed to
   move: finishing a task should visibly change the window. */
.task-progress { margin: auto 8px 0; padding: 10px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 6px; }
.task-progress-line { display: flex; align-items: baseline; gap: 5px; font-size: 12px; color: var(--text-dim); flex-wrap: wrap; }
.task-progress-line b { color: var(--text); font-variant-numeric: tabular-nums; }
.task-bar { height: 6px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.task-bar i { display: block; height: 100%; background: var(--ok); transition: width .25s ease; }
.task-danger { color: var(--danger); font-weight: 600; }
.task-dim { color: var(--text-faint); }
.task-progress-note { font-size: 11.5px; }
.task-side .statusbar { border-top: 1px solid var(--border); }

.task-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.task-composer { display: flex; flex-direction: column; gap: 6px; padding: 10px 12px; border-bottom: 1px solid var(--border); }
.task-new-title { font-size: 14px; height: 34px; }
.task-composer-meta { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.task-new-due { flex: 1 1 170px; min-width: 130px; }
.task-new-priority, .task-new-list { flex: 0 0 auto; width: auto; max-width: 140px; }
.task-main > .toolbar { border-bottom: 1px solid var(--border); }
.task-search { flex: 1; min-width: 120px; max-width: 320px; }
.task-sort, .task-groupby { width: auto; max-width: 190px; }

.task-groups { flex: 1; min-height: 0; overflow: auto; padding: 10px 12px 18px; display: flex; flex-direction: column; gap: 14px; }
.task-group { display: flex; flex-direction: column; gap: 2px; }
.task-group-head {
  display: flex; align-items: baseline; gap: 10px; padding: 2px 2px 6px;
  border-bottom: 1px solid var(--border); position: sticky; top: 0; background: var(--surface-solid);
}
.task-group-title { font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.task-group-count, .task-group-steps { font-size: 11px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.task-group-steps { margin-left: auto; }

.task-row {
  display: grid; grid-template-columns: 26px minmax(0, 1fr) auto; gap: 10px; align-items: start;
  padding: 8px 6px; border-radius: var(--radius-sm); border: 1px solid transparent;
}
.task-row:hover { background: var(--hover); }
.task-row.open { background: var(--surface-2); border-color: var(--border); }
/* Overdue is the only state allowed to colour the row itself: it is the reason this
   window was opened. */
.task-row.overdue { border-left: 3px solid var(--danger); }
.task-check {
  width: 22px; height: 22px; margin-top: 1px; border-radius: 6px; border: 2px solid var(--border-strong);
  background: transparent; color: transparent; cursor: pointer; font-size: 14px; line-height: 1;
  display: grid; place-items: center; transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.task-check::before { content: '✓'; }
.task-check:hover { border-color: var(--accent); }
.task-check:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.task-row.done .task-check { background: var(--ok); border-color: var(--ok); color: #08130d; }
.task-body { min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.task-title { font-size: 14px; line-height: 1.4; cursor: pointer; word-break: break-word; }
.task-row.done .task-title { color: var(--text-faint); text-decoration: line-through; }
.task-meta { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }
.task-chip {
  font-size: 10.5px; padding: 2px 7px; border-radius: 999px; border: 1px solid var(--border);
  color: var(--text-dim); background: var(--surface-2); white-space: nowrap;
}
.task-due-overdue { border-color: var(--danger); color: var(--danger); font-weight: 600; }
.task-due-today { border-color: var(--accent); color: var(--accent); font-weight: 600; }
.task-due-soon { border-color: var(--border-strong); color: var(--text); }
.task-due-later, .task-due-done { opacity: .65; }
.task-prio-high { border-color: var(--danger); color: var(--danger); }
.task-prio-medium { border-color: var(--warn); color: var(--warn); }
.task-list-chip { border-style: dashed; }
.task-tag { border-style: dotted; }
.task-notes { font-size: 12.5px; color: var(--text-dim); line-height: 1.5; white-space: pre-wrap; padding-top: 2px; }
/* Steps: a task with steps shows how far through it it is without being opened. */
.task-steps-bar { display: flex; align-items: center; gap: 8px; }
.task-steps-bar i { display: block; height: 4px; min-width: 24px; border-radius: 999px; background: var(--accent); }
.task-steps-count { font-size: 10.5px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.task-steps { display: flex; flex-direction: column; gap: 2px; padding-top: 2px; }
.task-steps:empty { display: none; }
.task-step { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.task-step-check {
  width: 17px; height: 17px; flex: 0 0 auto; border-radius: 4px; border: 1px solid var(--border-strong);
  background: transparent; color: var(--ok); cursor: pointer; font-size: 11px; line-height: 1;
}
.task-step-check.on { background: var(--ok); border-color: var(--ok); color: #08130d; }
.task-step-check:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.task-step-text { min-width: 0; word-break: break-word; }
.task-step-text.done { color: var(--text-faint); text-decoration: line-through; }
.task-step-remove { margin-left: auto; border: 0; background: transparent; color: var(--text-faint); cursor: pointer; font-size: 13px; }
.task-step-remove:hover { color: var(--danger); }
.task-step-add { font-size: 12.5px; height: 28px; margin-top: 3px; }
.task-actions { display: flex; gap: 2px; align-items: center; opacity: 0; transition: opacity .12s ease; }
.task-row:hover .task-actions, .task-row.open .task-actions, .task-row:focus-within .task-actions { opacity: 1; }
.task-act {
  min-width: 26px; height: 26px; padding: 0 6px; border: 1px solid transparent; border-radius: 6px;
  background: transparent; color: var(--text-dim); font: inherit; font-size: 11.5px; cursor: pointer;
}
.task-act:hover { background: var(--hover); color: var(--text); border-color: var(--border); }
.task-act:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; opacity: 1; }
.task-act-del:hover { color: var(--danger); }
.task-shown { color: var(--text-faint); }
.task-empty {
  display: flex; flex-direction: column; gap: 6px; align-items: center; justify-content: center;
  padding: 40px 20px; text-align: center; color: var(--text-dim);
}
.task-empty b { font-size: 15px; color: var(--text); }
.task-empty p { margin: 0; max-width: 46ch; font-size: 12.5px; line-height: 1.6; }
/* A window can be far narrower than the screen, so this app answers to its own width the
   way Files does. Below 720 the row actions stop hiding; below 560 the sidebar becomes a
   strip of filters along the top instead of a column stealing half the list. */
.app.tasks { container-type: inline-size; }
@container (max-width: 720px) {
  .task-side { width: 168px; flex: 0 0 168px; }
  .task-actions { opacity: 1; }
  .task-row { grid-template-columns: 24px minmax(0, 1fr) auto; gap: 6px; }
}
@container (max-width: 560px) {
  .tasks-wrap { flex-direction: column; }
  .task-side { flex: 0 0 auto; width: auto; gap: 6px; padding: 6px 0; border-right: 0; border-bottom: 1px solid var(--border); }
  .task-filters { flex-direction: row; flex-wrap: wrap; gap: 4px; padding: 0 10px; }
  .task-filter { padding: 4px 9px; font-size: 11.5px; }
  .task-side-head, .task-lists, .task-side .statusbar { display: none; }
  .task-progress { padding: 0 10px; }
  .task-composer { padding: 8px 10px; }
  .task-groups { padding: 8px 10px 14px; }
  .task-actions { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .task-check, .task-bar i, .task-actions { transition: none; }
}

/* ---------- settings ---------- */
.settings-main { flex: 1; overflow: auto; padding: 16px; }
.card { border: 1px solid var(--border); border-radius: 12px; padding: 14px; margin-bottom: 14px; background: var(--surface-2); }
.card h3 { margin: 0 0 4px; font-size: 14px; }
.card p { margin: 0 0 12px; color: var(--text-dim); font-size: 12.5px; }
.row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.wp-tile {
  width: 104px; height: 64px; border-radius: 9px; border: 2px solid var(--border); cursor: pointer;
  background-size: cover; background-position: center;
}
.wp-tile.active { border-color: var(--accent); }
/* Live wallpaper pattern picker: every tile is a real frame drawn by the engine.
   `.saver-pattern` is the screensaver's own picker — the same tiles, because it
   draws the same patterns, but a separate question from what the desktop wears. */
.wp-pattern, .saver-pattern {
  width: 104px; display: flex; flex-direction: column; gap: 4px; padding: 4px;
  border: 2px solid var(--border); border-radius: 9px; background: var(--surface-solid);
  cursor: pointer; color: var(--text-dim);
}
.wp-pattern:hover, .saver-pattern:hover { border-color: var(--border-strong); background: var(--hover); }
.wp-pattern.active, .saver-pattern.active { border-color: var(--accent); color: var(--text); }

/* The desktop clock's face picker. The tiles hold the real widget, so they are the
   size of the thing they are offering rather than a drawing of it. */
.dc-faces { gap: 10px; align-items: flex-start; }
.dc-face-tile {
  display: flex; flex-direction: column; gap: 5px; padding: 6px 8px 8px;
  border: 1px solid var(--border); border-radius: 10px; background: transparent;
  color: var(--text-dim); font: inherit; cursor: pointer;
}
/* The name under a preview is a caption, not a headline: the preview itself is the
   thing being chosen, and a full-size label would shout over a scaled-down clock. */
.dc-face-tile .wp-pattern-label { font-size: 13px; font-weight: 600; margin-top: auto; text-align: center; }
.dc-face-tile:hover { border-color: var(--border-strong); background: var(--hover); }
.dc-face-tile.active { border-color: var(--accent); color: var(--text); }
.dc-face-tile.active .wp-pattern-label { color: var(--text); }
.wp-preview, .wp-preview-static, .saver-preview, .saver-preview-static { width: 100%; height: 54px; display: block; border-radius: 6px; background-size: cover; background-position: center; }
/* The "your photos" tile shows a real picture from this filesystem, for the same
   reason the pattern tiles show real previews: the tile you click is what you get. */
img.saver-preview-photo { object-fit: cover; }
.saver-preview-empty {
  display: flex; align-items: center; justify-content: center; gap: 4px;
  background: var(--surface-3); color: var(--text-faint); font-size: 11px; font-style: italic;
}
/* The speed control shares the section header row so the picker stays above the fold. */
.wp-motion-head { justify-content: space-between; align-items: center; }
.wp-motion-head .start-section { margin: 0 0 2px; }
.wp-speed-group { display: flex; align-items: center; gap: 8px; }
.wp-speed { width: 150px; accent-color: var(--accent); }
.wp-speed:disabled { opacity: .45; }
.wp-speed-label { font-size: 12px; color: var(--text-dim); }
.wp-speed-value { font-size: 11.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.wp-status, .saver-status { margin-top: 4px; font-size: 11.5px; color: var(--text-faint); }
.wp-status.live, .saver-status.live { color: var(--text-dim); }
/* Settings → Appearance → Time of day. The bar is the whole day: every phase the
   width it really occupies, and a marker on the moment you are reading it at. It is
   painted with the same function the desktop is tinted with, so it cannot lie. */
.wp-daylight { gap: 6px; }
.dl-tile { width: 92px; }
.dl-daybar {
  position: relative; height: 34px; margin-top: 8px; border-radius: 8px; overflow: hidden;
  border: 1px solid var(--border); background-size: cover; background-position: center;
}
.dl-band, .dl-tick {
  position: absolute; font-size: 9.5px; letter-spacing: .04em; white-space: nowrap;
  color: #fff; background: rgb(0 0 0 / .38); padding: 1px 4px; border-radius: 4px;
  pointer-events: none; font-variant-numeric: tabular-nums;
}
.dl-band { top: 3px; text-transform: uppercase; }
.dl-tick { bottom: 3px; transform: translateX(-50%); background: none; color: rgb(255 255 255 / .8); text-shadow: 0 1px 3px rgb(0 0 0 / .7); }
.dl-tick.first { transform: none; }
/* `.dl-hand`, not `.dl-now`: the desktop-looks panel already uses that name for a
   pill, and a pill on a clock face is what it looked like. */
.dl-hand {
  position: absolute; top: 0; bottom: 0; width: 2px; background: var(--accent);
  /* A hairline with a cap: a wide halo would swallow the label it is standing on,
     and the whole point of the marker is to be read against them. */
  box-shadow: 0 0 0 1px rgb(0 0 0 / .45); transform: translateX(-1px);
}
.dl-hand::after {
  content: ''; position: absolute; top: 2px; left: -3px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--accent); border: 1.5px solid rgb(0 0 0 / .55);
}
.kv { display: grid; grid-template-columns: 130px 1fr; gap: 4px 10px; font-size: 12.5px; }
.kv .k { color: var(--text-dim); }

/* Settings → Desktop looks: one row per desktop, painted with that desktop's own
   wallpaper so the list is a picture of the desktops, not a table of names. */
.ws-looks { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.ws-look-row { display: flex; align-items: center; gap: 8px; }
.ws-look-swatch {
  width: 26px; height: 20px; flex: 0 0 auto; border-radius: 5px;
  border: 1px solid var(--border-strong); background: var(--wallpaper-default);
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / .22);
}
.ws-look-n {
  width: 18px; height: 18px; flex: 0 0 auto; border-radius: 4px; display: grid; place-items: center;
  background: var(--surface-3); font-size: 10px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.ws-look-name { font-size: 12.5px; font-weight: 600; flex: 0 1 auto; min-width: 76px; max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ws-look-note { flex: 1; min-width: 0; font-size: 11.5px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Settings → What is on each desktop: this swatch is a desk, not a wallpaper — a grid
   of icon tiles. */
.desk-swatch {
  background:
    radial-gradient(circle at 6px 6px, var(--accent) 2px, transparent 2.5px),
    radial-gradient(circle at 18px 6px, var(--accent) 2px, transparent 2.5px),
    radial-gradient(circle at 6px 15px, var(--text-dim) 2px, transparent 2.5px),
    var(--surface-2) !important;
}

/* Settings → Default apps: one row per file type. The extension is set in the mono face
   so the left edge reads as a column of file types rather than prose, and a type you
   changed is marked instead of being quietly different from the default. */
.assoc-row { gap: 6px; }
/* A row you changed should look changed from across the room, not just at the chip. */
.assoc-row.changed {
  padding: 4px 6px; margin: 0 -6px; border-radius: 9px;
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent);
}
.assoc-ext {
  flex: 0 0 58px; padding: 3px 6px; border-radius: 4px; text-align: center;
  font-family: var(--mono); font-size: 11.5px; font-weight: 600;
  color: var(--text-dim); background: var(--surface-3);
}
.assoc-row.changed .assoc-ext { color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.assoc-select { flex: 0 1 230px; min-width: 130px; font-size: 11.5px; }

/* One gesture per two lines in Settings: the picker on top, and underneath it the
   plain-words version of what the gesture is and what it now does. Nothing in this
   row is truncated, which is why the note is a line of its own. */
.gesture-row {
  display: flex; flex-direction: column; gap: 5px; padding: 8px 6px;
  border-top: 1px solid var(--border);
}
.gesture-row:first-child { border-top: 0; padding-top: 2px; }
.gesture-row.changed {
  border-radius: 9px; border-top: 0; background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent);
}
.gesture-row-main { display: flex; align-items: center; gap: 9px; }
.gesture-glyph {
  flex: 0 0 30px; height: 26px; display: grid; place-items: center; border-radius: 6px;
  background: var(--surface-3); color: var(--text-dim); font-size: 14px;
  border: 1px solid var(--border);
}
.gesture-row.changed .gesture-glyph { color: var(--accent); border-color: var(--accent); background: var(--surface-2); }
.gesture-name { flex: 0 0 104px; font-size: 12.5px; font-weight: 700; }
.gesture-row .assoc-select { flex: 1 1 auto; min-width: 150px; width: auto; }
.gesture-row-note {
  display: flex; flex-direction: column; gap: 2px; padding-left: 39px;
  font-size: 11px; color: var(--text-dim); line-height: 1.45;
}
.gesture-row-to { color: var(--text-dim); }

/* Keyboard shortcut editor. One row per binding the machine actually answers today —
   workspace slots that do not exist are not listed, and neither is an action that
   is not installed. */
.keys-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.keys-filter {
  flex: 1; min-width: 150px; height: 28px; padding: 0 10px; border-radius: 7px;
  border: 1px solid var(--border); background: var(--surface-solid); color: var(--text); font-size: 12.5px;
}
.keys-count { font-size: 11.5px; color: var(--text-faint); white-space: nowrap; }
.keys-status {
  margin: 0 0 10px; padding: 8px 10px; border-radius: 8px; font-size: 12.5px;
  border: 1px solid var(--border); background: var(--surface-solid); color: var(--text-dim);
}
.keys-status.ok { border-color: var(--ok); color: var(--text); }
.keys-status.warn { border-color: var(--warn); color: var(--text); }
.keys-status.err { border-color: var(--danger); color: var(--text); }
.keys-list { display: flex; flex-direction: column; }
.keys-note { margin: 12px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--text-faint); }
.keys-group { margin-bottom: 4px; }
.keyrow { display: flex; align-items: center; gap: 10px; padding: 4px 6px; border-radius: 8px; }
.keyrow:hover { background: var(--surface-solid); }
.keyrow.capturing { background: var(--surface-solid); outline: 1px solid var(--accent); }
.key-chord {
  min-width: 128px; flex: 0 0 auto; text-align: center; padding: 3px 7px; border-radius: 6px;
  font-family: var(--mono); font-size: 11.5px; border: 1px solid var(--border-strong);
  background: var(--surface-3); color: var(--text);
}
.key-chord.none { border-style: dashed; background: transparent; color: var(--text-faint); }
.key-chord.recording { border-color: var(--accent); color: var(--accent); animation: key-wait 1.2s ease-in-out infinite; }
@keyframes key-wait { 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) { .key-chord.recording { animation: none; } }
.key-label { flex: 1 1 auto; min-width: 0; font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.key-flag { font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--accent); flex: 0 0 auto; }
.key-actions { display: flex; gap: 6px; margin-left: auto; flex: 0 0 auto; }
.keyrow .btn.tiny { height: 26px; }
/* "Which key is free?" — the answer, offered inline while a row is listening. They go
   on a line of their own: three chords squeezed into the row would clip the name of the
   action, and the name is the part you are reading. */
.keyrow.capturing { flex-wrap: wrap; }
.key-suggest {
  order: 3; flex: 1 0 100%; display: flex; flex-wrap: wrap; gap: 6px;
  align-items: center; padding-top: 2px;
}
.key-suggest::before {
  content: 'keys nothing is using:'; font-size: 10px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-faint);
}
.key-suggest-btn { font-family: var(--mono); font-size: 11px; border-color: var(--accent); color: var(--accent); }
.key-suggest-btn:hover, .key-suggest-btn:focus-visible { background: var(--accent); color: var(--bg); border-color: var(--accent); }

/* ---------- web ---------- */
.web-main { flex: 1; min-height: 0; border: 0; width: 100%; background: #fff; }

/* ---------- welcome ---------- */
/* The tour is long and the window is not. The list scrolls and the buttons do not: a
   welcome screen whose "Open Terminal" is below the fold is a welcome screen you have to
   read all the way through before you can do anything. */
.welcome { display: flex; flex-direction: column; height: 100%; min-height: 0; padding: 16px 20px 0; }
.welcome .tour { flex: 1; min-height: 0; overflow: auto; padding-bottom: 12px; }
.welcome h1 { margin: 0 0 4px; font-size: 20px; }
.welcome .sub { color: var(--text-dim); margin-bottom: 12px; font-size: 12.5px; }
.welcome ul { margin: 0 0 14px; padding-left: 18px; font-size: 12.5px; line-height: 1.55; }
.welcome code { font-family: var(--mono); background: var(--surface-2); padding: 1px 5px; border-radius: 4px; font-size: 12px; }
.welcome .cta { display: flex; gap: 8px; flex-wrap: wrap; padding: 10px 0 12px; border-top: 1px solid var(--border); }

/* ---------- photos ---------- */
/* The gallery. The grid's column count and tile size are set by `gridPlan` in
   src/core/photos-core.js and arrive as custom properties, so the layout the app draws is
   the layout the rules describe. */
.photos-bar {
  display: flex; align-items: center; gap: 6px; padding: 7px 9px; flex-wrap: wrap;
  border-bottom: 1px solid var(--border); background: var(--surface-2);
}
.photos-bar .spacer { flex: 1 1 8px; min-width: 4px; }
.photo-albums { display: flex; flex-wrap: wrap; gap: 4px; flex: 1 1 240px; min-width: 0; padding-bottom: 2px; }
.photo-album {
  height: 26px; padding: 0 9px; flex: 0 0 auto; border-radius: 13px; cursor: pointer;
  border: 1px solid var(--border); background: var(--surface-3); color: var(--text-dim); font-size: 12px;
}
.photo-album:hover { background: var(--hover); color: var(--text); }
.photo-album.active { background: var(--accent); border-color: transparent; color: #fff; font-weight: 600; }
.photo-search { width: 172px; flex: 0 1 172px; }
.photo-sort { height: 28px; padding: 0 6px; }
.photo-size button { padding: 5px 9px; letter-spacing: .04em; }

.photo-main { flex: 1; min-height: 0; overflow: auto; padding: 12px; display: flex; flex-direction: column; }
/* `hidden` is an attribute, and a `display:` here outranks the browser's own
   `[hidden] { display: none }`. Without these two lines the gallery and the picture view
   are both on screen at once. */
.photo-grid[hidden], .photo-picture[hidden] { display: none; }
.photo-grid {
  display: grid; justify-content: start; align-content: start;
  grid-template-columns: repeat(var(--cols, 3), minmax(0, var(--tile, 176px)));
  gap: var(--gap, 12px);
}
.photo-tile {
  display: flex; flex-direction: column; padding: 0; text-align: left; cursor: pointer; color: var(--text);
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface-2); overflow: hidden;
}
.photo-tile:hover { border-color: var(--border-strong); background: var(--hover); }
.photo-tile.selected { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.photo-tile.broken { border-style: dashed; }
.photo-thumb { display: block; width: 100%; aspect-ratio: 1 / 1; overflow: hidden; background: var(--surface-3); }
.photo-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.photo-notimage { display: grid; place-items: center; height: 100%; font-size: 26px; opacity: .7; }
.photo-tile-name { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 6px 8px 7px; }
.photo-tile-name > span:first-child { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.photo-tile-meta { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); }

.photo-picture { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: 10px; }
.photo-stage {
  flex: 1; min-height: 0; display: grid; place-items: center; overflow: hidden;
  border: 1px solid var(--border); border-radius: 12px;
  background: repeating-conic-gradient(var(--surface-2) 0 25%, var(--surface-3) 0 50%) 50% / 22px 22px;
}
.photo-full { max-width: 100%; max-height: 100%; object-fit: contain; animation: photo-in .26s ease-out; }
@keyframes photo-in { from { opacity: 0; transform: scale(.985); } to { opacity: 1; transform: none; } }
.photo-broken { text-align: center; color: var(--text-dim); font-size: 13px; padding: 24px; }
.photo-broken span { font-size: 34px; display: block; margin-bottom: 8px; }
.photo-caption { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.photo-caption strong { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.photo-facts { font-family: var(--mono); font-size: 11.5px; color: var(--text-dim); }
.photo-actions, .photo-controls { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.photo-actions .spacer, .photo-controls .spacer { flex: 1 1 8px; min-width: 4px; }
.photo-actions .btn.danger[disabled] { opacity: .45; cursor: not-allowed; }
.photo-count { font-family: var(--mono); font-size: 12px; color: var(--text-dim); }
.photo-speed { height: 26px; padding: 0 5px; width: 62px; }
/* The bar *is* the slide: it fills over exactly the time the picture is up for. */
.photo-progress { height: 3px; border-radius: 3px; overflow: hidden; background: var(--surface-2); flex: 0 0 auto; }
.photo-progress i { display: block; height: 100%; background: var(--accent); transform-origin: left; transform: scaleX(0); }
@keyframes photo-slide { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.photo-status { font-family: var(--mono); font-size: 11.5px; }
@media (prefers-reduced-motion: reduce) { .photo-full { animation: none; } }

/* ---------- screenshots ---------- */
/* The shutter: the desktop briefly lights up, so you know which moment was taken. It is
   added *after* the desktop has been cloned, so the flash is never in the picture — and
   `Screenshot` does not add it at all when the OS has been asked to avoid motion. */
.shutter-flash {
  position: absolute; inset: 0; z-index: 100007; pointer-events: none;
  background: radial-gradient(circle at 50% 42%, rgba(255, 255, 255, .9), rgba(255, 255, 255, .3) 55%, rgba(255, 255, 255, 0) 100%);
  animation: shutter .34s ease-out forwards;
}
@keyframes shutter { 0% { opacity: 0; } 14% { opacity: 1; } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .shutter-flash { animation: none; opacity: 0; } }

/* ---------- monitor: the OS looking at itself ---------- */
/* Three screens over one set of numbers. The cards across the top are the same four the
   `monitor` command prints; the disk map is the part only a window can do, because it is
   the part you read by looking rather than by reading. */
.app.monitor { background: var(--surface-solid); }

.mon-cards {
  flex: 0 0 auto; display: grid; gap: 8px; padding: 10px 12px;
  grid-template-columns: repeat(auto-fit, minmax(178px, 1fr));
  border-bottom: 1px solid var(--border); background: var(--surface-2);
}
.mon-card { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-solid); padding: 7px 10px; display: grid; gap: 2px; align-content: start; }
.mon-card-top { display: flex; gap: 6px; align-items: center; font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase; color: var(--text-faint); }
.mon-card-glyph { font-size: 13px; }
.mon-card-value { font-family: var(--mono); font-size: 14.5px; font-weight: 600; line-height: 1.25; }
.mon-card-note { font-size: 11px; color: var(--text-dim); }
/* The activity card carries its own sparkline: the number of things that happened is not
   a shape, and the shape is the half you can read without looking at it. */
.mon-spark { font-family: var(--mono); font-size: 13px; line-height: 1; letter-spacing: 1px; color: var(--accent); }

.mon-tabs { flex: 0 0 auto; display: flex; gap: 4px; padding: 8px 12px 0; border-bottom: 1px solid var(--border); }
.mon-tab {
  display: flex; align-items: baseline; gap: 7px; padding: 6px 11px; cursor: pointer;
  border: 1px solid transparent; border-bottom: 0; border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  background: transparent; color: var(--text-dim);
}
.mon-tab:hover { background: var(--hover); color: var(--text); }
.mon-tab.selected { background: var(--surface-2); border-color: var(--border); color: var(--text); }
.mon-tab-label { font-size: 12.5px; font-weight: 600; }
.mon-tab-hint { font-size: 10.5px; color: var(--text-faint); }

.mon-body { flex: 1 1 auto; min-height: 0; overflow: auto; }

/* the disk map: area is bytes */
.mon-disk-head { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 10px 12px 8px; }
.mon-crumbs { display: flex; align-items: center; gap: 1px; font-family: var(--mono); font-size: 12px; min-width: 0; flex-wrap: wrap; }
.mon-crumb { border: 0; background: none; color: var(--text-dim); padding: 2px 6px; border-radius: var(--radius-sm); cursor: pointer; }
.mon-crumb:hover { background: var(--hover); color: var(--text); }
.mon-disk-total { font-family: var(--mono); font-size: 11px; color: var(--text-faint); }
.mon-disk-wrap { display: grid; grid-template-columns: minmax(0, 1fr) 232px; gap: 10px; padding: 0 12px 12px; }
.mon-disk {
  position: relative; min-height: 300px; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2);
}
.mon-tile {
  position: absolute; display: flex; flex-direction: column; gap: 1px; overflow: hidden;
  /* A button has a natural minimum size, and a treemap has no such thing: a 4-byte file
     is a 1 px box and that is the truth about it. Without this the browser quietly makes
     the small tiles bigger than the bytes they stand for. */
  appearance: none; min-width: 0; min-height: 0; border: 0;
  padding: 4px 6px; background: var(--surface-3);
  /* The seam between two tiles is drawn with an inset shadow, not a border: a border is
     part of the box, and a box cannot be smaller than its own border and padding, which
     would make the smallest tiles bigger than the bytes they stand for. `border: 0` is not
     fussiness — a `<button>` carries a 2 px outset border from the user-agent stylesheet, and
     without this every tile that was a button wore a grey frame the map did not draw. */
  box-shadow: inset 0 0 0 1px var(--surface-solid);
  color: var(--text); text-align: left; font: inherit; cursor: pointer;
  animation: tile-in .3s ease both;
}
/* The box of a tile never moves — only its paint and its label do. A map whose tiles
   slide about is a map you cannot read, and a map that moves while you are clicking it
   is a map that misses. */
@keyframes tile-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes tile-label-in { from { transform: translateY(4px); } to { transform: none; } }
/* A folder and a file are different kinds of thing, and a map that paints them the same
   colour asks you to click one to find out. Folders keep the accent and gain a corner
   mark; files are flatter and cooler, so a folder stands out before you read a label. */
.mon-tile-dir:not(.mon-tile-tiny)::before {
  content: ''; position: absolute; right: 0; bottom: 0; width: 10px; height: 10px;
  background: color-mix(in oklab, var(--accent) 80%, transparent);
  clip-path: polygon(0 100%, 100% 0, 100% 100%);
  opacity: .55;
}
.mon-tile-file { filter: saturate(.72); }
.mon-tile:hover { filter: brightness(1.14); z-index: 2; }
.mon-tile-file:hover { filter: saturate(.72) brightness(1.14); }
.mon-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; z-index: 3; }
.mon-tile.selected { outline: 2px solid var(--accent); outline-offset: -2px; z-index: 3; }
.mon-tile-name { font-size: 12px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; animation: tile-label-in .42s ease both; }
.mon-tile-bytes { font-family: var(--mono); font-size: 10.5px; opacity: .72; animation: tile-label-in .5s ease both; }
/* A tile too small to hold its name shows the name anyway, at the edge of readable: a
   disk map with silent small folders would be a map that hides the interesting ones. */
.mon-tile-tiny { padding: 0; }
.mon-tile-flat { cursor: default; }
.mon-tile-flat .mon-tile-name { display: none; }
/* A tile with no room for a name is a colour, not a caption. */
.mon-tile-unlabelled .mon-tile-name { display: none; }
.mon-tile-tiny .mon-tile-name { font-size: 9.5px; font-weight: 500; opacity: .78; }

.mon-side {
  display: grid; gap: 9px; align-content: start; padding: 10px; min-width: 0;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2);
}
.mon-side-title { font-size: 14px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mon-side-path { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); word-break: break-all; }
.mon-side-bytes { font-family: var(--mono); font-size: 17px; color: var(--accent); }
.mon-side-actions { display: flex; gap: 6px; flex-wrap: wrap; }
.mon-section { font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase; color: var(--text-faint); }
.mon-kinds { display: grid; gap: 5px; }
.mon-kind { display: grid; grid-template-columns: 58px minmax(0, 1fr) auto; gap: 6px; align-items: center; font-size: 11px; }
.mon-kind-label { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mon-kind-value { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); white-space: nowrap; }
.mon-bar-track { height: 6px; border-radius: 3px; background: var(--surface-3); overflow: hidden; }
.mon-bar-fill { display: block; height: 100%; border-radius: 3px; background: var(--accent); transition: width .3s ease; }
.mon-top { display: grid; gap: 1px; }
.mon-file {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: baseline;
  padding: 3px 6px; border: 0; border-radius: var(--radius-sm); background: none; cursor: pointer; text-align: left;
}
.mon-file:hover { background: var(--hover); }
.mon-file-name { font-family: var(--mono); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mon-file-bytes { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); }
.mon-note { font-size: 10.5px; color: var(--text-faint); }

/* activity: the journal, and a shape made of it */
.mon-activity-head { display: grid; gap: 10px; padding: 10px 12px 8px; }
.mon-hist {
  position: relative; display: flex; align-items: flex-end; gap: 2px; height: 84px; padding: 6px 8px 18px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2);
}
/* The bars stand on a line. Without it a histogram is just a pile of rectangles. */
.mon-hist::after { content: ""; position: absolute; left: 8px; right: 8px; bottom: 15px; height: 1px; background: var(--border-strong); opacity: .7; }
.mon-hist-bar {
  flex: 1 1 0; min-width: 2px; height: var(--h, 2%); min-height: 2px;
  border-radius: 2px 2px 0 0; background: var(--surface-3); transition: height .35s ease;
}
.mon-hist-bar.level-1 { background: color-mix(in oklab, var(--accent) 35%, transparent); }
.mon-hist-bar.level-2 { background: color-mix(in oklab, var(--accent) 62%, transparent); }
.mon-hist-bar.level-3 { background: var(--accent); }
.mon-hist-axis { position: absolute; bottom: 3px; font-family: var(--mono); font-size: 9.5px; color: var(--text-faint); letter-spacing: .04em; }
.mon-hist-axis-start { left: 8px; }
.mon-hist-axis-end { right: 8px; }
.mon-hist-caption { font-size: 11px; color: var(--text-dim); margin-top: 4px; }
.mon-filters { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.mon-spans, .mon-chips { display: flex; gap: 3px; flex-wrap: wrap; }
.mon-span, .mon-chip {
  height: 25px; padding: 0 9px; border: 1px solid var(--border); border-radius: 999px;
  background: transparent; color: var(--text-dim); font-size: 11.5px; cursor: pointer;
}
.mon-span:hover, .mon-chip:hover { background: var(--hover); color: var(--text); }
.mon-span.selected, .mon-chip.selected { background: var(--accent-soft); border-color: var(--accent); color: var(--text); }
.mon-search { flex: 1 1 160px; max-width: 260px; }
.mon-log { display: grid; gap: 1px; padding: 0 12px 12px; }
.mon-entry {
  display: grid; grid-template-columns: 66px 20px minmax(0, 1fr) minmax(0, 26%); gap: 8px; align-items: baseline;
  position: relative; padding: 4px 7px; border-radius: var(--radius-sm); font-size: 12.5px;
}
.mon-entry:hover { background: var(--hover); }
/* A log row is a row of a table that has no lines in it. The faint rule is what makes it
   read as a list of times rather than a pile of sentences. */
.mon-entry::after { content: ''; position: absolute; left: 7px; right: 7px; bottom: 0; height: 1px; background: var(--border); opacity: .55; }
.mon-entry-when { display: grid; gap: 1px; font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); }
.mon-entry-ago { font-size: 9.5px; opacity: .6; }
.mon-entry-glyph { text-align: center; }
.mon-entry-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mon-entry-detail { font-family: var(--mono); font-size: 10.5px; color: var(--text-faint); text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* on it: everything that is on the machine right now */
.mon-open { display: grid; gap: 12px; padding: 12px; grid-template-columns: repeat(auto-fit, minmax(272px, 1fr)); }
.mon-section-box { border: 1px solid var(--border); border-radius: var(--radius); padding: 10px; background: var(--surface-2); min-width: 0; }
.mon-list { display: grid; gap: 1px; margin-top: 6px; }
.mon-row {
  display: grid; grid-template-columns: 22px 118px minmax(0, 1fr) auto auto; gap: 8px; align-items: baseline;
  padding: 4px 6px; border: 0; border-radius: var(--radius-sm); background: none; cursor: pointer; text-align: left;
}
.mon-row:hover { background: var(--hover); }
.mon-row-glyph { text-align: center; }
.mon-row-name { font-size: 12px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mon-row-title { font-size: 11.5px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mon-row-tag { font-family: var(--mono); font-size: 10px; color: var(--text-faint); border: 1px solid var(--border); border-radius: 999px; padding: 0 6px; }
.mon-row-tag.here { border-color: var(--accent); color: var(--text); }
.mon-apps { display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 5px; margin-top: 6px; }
.mon-app {
  display: grid; gap: 2px; justify-items: center; padding: 7px 4px; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-solid);
}
.mon-app:hover { background: var(--hover); }
.mon-app.running { border-color: var(--accent); background: var(--accent-soft); }
.mon-app-icon { font-size: 19px; }
.mon-app-name { font-size: 10.5px; color: var(--text-dim); }
.mon-app-dot { font-size: 9px; color: var(--text-faint); }
.mon-app.running .mon-app-dot { color: var(--accent); }
.mon-facts { display: grid; gap: 0; margin-top: 6px; }
/* The status line is one long sentence and the window is not always wide. A status bar that
   wraps is three times as tall as the information it carries, and it pushes the map up out
   of the window. It gets one line, and the sentence is the part that gives way. */
.app.monitor .statusbar { flex-wrap: nowrap; }
.app.monitor .statusbar > span:first-child { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The watch note is the longer sentence and the less urgent one, so it is the one that gives
   way — and the whole of it stays reachable as the tooltip. */
.app.monitor .mon-watch { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mon-fact { display: grid; grid-template-columns: 104px minmax(0, 1fr); gap: 8px; padding: 3px 0; border-bottom: 1px solid var(--border); font-size: 11.5px; }
.mon-fact-label { color: var(--text-faint); }
.mon-fact-value { font-family: var(--mono); font-size: 11px; word-break: break-word; }

@media (max-width: 760px) {
  .mon-disk-wrap { grid-template-columns: minmax(0, 1fr); }
  .mon-entry { grid-template-columns: 58px 18px minmax(0, 1fr); }
  .mon-row { grid-template-columns: 20px minmax(0, 1fr) auto; }
  .mon-row-title { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .mon-tile, .mon-tile-name, .mon-tile-bytes { animation: none; }
  .mon-bar-fill, .mon-hist-bar { transition: none; }
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 8px; border: 2px solid transparent; background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
::-webkit-scrollbar-track { background: transparent; }

@media (max-width: 720px) {
  .files-side { width: 128px; }
  .notes-side { width: 178px; flex: 0 0 178px; }
  .launcher-panel { width: calc(100vw - 16px); }
  .start-label { display: none; }
  .tray-timer .tt-label { display: none; }
  .photo-albums { flex: 1 1 100%; }
  .photo-search { width: 132px; flex: 0 1 132px; }
}
