/* Shiny OS desktop shell.
 *
 * Unscoped on purpose: the desktop paints the page, and its custom properties are read by apps
 * hosted inside windows - which scoped CSS could not reach.
 *
 * Every colour here is a functional slot fed by OsThemeResolver. The fallbacks after each comma
 * are only what the page looks like before Blazor attaches; the theme always wins. Nothing in
 * this file hardcodes a palette. */

.os-desktop {
    --os-taskbar-size: 56px;

    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
    color: var(--os-window-fg, #e8e8ec);
    font-family: var(--os-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif);
    font-size: var(--os-font-size, 13px);
    user-select: none;
}


/* Density scales the padding of every control that opts in, so "compact" is one number. */
.os-desktop { --os-pad: calc(1px * var(--os-density, 1)); }

/* ---------- Shiny controls, wearing the OS theme ----------

   Shiny's controls colour themselves from Material tokens that default to a light surface. Inside
   a dark desktop those defaults are wrong in a way no app can fix from the outside: TreeView's
   selected row, for one, sets a pale-blue background and leaves the foreground inherited, so a
   desktop's own near-white text landed on it at about 1:1 - the row was there and the label was
   gone.

   Apps used to patch this each in their own scoped CSS, which is why it kept coming back: those
   overrides guess at the control's internal class names and go stale silently the moment one
   changes. Mapping the tokens once, here, fixes it for every Shiny control the desktop hosts -
   present and future - and keeps a single answer to "what colour is a selection".

   Only the desktop's own scope is touched, so a page hosting the shell alongside other Shiny UI
   does not have its colours rewritten out from under it. */
.os-desktop {
    --shiny-color-surface: var(--os-content-bg, #1e1e22);
    --shiny-color-on-surface: var(--os-content-fg, #e8e8ec);
    --shiny-color-surface-variant: var(--os-content-alt-bg, var(--os-content-bg, #1e1e22));
    --shiny-color-on-surface-variant: var(--os-text-secondary, #9aa4b2);

    /* Hover and the raised container both read as "slightly lifted off the surface", which is
       what the row-hover token already is. */
    --shiny-color-surface-container-high: var(--os-row-hover, rgba(127, 127, 127, .14));
    --shiny-color-surface-container-highest: var(--os-row-hover, rgba(127, 127, 127, .18));

    /* The three quieter container slots. Unmapped, they fell through to the control library's own
       palette - a slate-blue that stayed slate through every theme repaint, because no --os-* token
       was feeding it. The notebook is the only app that renders them, which is why it took a while
       to show up. */
    --shiny-color-surface-container-lowest: var(--os-content-bg, #1e1e22);
    --shiny-color-surface-container-low: var(--os-content-alt-bg, var(--os-content-bg, #1e1e22));
    --shiny-color-surface-container: var(--os-content-alt-bg, var(--os-content-bg, #1e1e22));

    --shiny-color-outline: var(--os-content-border, rgba(127, 127, 127, .35));
    --shiny-color-outline-variant: var(--os-content-border, rgba(127, 127, 127, .25));

    --shiny-color-primary: var(--os-accent, #3b82f6);
    --shiny-color-on-primary: var(--os-accent-fg, #ffffff);

    /* The selection pair. Both halves, deliberately: a container without its on-container is
       exactly the bug above. */
    --shiny-color-secondary-container: var(--os-selection-bg, rgba(59, 130, 246, .26));
    --shiny-color-on-secondary-container: var(--os-selection-fg, var(--os-content-fg, #e8e8ec));

    --shiny-color-primary-container: var(--os-selection-bg, rgba(59, 130, 246, .26));
    --shiny-color-on-primary-container: var(--os-selection-fg, var(--os-content-fg, #e8e8ec));

    --shiny-color-error: var(--os-danger, #ef4444);
    --shiny-color-scrim: var(--os-scrim, rgba(0, 0, 0, .5));
}

/* ---------- floating panels ----------

   A dialog is the one thing that floats over nothing but its own scrim, and it is why the surface
   slot above cannot simply be handed to everything.

   --os-content-bg is "transparent" in every stock preset, deliberately: app content sits inside
   window chrome that has already painted, so a second opaque fill there would be wasted paint. The
   dialog has no chrome underneath it, so the same mapping left its panel see-through - and a
   var() fallback could not save it, because the property was defined, just defined as transparent.

   So floating panels get an opaque slot instead. --os-menu-bg is the right one rather than an
   invented literal: it is what every other free-floating surface on this desktop already uses, and
   it is opaque in all four presets where content-bg is not. Scoped to the dialog, because the ~15
   controls that read the same slot sit INSIDE a window that has already painted and want the
   see-through behaviour they have. */
.os-desktop .shiny-dialog,
.os-desktop .shiny-dialog-backdrop {
    --shiny-color-surface: var(--os-menu-bg, var(--os-content-bg, #1e1e22));
    --shiny-color-surface-variant: var(--os-menu-hover, var(--os-row-hover, rgba(127, 127, 127, .14)));
}

.os-wallpaper { position: absolute; inset: 0; }
.os-surface { position: absolute; inset: 0; }

body.os-dragging { cursor: grabbing; }
body.os-dragging * { user-select: none !important; }

/* ---------- scrollbars ---------- */

.os-desktop *::-webkit-scrollbar { width: 10px; height: 10px; }
.os-desktop *::-webkit-scrollbar-track { background: var(--os-scrollbar-track, transparent); }

.os-desktop *::-webkit-scrollbar-thumb {
    background: var(--os-scrollbar-thumb, rgba(127, 127, 127, .3));
    border-radius: calc(var(--os-control-radius, 6px) / 1.5);
}

.os-desktop *::-webkit-scrollbar-thumb:hover { background: var(--os-scrollbar-thumb-hover, rgba(127, 127, 127, .5)); }
.os-desktop * { scrollbar-color: var(--os-scrollbar-thumb, rgba(127,127,127,.3)) var(--os-scrollbar-track, transparent); }

/* ---------- desktop icons ---------- */

.os-icons {
    position: absolute;
    inset: 12px auto 12px 12px;
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 4px;
}

.os-icon {
    width: 88px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: calc(8 * var(--os-pad)) calc(4 * var(--os-pad));
    border: 0;
    border-radius: var(--os-control-radius, 6px);
    background: transparent;
    color: var(--os-deskicon-fg, #fff);
    font: inherit;
    cursor: default;
    text-shadow: 0 1px 3px rgba(0, 0, 0, .7);
}

.os-icon:hover { background: var(--os-deskicon-hover, rgba(255, 255, 255, .12)); }
.os-icon.is-selected { background: var(--os-deskicon-selected, rgba(59, 130, 246, .34)); }

.os-icon-glyph {
    width: 46px;
    height: 46px;
    display: grid;
    place-items: center;
    font-size: 26px;
    border-radius: calc(var(--os-control-radius, 6px) * 2);
    background: var(--os-launcher-tile, rgba(255, 255, 255, .14));
    backdrop-filter: blur(calc(var(--os-blur, 22px) / 3));
}

.os-icon-label { font-size: .9em; text-align: center; line-height: 1.2; word-break: break-word; }

/* The Trash tile.  The tile is the same one every app gets - only the badge is new, and it hangs
   off the glyph box, so that box has to be the positioning context.  Setting position on
   .os-icon-glyph itself would apply to every app tile as well; scoping it to the trash keeps the
   change to the one tile that needs it. */
.os-icon-trash .os-icon-glyph { position: relative; }

/* Reads as a count, not as an alert, so it borrows the taskbar's badge slots rather than the
   danger colour: a bin with things in it is a normal state of a computer. */
.os-icon-badge {
    position: absolute;
    top: -3px;
    right: -3px;
    min-width: 15px;
    height: 15px;
    padding: 0 3px;
    border-radius: 8px;
    background: var(--os-badge-bg, #e5484d);
    color: var(--os-badge-fg, #fff);
    font-size: .68em;
    line-height: 15px;
    font-weight: 700;
    text-shadow: none;
}

/* ---------- windows ---------- */

.os-window {
    position: absolute;
    display: flex;
    flex-direction: column;
    min-width: 240px;
    min-height: 120px;
    border-radius: var(--os-window-radius, 10px);
    background: var(--os-window-bg, #1c1c21);
    color: var(--os-window-fg, #e8e8ec);
    border: var(--os-border-width, 1px) solid var(--os-window-border, rgba(255, 255, 255, .12));
    box-shadow: var(--os-window-shadow, 0 22px 60px rgba(0, 0, 0, .55));
    overflow: hidden;
    contain: layout paint;
}

.os-desktop.is-translucent .os-window { backdrop-filter: blur(var(--os-blur, 22px)) saturate(140%); }

.os-window.is-maximized {
    left: 0 !important;
    top: 0 !important;
    width: 100% !important;
    height: 100% !important;
    border-radius: 0;
    border-width: 0;
}

.os-window.is-minimized { display: none; }
.os-window.is-dragging { transition: none; will-change: left, top, width, height; }
.os-window:not(.is-active) { box-shadow: var(--os-window-shadow-inactive, 0 10px 28px rgba(0, 0, 0, .38)); }

.os-titlebar {
    display: flex;
    align-items: center;
    gap: calc(8 * var(--os-pad));
    height: var(--os-titlebar-height, 36px);
    padding: 0 calc(8 * var(--os-pad)) 0 calc(10 * var(--os-pad));
    flex: 0 0 auto;
    cursor: default;
    background: var(--os-titlebar-bg, transparent);
    color: var(--os-titlebar-fg, inherit);
    border-bottom: var(--os-border-width, 1px) solid var(--os-window-border, rgba(255, 255, 255, .12));
    touch-action: none;
}

.os-window:not(.is-active) .os-titlebar {
    background: var(--os-titlebar-inactive-bg, transparent);
    color: var(--os-titlebar-inactive-fg, rgba(232, 232, 236, .62));
}

.os-title-icon { font-size: 1.15em; }
.os-title-text { flex: 1 1 auto; min-width: 0; display: flex; align-items: baseline; gap: 8px; overflow: hidden; }
.os-title { font-size: .96em; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.os-title-status { font-size: .85em; opacity: .62; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.os-title-actions { display: flex; gap: 2px; flex: 0 0 auto; }

.os-chrome-btn {
    width: 26px;
    height: 24px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: calc(var(--os-control-radius, 6px) - 1px);
    background: transparent;
    color: inherit;
    cursor: pointer;
    padding: 0;
}

.os-chrome-btn svg { width: 10px; height: 10px; fill: none; stroke: currentColor; stroke-width: 1.2; stroke-linecap: round; }
.os-chrome-btn:hover { background: var(--os-titlebar-btn-hover, rgba(255, 255, 255, .10)); }

.os-chrome-btn.is-close:hover {
    background: var(--os-close-hover-bg, #e5484d);
    color: var(--os-close-hover-fg, #fff);
}

.os-window-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    position: relative;
    background: var(--os-content-bg, transparent);
    color: var(--os-content-fg, inherit);
}

/* eight resize edges */
.os-resize { position: absolute; z-index: 5; touch-action: none; }
.os-resize-n { top: -3px; left: 8px; right: 8px; height: 7px; cursor: ns-resize; }
.os-resize-s { bottom: -3px; left: 8px; right: 8px; height: 7px; cursor: ns-resize; }
.os-resize-e { right: -3px; top: 8px; bottom: 8px; width: 7px; cursor: ew-resize; }
.os-resize-w { left: -3px; top: 8px; bottom: 8px; width: 7px; cursor: ew-resize; }
.os-resize-ne { top: -3px; right: -3px; width: 12px; height: 12px; cursor: nesw-resize; }
.os-resize-nw { top: -3px; left: -3px; width: 12px; height: 12px; cursor: nwse-resize; }
.os-resize-se { bottom: -3px; right: -3px; width: 12px; height: 12px; cursor: nwse-resize; }
.os-resize-sw { bottom: -3px; left: -3px; width: 12px; height: 12px; cursor: nesw-resize; }

.os-snap-preview {
    position: absolute;
    z-index: 9;
    pointer-events: none;
    border: 2px solid var(--os-accent, #3b82f6);
    border-radius: var(--os-window-radius, 10px);
    background: color-mix(in srgb, var(--os-accent, #3b82f6) 18%, transparent);
    transition: left .09s ease, top .09s ease, width .09s ease, height .09s ease;
}

@media (prefers-reduced-motion: reduce) {
    .os-snap-preview { transition: none; }
}

/* ---------- taskbar ---------- */

.os-taskbar {
    position: absolute;
    display: flex;
    align-items: center;
    gap: calc(8 * var(--os-pad));
    padding: 0 calc(8 * var(--os-pad));
    background: var(--os-taskbar-bg, rgba(24, 24, 28, .82));
    color: var(--os-taskbar-fg, #e8e8ec);
    border: 0 solid var(--os-taskbar-border, rgba(255, 255, 255, .12));
    z-index: 500;
}

.os-desktop.is-translucent .os-taskbar { backdrop-filter: blur(var(--os-blur, 22px)) saturate(150%); }

.os-taskbar-bottom { left: 0; right: 0; bottom: 0; height: var(--os-taskbar-size); border-top-width: var(--os-border-width, 1px); }
.os-taskbar-top { left: 0; right: 0; top: 0; height: var(--os-taskbar-size); border-bottom-width: var(--os-border-width, 1px); }
.os-taskbar-left { left: 0; top: 0; bottom: 0; width: var(--os-taskbar-size); flex-direction: column; padding: calc(8 * var(--os-pad)) 0; border-right-width: var(--os-border-width, 1px); }
.os-taskbar-right { right: 0; top: 0; bottom: 0; width: var(--os-taskbar-size); flex-direction: column; padding: calc(8 * var(--os-pad)) 0; border-left-width: var(--os-border-width, 1px); }

.os-start {
    width: 40px;
    height: 40px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: var(--os-control-radius, 6px);
    background: transparent;
    color: inherit;
    cursor: pointer;
    flex: 0 0 auto;
}

.os-start:hover { background: var(--os-taskbar-hover, rgba(255, 255, 255, .10)); }
.os-start.is-on { background: var(--os-taskbar-active, rgba(59, 130, 246, .30)); }

.os-start-glyph { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; width: 18px; height: 18px; }
.os-start-glyph span { border-radius: 2px; background: currentColor; }

.os-tasks { display: flex; align-items: center; gap: 4px; flex: 1 1 auto; overflow: hidden; }
.os-taskbar-left .os-tasks, .os-taskbar-right .os-tasks { flex-direction: column; }

.os-task {
    display: flex;
    align-items: center;
    gap: 7px;
    max-width: 190px;
    padding: calc(7 * var(--os-pad)) calc(11 * var(--os-pad));
    border: 0;
    border-radius: var(--os-control-radius, 6px);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: .96em;
    cursor: pointer;
    position: relative;
}

.os-task:hover { background: var(--os-taskbar-hover, rgba(255, 255, 255, .10)); }
.os-task.is-active { background: var(--os-taskbar-active, rgba(59, 130, 246, .26)); }
.os-task-icon { font-size: 1.2em; flex: 0 0 auto; }
.os-task-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.os-task-dot {
    position: absolute;
    bottom: 3px;
    left: 50%;
    transform: translateX(-50%);
    width: 14px;
    height: 2.5px;
    border-radius: 2px;
    background: var(--os-taskbar-indicator, var(--os-accent, #3b82f6));
}

.os-taskbar-left .os-task-label, .os-taskbar-right .os-task-label { display: none; }

.os-tray { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; }

.os-tray-btn {
    position: relative;
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: var(--os-control-radius, 6px);
    background: transparent;
    color: inherit;
    cursor: pointer;
    font-size: 1.15em;
}

.os-tray-btn:hover, .os-tray-btn.is-on { background: var(--os-taskbar-hover, rgba(255, 255, 255, .10)); }

.os-tray-badge {
    position: absolute;
    top: 2px;
    right: 2px;
    min-width: 15px;
    height: 15px;
    padding: 0 3px;
    border-radius: 8px;
    background: var(--os-badge-bg, #e5484d);
    color: var(--os-badge-fg, #fff);
    font-size: .74em;
    line-height: 15px;
    font-weight: 700;
}

.os-clock {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 1px;
    padding: calc(4 * var(--os-pad)) calc(10 * var(--os-pad));
    border: 0;
    border-radius: var(--os-control-radius, 6px);
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
    line-height: 1.1;
}

.os-clock:hover { background: var(--os-taskbar-hover, rgba(255, 255, 255, .10)); }
.os-clock-time { font-size: .96em; font-weight: 600; font-variant-numeric: tabular-nums; }
.os-clock-date { font-size: .8em; color: var(--os-text-secondary, rgba(232, 232, 236, .62)); }

/* ---------- launcher ---------- */

.os-launcher {
    position: absolute;
    left: 12px;
    bottom: 12px;
    width: min(560px, calc(100% - 24px));
    max-height: min(560px, calc(100% - 24px));
    display: flex;
    flex-direction: column;
    border-radius: calc(var(--os-window-radius, 10px) * 1.4);
    background: var(--os-launcher-bg, rgba(24, 24, 28, .86));
    color: var(--os-launcher-fg, #e8e8ec);
    border: var(--os-border-width, 1px) solid var(--os-launcher-border, rgba(255, 255, 255, .12));
    box-shadow: var(--os-window-shadow, 0 22px 60px rgba(0, 0, 0, .55));
    z-index: 600;
    overflow: hidden;
}

.os-desktop.is-translucent .os-launcher { backdrop-filter: blur(calc(var(--os-blur, 22px) * 1.2)) saturate(150%); }

.os-launcher-search {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: calc(12 * var(--os-pad)) calc(14 * var(--os-pad));
    border-bottom: var(--os-border-width, 1px) solid var(--os-launcher-border, rgba(255, 255, 255, .12));
}

.os-launcher-search input {
    flex: 1 1 auto;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 1.08em;
    outline: none;
}

.os-launcher-body { overflow: auto; padding: calc(10 * var(--os-pad)) calc(12 * var(--os-pad)) calc(14 * var(--os-pad)); }
.os-launcher-group + .os-launcher-group { margin-top: 12px; }

.os-launcher-group h4 {
    margin: 0 0 6px 4px;
    font-size: .8em;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--os-text-secondary, rgba(232, 232, 236, .55));
}

.os-launcher-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 4px; }

.os-launcher-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: calc(12 * var(--os-pad)) calc(8 * var(--os-pad));
    border: 0;
    border-radius: var(--os-control-radius, 6px);
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
    text-align: center;
}

.os-launcher-tile:hover { background: var(--os-launcher-hover, rgba(255, 255, 255, .10)); }

.os-launcher-icon {
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
    font-size: 1.85em;
    border-radius: calc(var(--os-control-radius, 6px) * 2);
    background: var(--os-launcher-tile, rgba(255, 255, 255, .10));
}

.os-launcher-name { font-size: .96em; font-weight: 600; }
.os-launcher-desc { font-size: .8em; color: var(--os-text-secondary, rgba(232, 232, 236, .55)); line-height: 1.25; }
.os-launcher-empty { padding: 28px; text-align: center; color: var(--os-text-secondary, rgba(232, 232, 236, .55)); }

/* ---------- flyout ---------- */

.os-flyout {
    position: absolute;
    right: 12px;
    bottom: 12px;
    width: min(330px, calc(100% - 24px));
    max-height: min(560px, calc(100% - 24px));
    display: flex;
    flex-direction: column;
    border-radius: calc(var(--os-window-radius, 10px) * 1.4);
    background: var(--os-flyout-bg, rgba(24, 24, 28, .86));
    color: var(--os-flyout-fg, #e8e8ec);
    border: var(--os-border-width, 1px) solid var(--os-flyout-border, rgba(255, 255, 255, .12));
    box-shadow: var(--os-window-shadow, 0 22px 60px rgba(0, 0, 0, .55));
    z-index: 600;
    overflow: hidden;
}

.os-desktop.is-translucent .os-flyout { backdrop-filter: blur(calc(var(--os-blur, 22px) * 1.2)) saturate(150%); }

.os-flyout-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: calc(11 * var(--os-pad)) calc(13 * var(--os-pad));
    font-weight: 600;
    border-bottom: var(--os-border-width, 1px) solid var(--os-flyout-border, rgba(255, 255, 255, .12));
}

.os-flyout-clear { border: 0; background: transparent; color: var(--os-link-fg, var(--os-accent, #3b82f6)); font: inherit; font-size: .92em; cursor: pointer; }
.os-flyout-clear:disabled { color: var(--os-text-disabled, rgba(232, 232, 236, .34)); cursor: default; }
.os-flyout-list { flex: 1 1 auto; overflow: auto; padding: 8px; min-height: 60px; }
.os-flyout-empty { padding: 26px; text-align: center; color: var(--os-text-secondary, rgba(232, 232, 236, .5)); }

.os-note { display: flex; gap: 9px; padding: calc(9 * var(--os-pad)) calc(10 * var(--os-pad)); border-radius: var(--os-control-radius, 6px); cursor: pointer; }
.os-note:hover { background: var(--os-menu-hover, rgba(255, 255, 255, .10)); }
.os-note-icon { font-size: 1.15em; }
.os-note-body { flex: 1 1 auto; min-width: 0; }
.os-note-title { font-size: .96em; font-weight: 600; }
.os-note-message { font-size: .88em; color: var(--os-text-secondary, rgba(232, 232, 236, .72)); margin-top: 1px; }
.os-note-time { font-size: .8em; color: var(--os-text-disabled, rgba(232, 232, 236, .45)); margin-top: 3px; }
.os-note-dismiss { border: 0; background: transparent; color: var(--os-text-disabled, inherit); cursor: pointer; align-self: flex-start; }
.os-note-dismiss:hover { color: inherit; }
.os-note-success .os-note-title { color: var(--os-success, #30a46c); }
.os-note-error .os-note-title { color: var(--os-danger, #e5484d); }
.os-note-warning .os-note-title { color: var(--os-warning, #f5a623); }

.os-flyout-foot { border-top: var(--os-border-width, 1px) solid var(--os-flyout-border, rgba(255, 255, 255, .12)); padding: calc(10 * var(--os-pad)) calc(12 * var(--os-pad)); display: flex; flex-direction: column; gap: 8px; }
.os-quick { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: .92em; }
.os-quick-check { justify-content: flex-start; gap: 8px; }

.os-quick select, .os-quick input[type=color] {
    background: var(--os-toolbar-hover, rgba(255, 255, 255, .1));
    color: inherit;
    border: var(--os-border-width, 1px) solid var(--os-content-border, rgba(255, 255, 255, .14));
    border-radius: var(--os-control-radius, 6px);
    padding: 3px 6px;
    font: inherit;
    font-size: .92em;
}

.os-quick input[type=color] { padding: 0; width: 34px; height: 24px; }
.os-quick-actions { display: flex; gap: 6px; }

.os-quick-actions button {
    flex: 1 1 auto;
    padding: calc(6 * var(--os-pad));
    border: var(--os-border-width, 1px) solid var(--os-content-border, rgba(255, 255, 255, .14));
    border-radius: var(--os-control-radius, 6px);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: .88em;
    cursor: pointer;
}

.os-quick-actions button:hover { background: var(--os-menu-hover, rgba(255, 255, 255, .1)); }

/* ---------- desktop context menu ---------- */

.os-menu {
    position: fixed;
    z-index: 700;
    min-width: 180px;
    padding: 4px;
    border-radius: var(--os-control-radius, 6px);
    background: var(--os-menu-bg, #22222a);
    color: var(--os-menu-fg, #e8e8ec);
    border: var(--os-border-width, 1px) solid var(--os-menu-border, rgba(255, 255, 255, .14));
    box-shadow: var(--os-window-shadow, 0 22px 60px rgba(0, 0, 0, .55));
}

.os-menu button {
    display: block;
    width: 100%;
    text-align: left;
    padding: calc(7 * var(--os-pad)) calc(10 * var(--os-pad));
    border: 0;
    border-radius: calc(var(--os-control-radius, 6px) - 1px);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: .96em;
    cursor: pointer;
}

.os-menu button:hover { background: var(--os-menu-hover, rgba(255, 255, 255, .1)); }
.os-menu-sep { height: 1px; margin: 4px 6px; background: var(--os-menu-separator, rgba(255, 255, 255, .12)); }

/* Anything that destroys data.  The same slot the file manager tints its Delete command with, so
   the two agree on what "this one is not undoable" looks like. */
.os-menu button.is-danger { color: var(--os-menu-danger-fg, #f16a6f); }

/* Disabled has to lose the hover highlight as well as the colour: a row that lights up under the
   pointer and then does nothing reads as a broken menu rather than an unavailable command. */
.os-menu button:disabled { color: var(--os-text-disabled, rgba(232, 232, 236, .38)); cursor: default; }
.os-menu button:disabled:hover { background: transparent; }

/* The question above a confirm.  Not a button, so it must not look like one. */
.os-menu-note {
    padding: calc(7 * var(--os-pad)) calc(10 * var(--os-pad));
    max-width: 240px;
    font-size: .9em;
    line-height: 1.35;
    color: var(--os-text-secondary, rgba(232, 232, 236, .72));
}

/* ---------- tooltips ---------- */

.os-tooltip {
    position: fixed;
    z-index: 2000;
    max-width: 280px;
    padding: 5px 9px;
    border-radius: calc(var(--os-control-radius, 6px) - 2px);
    background: var(--os-tooltip-bg, #33333d);
    color: var(--os-tooltip-fg, #f2f2f6);
    border: var(--os-border-width, 1px) solid var(--os-tooltip-border, rgba(255, 255, 255, .16));
    font-family: var(--os-font-family, inherit);
    font-size: calc(var(--os-font-size, 13px) * 0.88);
    line-height: 1.35;
    pointer-events: none;
    opacity: 0;
    transform: translateY(2px);
    transition: opacity .12s ease, transform .12s ease;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .3);
}

.os-tooltip.is-open { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    .os-tooltip { transition: none; }
}

/* ---------- app surfaces ----------
 * Apps hosted in a window inherit these, so an app themes with the desktop without importing
 * anything of its own. The file manager's tokens are mapped onto the OS slots here - the two
 * frameworks agree on colour without either referencing the other. */

/* The extra `.os-desktop` here is load-bearing: the file manager declares its own fallbacks in a
 * *scoped* stylesheet, which compiles to `.fm-root[b-xxxxx]` - the same (0,2,0) specificity as
 * `.os-window-body .fm-root`. On a tie the later sheet wins, and the scoped bundle is always
 * linked after this one, so those fallbacks would silently beat the theme. */
.os-desktop .os-window-body .fm-root {
    --fm-bg: var(--os-content-bg, transparent);
    --fm-fg: var(--os-content-fg, inherit);
    --fm-border: var(--os-content-border, rgba(127, 127, 127, .22));
    --fm-hover: var(--os-row-hover, rgba(127, 127, 127, .12));
    --fm-accent: var(--os-accent, #3b82f6);
    --fm-selected: var(--os-selection-bg, rgba(59, 130, 246, .26));
    --fm-selected-fg: var(--os-selection-fg, inherit);
    --fm-header-bg: var(--os-content-header-bg, var(--os-window-bg, #1c1c21));
    --fm-alt-bg: var(--os-content-alt-bg, transparent);
    --fm-menu-bg: var(--os-menu-bg, #22222a);
    --fm-menu-fg: var(--os-menu-fg, inherit);
    --fm-menu-border: var(--os-menu-border, rgba(127, 127, 127, .22));
    --fm-menu-hover: var(--os-menu-hover, rgba(127, 127, 127, .14));
    --fm-menu-separator: var(--os-menu-separator, rgba(127, 127, 127, .22));
    --fm-danger: var(--os-menu-danger-fg, #f16a6f);
    --fm-toolbar-bg: var(--os-toolbar-bg, transparent);
    --fm-toolbar-border: var(--os-toolbar-border, rgba(127, 127, 127, .22));
    --fm-toolbar-hover: var(--os-toolbar-hover, rgba(127, 127, 127, .12));
    --fm-toolbar-active: var(--os-toolbar-active, rgba(59, 130, 246, .26));
    --fm-sidebar-bg: var(--os-sidebar-bg, transparent);
    --fm-text-secondary: var(--os-text-secondary, inherit);
    --fm-radius: var(--os-control-radius, 6px);
    --fm-border-width: var(--os-border-width, 1px);
    --fm-density: var(--os-density, 1);
    height: 100%;
}

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

/* ---------- taskbar window picker / jump list ---------- */

.os-taskmenu {
    position: absolute;
    z-index: 650;
    min-width: 232px;
    max-width: 320px;
    padding: 4px;
    border-radius: var(--os-control-radius, 6px);
    background: var(--os-menu-bg, #22222a);
    color: var(--os-menu-fg, #e8e8ec);
    border: var(--os-border-width, 1px) solid var(--os-menu-border, rgba(255, 255, 255, .14));
    box-shadow: var(--os-window-shadow, 0 22px 60px rgba(0, 0, 0, .55));
}

.os-desktop.is-translucent .os-taskmenu { backdrop-filter: blur(var(--os-blur, 22px)) saturate(150%); }

.os-taskmenu-head {
    padding: 6px 9px 5px;
    font-size: .82em;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--os-text-secondary, rgba(232, 232, 236, .55));
}

.os-taskmenu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: calc(6 * var(--os-pad)) calc(8 * var(--os-pad));
    border: 0;
    border-radius: calc(var(--os-control-radius, 6px) - 1px);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: .94em;
    cursor: pointer;
    text-align: left;
}

.os-taskmenu-item:hover { background: var(--os-menu-hover, rgba(255, 255, 255, .1)); }
.os-taskmenu-item.is-active { background: var(--os-selection-bg, rgba(59, 130, 246, .26)); color: var(--os-selection-fg, inherit); }
.os-taskmenu-label { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.os-taskmenu-close {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 18px;
    height: 18px;
    border-radius: 4px;
    opacity: .5;
}

.os-taskmenu-close:hover { opacity: 1; background: var(--os-close-hover-bg, #e5484d); color: var(--os-close-hover-fg, #fff); }
.os-taskmenu-sep { height: 1px; margin: 4px 6px; background: var(--os-menu-separator, rgba(255, 255, 255, .12)); }

/* Stacked indicator: one bar per window, up to three, so "several open" reads at a glance. */
.os-task-dot-1 { width: 14px; }
.os-task-dot-2 { width: 20px; box-shadow: 0 0 0 1px var(--os-taskbar-bg, transparent) inset; }
.os-task-dot-3 { width: 26px; }

.os-task-dot-2::after, .os-task-dot-3::after {
    content: "";
    position: absolute;
    inset: 0;
    background: repeating-linear-gradient(90deg, currentColor 0 5px, transparent 5px 8px);
    opacity: 0;
}

/* ---------- app menu bar ---------- */

.os-menubar { display: flex; align-items: center; gap: 1px; flex: 0 0 auto; }

.os-menubar-btn {
    padding: 3px 8px;
    border: 0;
    border-radius: calc(var(--os-control-radius, 6px) - 2px);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: .92em;
    cursor: pointer;
}

.os-menubar-btn:hover, .os-menubar-btn.is-open { background: var(--os-titlebar-btn-hover, rgba(255, 255, 255, .1)); }

.os-appmenu {
    position: absolute;
    left: 8px;
    top: var(--os-titlebar-height, 36px);
    z-index: 40;
    /* Wide enough that a label and its accelerator are separated by the gutter below rather than
       by whatever happens to be left over. */
    min-width: 244px;
}

/* Every rule below is written as `.os-appmenu .os-appmenu-*` on purpose.
 *
 * The panel carries BOTH classes - `class="os-menu os-appmenu"` - so the desktop context menu's
 * `.os-menu button` (0,1,1) matches these buttons too, and outranks a bare `.os-appmenu-item`
 * (0,1,0) whatever the source order.  That is not a hypothetical: it is what shipped.  `.os-menu
 * button` sets `display: block`, so `display: flex`, `align-items`, `gap` and every `flex` on the
 * children were all being discarded - the label and the shortcut collapsed into one inline text
 * run with literally 0px between them, and the accelerators did not line up with each other
 * because nothing was pushing them anywhere.  Adding the ancestor class (0,2,0) is the fix the
 * theming notes call for; `!important` would have hidden the cause and kept the trap for the next
 * rule someone adds here. */

.os-appmenu .os-appmenu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: calc(6 * var(--os-pad)) calc(9 * var(--os-pad));
    border: 0;
    border-radius: calc(var(--os-control-radius, 6px) - 1px);
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: .94em;
    cursor: pointer;
    text-align: left;
}

.os-appmenu .os-appmenu-item:hover:not(:disabled) { background: var(--os-menu-hover, rgba(255, 255, 255, .1)); }
.os-appmenu .os-appmenu-item:disabled { color: var(--os-text-disabled, rgba(127, 127, 127, .5)); cursor: default; }
.os-appmenu .os-appmenu-item.is-danger { color: var(--os-menu-danger-fg, #f16a6f); }
.os-appmenu .os-appmenu-check { flex: 0 0 12px; font-size: .9em; text-align: center; }

/* The label takes whatever is left and ellipsises rather than shoving the accelerator off the
   right edge.  `min-width: 0` is what makes that work: a flex item's default `min-width: auto`
   refuses to shrink below its content, so without it a long label wins the argument and the
   shortcut overflows the panel. */
.os-appmenu .os-appmenu-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* `margin-left: auto` rather than a fixed accelerator column in a grid.  A grid column sized for
   the shortcut is reserved on every row of every menu, so a menu that declares no shortcuts at
   all - View, Help, most context menus - grows a band of dead space down its right-hand side and
   the labels stop looking centred in their own panel.  With auto margin the span simply is not
   there when `OsMenuItem.Shortcut` is empty (the Razor never renders it), so those menus keep
   their natural width and nothing is reserved for a column that has no occupants.
   The 24px padding is the actual separation asked for; the flex `gap` above only guarantees 8px
   when a long label has eaten the free space, which is not enough to read across. */
.os-appmenu .os-appmenu-shortcut {
    flex: 0 0 auto;
    margin-left: auto;
    padding-left: 24px;
    white-space: nowrap;
    font-size: .85em;
    /* Dimmer than the label so the eye reads the verb first and the chord second. */
    color: var(--os-menu-shortcut-fg, rgba(232, 232, 236, .45));
}

/* A disabled row dims wholesale; leaving the shortcut on its own brighter token would make the
   accelerator look live while the command it belongs to is not. */
.os-appmenu .os-appmenu-item:disabled .os-appmenu-shortcut { color: inherit; }

/* ---------- taskbar badge / progress / attention ---------- */

.os-task-iconwrap { position: relative; display: inline-flex; flex: 0 0 auto; }

.os-task-badge {
    position: absolute;
    top: -5px;
    right: -7px;
    min-width: 14px;
    height: 14px;
    padding: 0 3px;
    border-radius: 7px;
    background: var(--os-badge-bg, #e5484d);
    color: var(--os-badge-fg, #fff);
    font-size: .68em;
    line-height: 14px;
    font-weight: 700;
    text-align: center;
}

.os-task-progress {
    position: absolute;
    left: 6px;
    right: 6px;
    bottom: 2px;
    height: 3px;
    border-radius: 2px;
    background: var(--os-taskbar-hover, rgba(255, 255, 255, .18));
    overflow: hidden;
}

.os-task-progress > span { display: block; height: 100%; background: var(--os-accent, #3b82f6); transition: width .2s ease; }

.os-task.needs-attention { animation: os-attention 1s ease-in-out 3; }

@keyframes os-attention {
    0%, 100% { background: transparent; }
    50% { background: color-mix(in srgb, var(--os-accent, #3b82f6) 45%, transparent); }
}

@media (prefers-reduced-motion: reduce) {
    .os-task.needs-attention { animation: none; outline: 2px solid var(--os-accent, #3b82f6); outline-offset: -2px; }
    .os-task-progress > span { transition: none; }
}

/* ---------- hover text ----------

   A hover that is a faint wash keeps the row's own text. A solid highlight - navy in the Windows
   packs, the accent on macOS - needs a text colour of its own, or it is black on navy: exactly
   what the old Classic pack shipped. Unset tokens fall through to inherit, so the modern packs are
   unchanged. The shortcut and the description follow the label so a hovered row reads as one. */
.os-desktop .os-menu button:hover:not(:disabled),
.os-desktop .os-appmenu .os-appmenu-item:hover:not(:disabled),
.os-desktop .os-taskmenu-item:hover { color: var(--os-menu-hover-fg, inherit); }

.os-desktop .os-appmenu .os-appmenu-item:hover:not(:disabled) .os-appmenu-shortcut { color: var(--os-menu-hover-fg, var(--os-menu-shortcut-fg, inherit)); }

.os-desktop .os-launcher-tile:hover { color: var(--os-launcher-hover-fg, inherit); }
.os-desktop .os-launcher-tile:hover .os-launcher-desc { color: var(--os-launcher-hover-fg, var(--os-text-secondary, inherit)); }

/* =====================================================================================
   Chrome styles

   OsTheme.Chrome, emitted by ShinyDesktop as one class on the root: os-chrome-modern | -win31 |
   -win95 | -winxp | -macos. Colours still come from the tokens; what lives here is shape - which
   side the caption buttons sit on, bevels in place of hairlines, a labelled start button, a dock.
   Modern has no rules: everything above already is the modern chrome.

   Every rule is prefixed `.os-desktop.os-chrome-*` so it outranks the base rule it reshapes
   (`.os-window:not(.is-active)` and `.os-chrome-btn.is-close:hover` are both 0,2,0) without
   reaching for !important.

   "Horizontal bar" selectors - `:is(.os-taskbar-bottom, .os-taskbar-top)` - scope anything that
   sizes buttons to the bar's height. A start pill that is 100% tall is a start button on a bottom
   bar and a 900px-tall green column on a left one.
   ===================================================================================== */

.os-start-label { display: none; }

/* ---------- Windows 95 and 3.1: the bevel ----------

   Four inset lines: white and near-black on the outside, a light and a mid grey inside. The greys
   are mixed from the face colour rather than written as #dfdfdf/#808080, so a user who pins a
   different window colour gets bevels that match it instead of grey ones round a beige window.
   3.1's windows are white, so its face is the taskbar grey - the colour its buttons actually were. */

.os-desktop.os-chrome-win95 { --os-face: var(--os-window-bg, #c0c0c0); }
.os-desktop.os-chrome-win31 { --os-face: var(--os-taskbar-bg, #c0c0c0); }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) {
    --os-bevel-hi: #ffffff;
    --os-bevel-lo: #0a0a0a;
    --os-bevel-shadow: color-mix(in srgb, var(--os-face) 67%, #000);
    --os-bevel-light: color-mix(in srgb, var(--os-face) 70%, #fff);
    --os-bevel-raised: inset -1px -1px var(--os-bevel-lo), inset 1px 1px var(--os-bevel-hi), inset -2px -2px var(--os-bevel-shadow), inset 2px 2px var(--os-bevel-light);
    --os-bevel-pressed: inset -1px -1px var(--os-bevel-hi), inset 1px 1px var(--os-bevel-lo), inset -2px -2px var(--os-bevel-light), inset 2px 2px var(--os-bevel-shadow);
    --os-bevel-field: inset -1px -1px var(--os-bevel-hi), inset 1px 1px var(--os-bevel-shadow), inset -2px -2px var(--os-bevel-light), inset 2px 2px var(--os-bevel-lo);
    --os-bevel-well: inset -1px -1px var(--os-bevel-hi), inset 1px 1px var(--os-bevel-shadow);

    /* The 50% checkerboard 95 used for a pressed-and-latched button and for scrollbar tracks. */
    --os-dither: repeating-conic-gradient(var(--os-bevel-hi) 0 25%, var(--os-face) 0 50%) 0 0 / 2px 2px;
}

/* No glass, no rounded tiles and no text shadow: none of it existed yet. XP shares the flat icon
   tile; it kept its label shadow, so that one stays. */
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-icon { text-shadow: none; border-radius: 0; }
.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-icon-glyph { background: transparent; backdrop-filter: none; }

/* Selection highlights the label only, the way Program Manager and Explorer did. */
.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-icon:hover,
.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-icon.is-selected { background: transparent; }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-icon.is-selected .os-icon-label {
    background: var(--os-deskicon-selected, #000080);
    color: var(--os-accent-fg, #fff);
    outline: 1px dotted var(--os-accent-fg, #fff);
    outline-offset: -1px;
    padding: 0 2px;
}

/* Caption buttons: bevelled grey, pressed rather than hovered. The icon set's glyph is hidden and
   drawn below instead - the era packs use the emoji set, whose "–" and "□" sit on the text
   baseline at whatever size the font decides, which is not a caption button. */
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-chrome-btn,
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-chrome-btn:hover {
    position: relative;
    width: 16px;
    height: 14px;
    border-radius: 0;
    background: var(--os-face);
    color: var(--os-bevel-lo);
    box-shadow: var(--os-bevel-raised);
}

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-chrome-btn:active { box-shadow: var(--os-bevel-pressed); }
.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-chrome-btn > * { display: none; }

/* Drawn glyphs, shared by 95 and XP. --os-glyph is the glyph's box; XP's buttons are bigger. */
.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn::before,
.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    box-sizing: border-box;
}

.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn:not(.is-restore)::after { content: none; }

.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn.is-min::before {
    width: calc(var(--os-glyph, 8px) * .75);
    height: 2px;
    background: currentColor;
    transform: translate(-50%, calc(var(--os-glyph, 8px) * .3));
}

.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn.is-max::before {
    width: calc(var(--os-glyph, 8px) + 1px);
    height: var(--os-glyph, 8px);
    border: 1px solid currentColor;
    border-top-width: 2px;
    transform: translate(-50%, -50%);
}

.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn.is-restore::before,
.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn.is-restore::after {
    width: calc(var(--os-glyph, 8px) * .8);
    height: calc(var(--os-glyph, 8px) * .7);
    border: 1px solid currentColor;
    border-top-width: 2px;
}

.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn.is-restore::before { transform: translate(-25%, -85%); }
.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn.is-restore::after { transform: translate(-75%, -15%); }

.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn.is-close::before,
.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn.is-close::after {
    content: "";
    width: calc(var(--os-glyph, 8px) * 1.1);
    height: 2px;
    background: currentColor;
}

.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn.is-close::before { transform: translate(-50%, -50%) rotate(45deg); }
.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-chrome-btn.is-close::after { transform: translate(-50%, -50%) rotate(-45deg); }

/* Taskbar: bevelled buttons sized to the bar, a latched-and-dithered active task, a sunken tray. */
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-taskbar { gap: 4px; padding: 0 3px; }
.os-desktop.os-chrome-win95 .os-taskbar-bottom { box-shadow: inset 0 1px var(--os-bevel-light); }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) :is(.os-start, .os-task),
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) :is(.os-start, .os-task):hover {
    border-radius: 0;
    background: var(--os-face);
    color: var(--os-taskbar-fg, #000);
    box-shadow: var(--os-bevel-raised);
}

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) :is(.os-taskbar-bottom, .os-taskbar-top) :is(.os-start, .os-task, .os-tray) {
    height: calc(100% - 8px);
    max-height: 30px;
}

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) :is(.os-taskbar-bottom, .os-taskbar-top) .os-start {
    display: flex;
    align-items: center;
    gap: 4px;
    width: auto;
    padding: 0 7px 0 5px;
    font-weight: 700;
}

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) :is(.os-taskbar-bottom, .os-taskbar-top) .os-task {
    flex: 0 1 160px;
    min-width: 0;
    max-width: 160px;
    padding: 0 8px;
}

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-start.is-on,
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-task.is-active { box-shadow: var(--os-bevel-pressed); }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-task.is-active { background: var(--os-dither); font-weight: 700; }
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-task-dot { border-radius: 0; bottom: 4px; }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-tray { padding: 0 6px; gap: 2px; box-shadow: var(--os-bevel-well); }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) :is(.os-tray-btn, .os-clock) { height: 100%; border-radius: 0; }
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-tray-btn { width: 26px; }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) :is(.os-tray-btn, .os-clock):hover,
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-tray-btn.is-on { background: transparent; }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-clock { justify-content: center; }
.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-clock-date { display: none; }
.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-clock-time { font-weight: 400; }

/* Menus, flyouts and tooltips: square, and the bevel is their only depth. */
.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) :is(.os-menu button, .os-taskmenu-item, .os-appmenu .os-appmenu-item) { border-radius: 0; }

.os-desktop.os-chrome-win95 :is(.os-menu, .os-taskmenu) {
    padding: 3px;
    border: 0;
    border-radius: 0;
    box-shadow: var(--os-bevel-raised);
}

.os-desktop.os-chrome-win95 :is(.os-menu-sep, .os-taskmenu-sep) {
    height: 0;
    margin: 3px 1px;
    background: none;
    border-top: 1px solid var(--os-bevel-shadow);
    border-bottom: 1px solid var(--os-bevel-hi);
}

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-tooltip { border-radius: 0; box-shadow: none; }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-quick-actions button {
    border: 0;
    border-radius: 0;
    background: var(--os-face);
    box-shadow: var(--os-bevel-raised);
}

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-quick-actions button:active { box-shadow: var(--os-bevel-pressed); }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) .os-quick select {
    border: 0;
    border-radius: 0;
    background: var(--os-content-bg, #fff);
    box-shadow: var(--os-bevel-field);
    padding: 3px 5px;
}

/* A flyout with a caption, so it reads as the little window it was. */
.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-flyout-head {
    background: var(--os-titlebar-bg, #000080);
    color: var(--os-titlebar-fg, #fff);
    border-bottom: 0;
}

.os-desktop.os-chrome-win95 .os-flyout {
    right: 2px;
    bottom: 0;
    padding: 3px;
    border: 0;
    border-radius: 0;
    box-shadow: var(--os-bevel-raised);
}

.os-desktop.os-chrome-win95 .os-flyout-head { padding: 3px 6px; }

/* Scrollbars. `scrollbar-color` has to go back to auto: Chrome ignores every ::-webkit-scrollbar
   rule on an element that sets it, and the base rule above sets it on everything. */
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) * { scrollbar-color: auto; scrollbar-width: auto; }
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) *::-webkit-scrollbar { width: 16px; height: 16px; }
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) *::-webkit-scrollbar-track { background: var(--os-dither); }

.os-desktop:is(.os-chrome-win95, .os-chrome-win31) *::-webkit-scrollbar-thumb,
.os-desktop:is(.os-chrome-win95, .os-chrome-win31) *::-webkit-scrollbar-thumb:hover {
    background: var(--os-face);
    border-radius: 0;
    box-shadow: var(--os-bevel-raised);
}

/* ---------- Windows 95 ---------- */

.os-desktop.os-chrome-win95 .os-window {
    padding: 3px;
    border: 0;
    box-shadow: var(--os-bevel-raised);
}

.os-desktop.os-chrome-win95 .os-window.is-maximized { padding: 0; box-shadow: none; }

.os-desktop.os-chrome-win95 .os-titlebar {
    gap: 3px;
    margin-bottom: 1px;
    padding: 0 2px 0 3px;
    border-bottom: 0;
}

.os-desktop.os-chrome-win95 .os-title { font-weight: 700; }
.os-desktop.os-chrome-win95 .os-title-actions { gap: 0; }

/* Close stands apart from the other two so it is not hit by a slip off Maximize. */
.os-desktop.os-chrome-win95 .os-chrome-btn.is-close { margin-left: 2px; }

.os-desktop.os-chrome-win95 .os-start-label { display: inline; }

/* The Start menu: a single column of rows beside the vertical "Windows95" band, opening straight
   off the taskbar rather than floating above it. */
.os-desktop.os-chrome-win95 .os-launcher {
    left: 2px;
    bottom: 0;
    width: min(300px, calc(100% - 4px));
    padding: 3px 3px 3px 27px;
    border: 0;
    border-radius: 0;
    box-shadow: var(--os-bevel-raised);
}

.os-desktop.os-chrome-win95 .os-launcher::before {
    content: "Windows95";
    position: absolute;
    left: 3px;
    top: 3px;
    bottom: 3px;
    width: 22px;
    /* Inline, not block: in vertical-rl the block axis is horizontal, so block padding widened the
       band over the first letters of every row beside it. */
    padding-inline: 6px;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    background: var(--os-bevel-shadow);
    color: var(--os-face);
    font: 700 18px "Arial Black", Arial, sans-serif;
    line-height: 22px;
}

.os-desktop.os-chrome-win95 .os-launcher-search {
    padding: 4px;
    border-bottom: 1px solid var(--os-bevel-shadow);
    box-shadow: 0 1px var(--os-bevel-hi);
}

.os-desktop.os-chrome-win95 .os-launcher-search input {
    padding: 3px 5px;
    background: var(--os-content-bg, #fff);
    color: var(--os-content-fg, #000);
    box-shadow: var(--os-bevel-field);
}

/* Rows rather than tiles - shared with XP, whose Start menu was also a list. */
.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-launcher-body { padding: 2px 0; }
.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-launcher-group + .os-launcher-group { margin-top: 4px; }
.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-launcher-group h4 { margin: 4px 8px 2px; }
.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-launcher-grid { grid-template-columns: 1fr; gap: 0; }

.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-launcher-tile {
    flex-direction: row;
    gap: 10px;
    padding: 3px 8px;
    border-radius: 0;
    text-align: left;
}

.os-desktop:is(.os-chrome-win95, .os-chrome-winxp) .os-launcher-icon { width: 26px; height: 26px; font-size: 1.3em; border-radius: 0; }
.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-launcher-desc { display: none; }
.os-desktop:is(.os-chrome-win95, .os-chrome-win31, .os-chrome-winxp) .os-launcher-name { font-weight: 400; }

/* ---------- Windows 3.1 ----------

   A black outline, a 3px grey frame and a black inner line - drawn as inset shadows, which paint
   over the window's white background but under its content. */

.os-desktop.os-chrome-win31 .os-window {
    padding: 4px;
    border: 1px solid var(--os-window-border, #000);
    box-shadow: inset 0 0 0 3px var(--os-face), inset 0 0 0 4px var(--os-window-border, #000);
}

.os-desktop.os-chrome-win31 .os-window.is-maximized { padding: 0; border-width: 0; box-shadow: none; }

.os-desktop.os-chrome-win31 .os-titlebar {
    gap: 0;
    padding: 0;
    border-bottom: 1px solid var(--os-window-border, #000);
}

.os-desktop.os-chrome-win31 .os-title-icon { display: none; }
.os-desktop.os-chrome-win31 .os-title-text { justify-content: center; }
.os-desktop.os-chrome-win31 .os-title { font-weight: 700; }

/* The actions group dissolves so its buttons become title-bar items that can be ordered one by
   one: the close button leaves for the far left, the other two stay right. Events still bubble
   through the dissolved element, so its stopPropagation keeps working. */
.os-desktop.os-chrome-win31 .os-title-actions { display: contents; }

.os-desktop.os-chrome-win31 .os-chrome-btn,
.os-desktop.os-chrome-win31 .os-chrome-btn:hover {
    width: calc(var(--os-titlebar-height, 20px) - 1px);
    height: 100%;
    border-left: 1px solid var(--os-window-border, #000);
}

/* The control-menu box. 3.1 had no close button; this box opened a menu whose default was Close,
   and double-clicking it closed the window - so Close is what it does here. */
.os-desktop.os-chrome-win31 .os-chrome-btn.is-close,
.os-desktop.os-chrome-win31 .os-chrome-btn.is-close:hover {
    order: -1;
    border-left: 0;
    border-right: 1px solid var(--os-window-border, #000);
    box-shadow: none;
}

.os-desktop.os-chrome-win31 .os-chrome-btn::before,
.os-desktop.os-chrome-win31 .os-chrome-btn::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
}

.os-desktop.os-chrome-win31 .os-chrome-btn:not(.is-restore)::after { content: none; }

.os-desktop.os-chrome-win31 .os-chrome-btn.is-close::before {
    width: 11px;
    height: 3px;
    border: 1px solid var(--os-bevel-shadow);
    background: var(--os-bevel-hi);
    transform: translate(-50%, -50%);
}

.os-desktop.os-chrome-win31 .os-chrome-btn.is-min::before { border-top: 4px solid currentColor; transform: translate(-50%, -30%); }
.os-desktop.os-chrome-win31 .os-chrome-btn.is-max::before { border-bottom: 4px solid currentColor; transform: translate(-50%, -70%); }
.os-desktop.os-chrome-win31 .os-chrome-btn.is-restore::before { border-bottom: 3px solid currentColor; transform: translate(-50%, -120%); }
.os-desktop.os-chrome-win31 .os-chrome-btn.is-restore::after { border-top: 3px solid currentColor; transform: translate(-50%, 20%); }

/* 3.1's buttons wore a black outline round their bevel. */
.os-desktop.os-chrome-win31 :is(.os-start, .os-task) { border: 1px solid var(--os-bevel-lo); border-radius: 2px; }

/* Program Manager: the launcher as a window, caption and all, over a grid of icons. */
.os-desktop.os-chrome-win31 .os-launcher {
    left: 8px;
    bottom: 8px;
    padding: 4px;
    border: 1px solid var(--os-launcher-border, #000);
    border-radius: 0;
    box-shadow: inset 0 0 0 3px var(--os-face), inset 0 0 0 4px var(--os-launcher-border, #000);
}

.os-desktop.os-chrome-win31 .os-launcher::before {
    content: "Program Manager";
    flex: 0 0 auto;
    height: var(--os-titlebar-height, 20px);
    line-height: var(--os-titlebar-height, 20px);
    text-align: center;
    font-weight: 700;
    background: var(--os-titlebar-bg, #000080);
    color: var(--os-titlebar-fg, #fff);
    border-bottom: 1px solid var(--os-launcher-border, #000);
}

.os-desktop.os-chrome-win31 .os-launcher-search input {
    padding: 2px 4px;
    border: 1px solid var(--os-launcher-border, #000);
    background: var(--os-content-bg, #fff);
}

.os-desktop.os-chrome-win31 .os-launcher-tile { border-radius: 0; }
.os-desktop.os-chrome-win31 .os-launcher-icon { background: transparent; border-radius: 0; }

.os-desktop.os-chrome-win31 :is(.os-menu, .os-taskmenu) {
    padding: 0;
    border-radius: 0;
    box-shadow: none;
}

.os-desktop.os-chrome-win31 .os-flyout {
    padding: 4px;
    border: 1px solid var(--os-flyout-border, #000);
    border-radius: 0;
    box-shadow: inset 0 0 0 3px var(--os-face), inset 0 0 0 4px var(--os-flyout-border, #000);
}

/* ---------- Windows XP (Luna) ----------

   The blue frame is drawn here, not by --os-border-width: that token is read by every control on
   the desktop, and 3px on all of them is not what XP looked like. The frame has no top edge - the
   rounded caption is the top. */

.os-desktop.os-chrome-winxp .os-window {
    border: 3px solid var(--os-window-border, #0831d9);
    border-top: 0;
    border-radius: var(--os-window-radius, 8px) var(--os-window-radius, 8px) 0 0;
}

.os-desktop.os-chrome-winxp .os-window:not(.is-active) { border-color: color-mix(in srgb, var(--os-window-border, #0831d9) 45%, #fff); }
.os-desktop.os-chrome-winxp .os-window.is-maximized { border-width: 0; border-radius: 0; }

.os-desktop.os-chrome-winxp .os-titlebar {
    padding: 0 5px 0 7px;
    border-bottom: 0;
    font-family: "Trebuchet MS", var(--os-font-family, Tahoma, sans-serif);
    text-shadow: 1px 1px 0 rgba(10, 24, 131, .85);
}

.os-desktop.os-chrome-winxp .os-window:not(.is-active) .os-titlebar { text-shadow: none; }
.os-desktop.os-chrome-winxp .os-title { font-weight: 700; font-size: 1.05em; }
.os-desktop.os-chrome-winxp .os-title-actions { gap: 2px; }

/* Glossy caption buttons: accent blue for minimise and maximise, the close slot's colour for
   close. XP's close button was red-orange at rest, not only on hover, so the hover slot is its
   base here and hovering brightens it. */
.os-desktop.os-chrome-winxp .os-chrome-btn,
.os-desktop.os-chrome-winxp .os-chrome-btn:hover {
    --os-glyph: 9px;
    position: relative;
    width: 21px;
    height: 21px;
    border: 1px solid #fff;
    border-radius: 3px;
    color: #fff;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--os-accent, #316ac5) 55%, #fff) 0%,
        var(--os-accent, #316ac5) 45%,
        color-mix(in srgb, var(--os-accent, #316ac5) 80%, #000) 100%);
    box-shadow: inset -1px -1px 1px rgba(0, 0, 0, .25);
}

.os-desktop.os-chrome-winxp .os-chrome-btn.is-close,
.os-desktop.os-chrome-winxp .os-chrome-btn.is-close:hover {
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--os-close-hover-bg, #f07b4f) 70%, #fff) 0%,
        color-mix(in srgb, var(--os-close-hover-bg, #f07b4f) 88%, #000) 45%,
        color-mix(in srgb, var(--os-close-hover-bg, #f07b4f) 70%, #000) 100%);
}

.os-desktop.os-chrome-winxp .os-chrome-btn:hover { filter: brightness(1.15); }
.os-desktop.os-chrome-winxp .os-chrome-btn:active { filter: brightness(.9); }
.os-desktop.os-chrome-winxp .os-window:not(.is-active) .os-chrome-btn { opacity: .6; }

.os-desktop.os-chrome-winxp .os-taskbar { padding: 0; gap: 6px; }

/* The start button is green whatever the accent - of all XP's colours it is the one that meant
   "Windows", which is why it has no slot. */
.os-desktop.os-chrome-winxp :is(.os-taskbar-bottom, .os-taskbar-top) .os-start,
.os-desktop.os-chrome-winxp :is(.os-taskbar-bottom, .os-taskbar-top) .os-start:hover {
    display: flex;
    align-items: center;
    gap: 5px;
    width: auto;
    height: 100%;
    padding: 0 22px 0 9px;
    border-radius: 0 14px 14px 0;
    background: linear-gradient(180deg, #3a9a3a 0%, #5ec85e 8%, #45ad45 40%, #3a9a3a 88%, #2d7d2d 100%);
    color: #fff;
    font: italic 700 1.45em "Franklin Gothic Medium", "Trebuchet MS", Tahoma, sans-serif;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, .55);
    box-shadow: inset -2px 0 3px rgba(0, 0, 0, .25), 2px 0 4px rgba(0, 0, 0, .25);
}

.os-desktop.os-chrome-winxp .os-start:hover { filter: brightness(1.1); }
.os-desktop.os-chrome-winxp .os-start.is-on { filter: brightness(.88); }
.os-desktop.os-chrome-winxp .os-start-label { display: inline; text-transform: lowercase; }

.os-desktop.os-chrome-winxp .os-task {
    max-width: 170px;
    border-radius: 3px;
    background: color-mix(in srgb, var(--os-taskbar-fg, #fff) 14%, transparent);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .2), inset 1px 1px 0 rgba(255, 255, 255, .2);
}

.os-desktop.os-chrome-winxp :is(.os-taskbar-bottom, .os-taskbar-top) .os-task { height: calc(100% - 12px); max-height: 32px; }
.os-desktop.os-chrome-winxp .os-task:hover { background: color-mix(in srgb, var(--os-taskbar-fg, #fff) 24%, transparent); }
.os-desktop.os-chrome-winxp .os-task.is-active { background: var(--os-taskbar-active, #1e52b7); box-shadow: inset 1px 1px 3px rgba(0, 0, 0, .5); }

/* The notification area's lighter blue well - another XP identity colour with no slot. */
.os-desktop.os-chrome-winxp :is(.os-taskbar-bottom, .os-taskbar-top) .os-tray {
    align-self: stretch;
    padding: 0 10px;
    background: linear-gradient(180deg, #0c59b9 0%, #139ee9 6%, #18b5f2 12%, #139beb 30%, #1290e8 90%, #0d8dea 100%);
    border-left: 1px solid #1042af;
    box-shadow: inset 1px 0 0 #1ba6f0;
}

.os-desktop.os-chrome-winxp :is(.os-tray-btn, .os-clock):hover,
.os-desktop.os-chrome-winxp .os-tray-btn.is-on { background: color-mix(in srgb, var(--os-taskbar-fg, #fff) 16%, transparent); }

/* The Start menu: a caption-blue header over a white list, flush with the taskbar. */
.os-desktop.os-chrome-winxp .os-launcher {
    left: 0;
    bottom: 0;
    width: min(380px, calc(100% - 8px));
    border: 1px solid var(--os-launcher-border, #1c4fc4);
    border-radius: var(--os-window-radius, 8px) var(--os-window-radius, 8px) 0 0;
    box-shadow: 3px 3px 10px rgba(0, 0, 0, .4);
}

.os-desktop.os-chrome-winxp .os-launcher-search {
    padding: 10px 12px;
    background: var(--os-titlebar-bg, #0058ee);
    color: var(--os-titlebar-fg, #fff);
    border-bottom: 0;
}

.os-desktop.os-chrome-winxp .os-launcher-search input {
    padding: 4px 8px;
    border-radius: 3px;
    background: var(--os-launcher-bg, #fff);
    color: var(--os-launcher-fg, #000);
}

.os-desktop.os-chrome-winxp :is(.os-menu, .os-taskmenu) {
    padding: 2px;
    border-radius: 0;
    box-shadow: 2px 2px 4px rgba(0, 0, 0, .3);
}

.os-desktop.os-chrome-winxp .os-flyout {
    right: 0;
    bottom: 0;
    border-radius: var(--os-window-radius, 8px) var(--os-window-radius, 8px) 0 0;
}

.os-desktop.os-chrome-winxp .os-tooltip { border-radius: 0; box-shadow: 2px 2px 3px rgba(0, 0, 0, .3); }

/* ---------- macOS ---------- */

.os-desktop.os-chrome-macos .os-titlebar { padding: 0 12px; }
.os-desktop.os-chrome-macos .os-title-icon { display: none; }

/* The right padding balances the lights on the left, so the title centres on the window rather
   than on whatever space the lights left over. */
.os-desktop.os-chrome-macos .os-title-text { justify-content: center; padding-right: 56px; }
.os-desktop.os-chrome-macos .os-title { font-size: 1em; }

/* Traffic lights: the group moves to the front, and close moves to the front of the group. */
.os-desktop.os-chrome-macos .os-title-actions { order: -1; gap: 8px; margin-right: 6px; }

.os-desktop.os-chrome-macos .os-chrome-btn,
.os-desktop.os-chrome-macos .os-chrome-btn:hover {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--os-light);
    color: rgba(0, 0, 0, .6);
    box-shadow: inset 0 0 0 .5px rgba(0, 0, 0, .18);
}

/* Yellow and green are Apple's whatever the accent - no theme should move them, so they have no
   slot. Red is the close slot, which the macOS pack sets to Apple's red. */
.os-desktop.os-chrome-macos .os-chrome-btn.is-close { order: -1; --os-light: var(--os-close-hover-bg, #ff5f57); }
.os-desktop.os-chrome-macos .os-chrome-btn.is-min { --os-light: #febc2e; }
.os-desktop.os-chrome-macos .os-chrome-btn:is(.is-max, .is-restore) { --os-light: #28c840; }

/* Glyphs appear only while the pointer is over the group, as on the real thing. */
.os-desktop.os-chrome-macos .os-chrome-btn > * { opacity: 0; transform: scale(.72); }
.os-desktop.os-chrome-macos .os-title-actions:hover .os-chrome-btn > * { opacity: 1; }

.os-desktop.os-chrome-macos .os-window:not(.is-active) .os-title-actions:not(:hover) .os-chrome-btn {
    background: color-mix(in srgb, var(--os-window-fg, #1d1d1f) 16%, var(--os-titlebar-inactive-bg, #f6f6f6));
}

/* The dock: a content-width shelf floating inside the band the taskbar reserves, so maximised
   windows still stop above it. Bottom only - a left or right bar keeps its shape. */
.os-desktop.os-chrome-macos .os-taskbar-bottom {
    left: 50%;
    right: auto;
    bottom: 6px;
    width: max-content;
    max-width: calc(100% - 24px);
    height: calc(var(--os-taskbar-size) - 10px);
    padding: 0 6px;
    gap: 4px;
    transform: translateX(-50%);
    border: 1px solid var(--os-taskbar-border, rgba(255, 255, 255, .5));
    border-radius: 18px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .22);
}

.os-desktop.os-chrome-macos .os-taskbar-bottom .os-tasks { flex: 0 1 auto; }
.os-desktop.os-chrome-macos .os-task { padding: 4px; border-radius: 10px; transition: transform .15s ease; }
.os-desktop.os-chrome-macos .os-task-label { display: none; }

/* The icon is scaled rather than re-rendered bigger: the size is a component parameter, and the
   dock is a CSS decision the markup should not have to know about. */
.os-desktop.os-chrome-macos .os-task-iconwrap { transform: scale(1.75); margin: 7px; }

/* No active highlight - the dot says running, and focus is the window's business. */
.os-desktop.os-chrome-macos .os-task:hover,
.os-desktop.os-chrome-macos .os-task.is-active { background: transparent; }

.os-desktop.os-chrome-macos .os-task:hover { transform: translateY(-4px) scale(1.1); }

.os-desktop.os-chrome-macos .os-task-dot {
    width: 4px;
    height: 4px;
    bottom: 0;
    border-radius: 50%;
    box-shadow: none;
}

.os-desktop.os-chrome-macos .os-task-dot::after { content: none; }

.os-desktop.os-chrome-macos .os-taskbar-bottom .os-tray {
    height: 60%;
    margin-left: 2px;
    padding-left: 6px;
    border-left: 1px solid color-mix(in srgb, var(--os-taskbar-fg, #1d1d1f) 18%, transparent);
}

.os-desktop.os-chrome-macos .os-clock-date { display: none; }

/* Launchpad-ish: centred over the dock, with squircle app tiles. */
.os-desktop.os-chrome-macos .os-launcher {
    left: 50%;
    bottom: 16px;
    width: min(640px, calc(100% - 24px));
    transform: translateX(-50%);
    border-radius: 16px;
}

.os-desktop.os-chrome-macos .os-launcher-icon { border-radius: 22%; box-shadow: 0 1px 3px rgba(0, 0, 0, .15); }

.os-desktop.os-chrome-macos :is(.os-menu, .os-taskmenu) {
    padding: 5px;
    border-radius: 8px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .18), 0 0 0 .5px rgba(0, 0, 0, .1);
}

.os-desktop.os-chrome-macos.is-translucent :is(.os-menu, .os-taskmenu) { backdrop-filter: blur(30px) saturate(180%); }

@media (prefers-reduced-motion: reduce) {
    .os-desktop.os-chrome-macos .os-task { transition: none; }
    .os-desktop.os-chrome-macos .os-task:hover { transform: none; }
}
