/*
 * RitualOS shell.
 *
 * RitualOS is a life operating system, so the dashboard is a desktop rather than a page: modules
 * open as real windows that can be dragged, snapped, maximised, minimised and stacked, with a
 * taskbar along the bottom, a Start menu and an Action Center.
 *
 * Each window frames the module's own page with ?zwin=1, which tells app/shell/head.php to
 * render the content without its own topbar or drawer. That means every existing page works
 * as a window with no changes to any of them.
 *
 * The look is Windows 10: square windows with a 32px title bar and the three caption buttons,
 * a 40px acrylic taskbar with the logo Start button, a Start menu of a rail, an all-apps list
 * and pinned tiles, and flyouts that sit flush against the taskbar.
 *
 * Loaded only by the desktop, not by every page. Metrics (--taskbar-h, --win-bar-h,
 * --caption-w, --start-w …) come from tokens.css.
 */

@layer shell {

  /* ══ desktop ══════════════════════════════════════════════════════════════════════════════ */
  body.is-desktop {
    height: 100vh;
    overflow: hidden;             /* the desktop does not scroll; windows do */
  }
  body.is-desktop .app-container {
    padding: 0;
    max-width: none;
    gap: 0;
    height: 100vh;
  }

  .z-desktop {
    position: relative;
    flex: 1;
    min-height: 0;
    padding: var(--sp-4);
    padding-bottom: calc(var(--taskbar-h) + var(--sp-4));
    overflow: hidden;
  }

  /* Peek: hovering the sliver at the end of the taskbar makes every window a ghost so the
     desktop shows through. */
  .z-desktop.is-peeking .z-win {
    opacity: 0.08;
    transition: opacity var(--dur) var(--ease-decel);
  }
  .z-desktop.is-peeking .z-gadget { opacity: 1; }


  /* ══ desktop gadgets ══════════════════════════════════════════════════════════════════════
     The at-a-glance layer that sits on the desktop itself, under the windows. */
  .z-gadgets {
    display: grid;
    /* 300px, not 230px. At 230 a 1600px desktop got six columns, which made the smallest
       widget 242px wide -- narrow enough that "Open tasks" rendered as "Open tas...". */
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    /* `dense` is load-bearing, not a polish. Without it a widget that cannot fit in the
       columns left on the current row starts a new one and leaves the remainder empty: a
       three-column Do Now followed by a full-width launcher left half the desktop blank for
       two rows running. Dense backfills those gaps with the smaller widgets that come after.
       Reordering is safe here because the grid carries no reading order -- each widget is a
       self-contained card, and the ones that must not move are full-width anyway. */
    grid-auto-flow: row dense;
    /* Rows stay content-sized. A `minmax(150px, auto)` floor looks like an improvement and is
       not: the auto maximum resolves against each card's min-content height, and because a
       widget body is a flex column that is allowed to shrink, that contribution collapses --
       so every row sat at exactly the 150px floor and clipped its own contents. */
    gap: var(--sp-4);
    align-content: start;
    height: 100%;
    overflow-y: auto;
    padding-right: var(--sp-2);
  }


  /* ══ window ═══════════════════════════════════════════════════════════════════════════════
     Square, opaque, one hairline. The active window's border takes the accent when the user
     has accent title bars on (the default); otherwise it stays neutral. */
  .z-win {
    position: absolute;
    display: flex;
    flex-direction: column;
    min-width: 320px;
    min-height: 200px;
    border-radius: 0;
    overflow: hidden;
    background: var(--surface-1);
    border: 1px solid var(--border-strong);
    box-shadow: var(--shadow-3);
    /* `backwards`, never `both`: a filled end state would outrank .is-min and .is-closing. */
    animation: z-win-open var(--dur-slow) var(--ease-decel) backwards;
    transition: opacity var(--dur) var(--ease-accel), transform var(--dur) var(--ease-accel);
  }

  @keyframes z-win-open {
    from { opacity: 0; transform: scale(0.92); }
    to   { opacity: 1; transform: none; }
  }

  .z-win.is-active { box-shadow: var(--shadow-4); }
  :root:not([data-accent-chrome="none"]) .z-win.is-active { border-color: var(--accent); }
  .z-win:not(.is-active) .z-win__title { color: var(--text-muted); }

  /* Minimise flies toward the window's own taskbar button; --min-x/--min-y are measured by
     os.js at the moment it happens. Restore plays the same path in reverse. */
  .z-win.is-min {
    opacity: 0;
    pointer-events: none;
    transform: translate(var(--min-x, 0px), var(--min-y, 40vh)) scale(0.1);
    transition: opacity var(--dur) var(--ease-accel), transform var(--dur-slow) var(--ease-accel);
  }
  .z-win.is-instant { transition: none !important; animation: none !important; }

  .z-win.is-closing {
    opacity: 0;
    transform: scale(0.96);
    transition: opacity var(--dur-fast) var(--ease-accel), transform var(--dur-fast) var(--ease-accel);
  }

  .z-win.is-snapping {
    transition: left var(--dur) var(--ease-decel), top var(--dur) var(--ease-decel),
                width var(--dur) var(--ease-decel), height var(--dur) var(--ease-decel);
  }

  /* ── title bar ─────────────────────────────────────────────────────────────────────────── */
  .z-win__bar {
    height: var(--win-bar-h);
    flex: none;
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: 0 0 0 var(--sp-2);
    cursor: default;
    user-select: none;
    background: var(--surface-2);
    color: var(--text-primary);
    border-bottom: 1px solid var(--border-subtle);
  }
  :root:not([data-accent-chrome="none"]) .z-win.is-active .z-win__bar {
    background: var(--accent);
    color: var(--accent-contrast);
    border-bottom-color: transparent;
  }
  :root:not([data-accent-chrome="none"]) .z-win.is-active .z-win__title { color: inherit; }

  .z-win__icon  { flex: none; font-size: 0.95rem; line-height: 1; }
  .z-win__title {
    flex: 1;
    min-width: 0;
    font-family: var(--font-body);
    font-size: var(--fs-xs);
    font-weight: var(--fw-normal);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-shadow: none;
  }

  /* ── caption buttons ───────────────────────────────────────────────────────────────────── */
  .z-win__ctrls { display: flex; flex: none; height: 100%; }

  .z-win__btn {
    width: var(--caption-w);
    height: 100%;
    padding: 0;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 0;
    background: none;
    color: inherit;
    cursor: default;
    user-select: none;
    transition: background var(--dur-fast) var(--ease-decel), color var(--dur-fast) var(--ease-decel);
  }
  .z-win__btn .z-icon { width: 16px; height: 16px; stroke-width: 1.25; }
  .z-win__btn:hover  { background: var(--surface-raise-2); }
  .z-win__btn:active { background: var(--surface-raise-3); }
  :root:not([data-accent-chrome="none"]) .z-win.is-active .z-win__btn:hover  { background: rgba(255, 255, 255, 0.18); }
  :root:not([data-accent-chrome="none"]) .z-win.is-active .z-win__btn:active { background: rgba(255, 255, 255, 0.28); }
  .z-win__btn--close:hover,
  .z-win.is-active .z-win__btn--close:hover { background: var(--close-red); color: #fff; }
  .z-win__btn--close:active,
  .z-win.is-active .z-win__btn--close:active { background: color-mix(in oklab, var(--close-red), black 20%); color: #fff; }
  .z-win__btn:focus-visible { box-shadow: inset 0 0 0 2px currentColor; }

  /* One button carries both glyphs; the state picks. */
  .z-win__btn .z-icon--restore { display: none; }
  .z-win.is-max .z-win__btn .z-icon--restore { display: block; }
  .z-win.is-max .z-win__btn .z-icon--max { display: none; }

  /* ── body ──────────────────────────────────────────────────────────────────────────────── */
  .z-win__body { flex: 1; min-height: 0; position: relative; background: var(--surface-1); }
  .z-win__body iframe { width: 100%; height: 100%; border: 0; display: block; }

  /* While a window is being dragged the iframe must stop swallowing pointer events, or the
     drag dies the moment the cursor crosses into the frame. */
  .z-desktop.is-dragging .z-win__body { pointer-events: none; }

  .z-win__loading {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    background: var(--surface-1);
    color: var(--text-muted);
    font-size: var(--fs-md);
  }

  .z-win__resize {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 14px;
    height: 14px;
    cursor: nwse-resize;
  }

  .z-win.is-max { border-radius: 0; }


  /* ══ snap preview ═════════════════════════════════════════════════════════════════════════
     The translucent outline that appears while a window is dragged to an edge, showing where
     it will land. Aero Snap. */
  .z-snap-hint {
    position: absolute;
    border-radius: var(--r-lg);
    background: var(--accent-soft);
    border: 2px solid var(--accent-line);
    box-shadow: var(--glow-accent);
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--dur-fast) var(--ease-out),
                left var(--dur) var(--ease-out), top var(--dur) var(--ease-out),
                width var(--dur) var(--ease-out), height var(--dur) var(--ease-out);
    z-index: 5;
  }
  .z-snap-hint.is-on { opacity: 1; }


  /* ══ taskbar ══════════════════════════════════════════════════════════════════════════════
     40px of acrylic along the bottom. Every control on it is a 40px-tall flat button whose
     hover is a lighter face and whose "running" state is a line along its bottom edge. */
  .z-taskbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--taskbar-h);
    z-index: var(--z-header);
    display: flex;
    align-items: stretch;
    gap: 0;
    padding: 0;
    background: var(--acrylic-noise), var(--taskbar-bg);
    -webkit-backdrop-filter: var(--acrylic-filter);
    backdrop-filter: var(--acrylic-filter);
    border-top: 1px solid var(--border-subtle);
    color: var(--text-primary);
    user-select: none;
  }
  [data-accent-chrome~="taskbar"] .z-taskbar {
    background: var(--acrylic-noise), color-mix(in srgb, var(--accent-dark2) 85%, transparent);
    color: var(--accent-contrast);
  }

  .z-tb-btn,
  .z-start,
  .z-taskview-btn,
  .z-task,
  .z-tray__btn,
  .z-tray__clock {
    display: inline-grid;
    place-items: center;
    height: 100%;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: inherit;
    cursor: default;
    transition: background var(--dur-fast) var(--ease-decel);
  }
  .z-start:hover, .z-taskview-btn:hover, .z-task:hover, .z-tray__btn:hover, .z-tray__clock:hover,
  .z-tb-search:hover { background: var(--surface-raise-2); }
  .z-start:active, .z-taskview-btn:active, .z-tray__btn:active, .z-tray__clock:active { background: var(--surface-raise-3); }
  .z-start.is-open, .z-taskview-btn.is-active, .z-tray__clock.is-active, .z-tray__btn[aria-expanded="true"] {
    background: var(--surface-raise-3);
  }
  .z-start:focus-visible, .z-taskview-btn:focus-visible, .z-task:focus-visible, .z-tray__btn:focus-visible,
  .z-tray__clock:focus-visible, .z-tb-search:focus-visible { box-shadow: inset 0 0 0 2px var(--text-primary); }

  /* The Start button: RitualOS's own mark, 48px wide. */
  .z-start { width: 48px; flex: none; }
  .z-start .z-icon { width: 18px; height: 18px; }
  .z-start__logo { width: 22px; height: 22px; display: block; transition: transform var(--dur-fast) var(--ease-decel); }
  .z-start:hover .z-start__logo { transform: scale(1.08); }
  .z-start.is-open .z-start__logo { transform: scale(0.94); }
  .z-start:hover .z-icon { color: var(--accent-light2); }
  [data-accent-chrome~="taskbar"] .z-start:hover .z-icon { color: #fff; }

  /* The search box. */
  .z-tb-search {
    flex: none;
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    width: 260px;
    height: 100%;
    padding: 0 var(--sp-3);
    border: 0;
    border-radius: 0;
    background: var(--surface-raise-1);
    color: var(--text-secondary);
    font: inherit;
    font-size: var(--fs-sm);
    text-align: left;
    cursor: text;
    transition: background var(--dur-fast) var(--ease-decel);
  }
  .z-tb-search .z-icon { width: 16px; height: 16px; flex: none; }
  .z-tb-search__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  [data-theme="light"] .z-tb-search { background: #ffffff; color: var(--text-muted); }

  .z-taskview-btn { width: 48px; flex: none; }
  .z-taskview-btn .z-icon { width: 18px; height: 18px; }

  /* The desktop pill sits between Task View and the running apps as a small label. */
  .z-workspaces-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    height: 100%;
    padding: 0 var(--sp-3);
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--text-muted);
    font-size: var(--fs-xs);
    cursor: default;
    white-space: nowrap;
    transition: background var(--dur-fast) var(--ease-decel), color var(--dur-fast) var(--ease-decel);
  }
  .z-workspaces-pill:hover { background: var(--surface-raise-2); color: var(--text-primary); }
  .z-ws-pill__icon { font-size: 0.9rem; line-height: 1; }
  .z-ws-pill__name { max-width: 110px; overflow: hidden; text-overflow: ellipsis; }
  .z-ws-pill__dots { display: inline-flex; align-items: center; gap: 3px; }
  .z-ws-dot, .z-ws-pill__dot {
    width: 5px;
    height: 5px;
    border-radius: 0;
    background: var(--text-faint);
    transition: background var(--dur) var(--ease-decel);
  }
  .z-ws-dot.is-active, .z-ws-pill__dot.is-active { background: var(--accent); }

  .z-taskbar__items {
    display: flex;
    align-items: stretch;
    gap: 0;
    flex: 1;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
    height: 100%;
  }
  .z-taskbar__items::-webkit-scrollbar { display: none; }

  /* A running window's taskbar button: the icon alone, 48px wide, with a line along the
     bottom that says "running" and widens when the window is the active one. */
  .z-task {
    position: relative;
    flex: none;
    width: 48px;
    max-width: none;
    padding: 0;
    color: inherit;
    font-size: 1.05rem;
    overflow: visible;
    white-space: nowrap;
  }
  .z-task::before { display: none; }
  .z-task::after {
    content: '';
    position: absolute;
    left: 50%;
    bottom: 0;
    width: 60%;
    height: 2px;
    transform: translateX(-50%);
    background: var(--text-muted);
    transition: width var(--dur) var(--ease-decel), background var(--dur) var(--ease-decel);
  }
  .z-task.is-active { background: var(--surface-raise-2); }
  .z-task.is-active::after { width: 100%; background: var(--accent-light1); }
  [data-accent-chrome~="taskbar"] .z-task.is-active::after { background: #fff; }
  .z-task__icon  { flex: none; line-height: 1; }
  .z-task__label { display: none; }

  /* Live preview thumbnail on hover. */
  .z-task__peek {
    position: absolute;
    bottom: calc(var(--taskbar-h) + 6px);
    width: 240px;
    height: 160px;
    border-radius: 0;
    overflow: hidden;
    background: var(--acrylic-tint-deep);
    -webkit-backdrop-filter: var(--acrylic-filter);
    backdrop-filter: var(--acrylic-filter);
    border: 1px solid var(--border-strong);
    box-shadow: var(--shadow-4);
    opacity: 0;
    pointer-events: none;
    transform: translateY(4px);
    transition: opacity var(--dur) var(--ease-decel), transform var(--dur) var(--ease-decel);
    z-index: var(--z-dropdown);
  }
  .z-task__peek.is-on { opacity: 1; transform: none; }
  .z-task__peek header {
    all: unset;
    display: block;
    padding: var(--sp-2) var(--sp-3);
    font-size: var(--fs-xs);
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .z-task__peek-shot { position: relative; height: calc(100% - 30px); overflow: hidden; background: var(--surface-1); }
  .z-task__peek-shot iframe {
    width: 200%;
    height: 200%;
    border: 0;
    transform: scale(0.5);
    transform-origin: 0 0;
    pointer-events: none;
  }

  /* ── tray ──────────────────────────────────────────────────────────────────────────────── */
  .z-tray {
    flex: none;
    display: flex;
    align-items: stretch;
    gap: 0;
    padding: 0;
    height: 100%;
    font-size: var(--fs-xs);
    color: inherit;
  }
  .z-tray__btn { position: relative; width: 32px; }
  .z-tray__btn .z-icon { width: 16px; height: 16px; }
  .z-tray__net.is-offline { color: var(--danger); }
  .z-tray__net.is-offline .z-icon { animation: z-net-blink 1.6s ease-in-out infinite; }
  @keyframes z-net-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }
  .z-tray__vol.is-muted { color: var(--text-muted); }
  .z-tray__vol.is-muted .z-icon { opacity: 0.7; }
  .z-tray__ac { width: 40px; }
  .z-tray__badge {
    position: absolute;
    top: 6px;
    right: 6px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: var(--r-full);
    background: var(--accent);
    color: var(--accent-contrast);
    font-size: 10px;
    font-weight: var(--fw-semi);
    line-height: 16px;
    text-align: center;
  }
  .z-tray__badge[hidden] { display: none; }

  .z-tray__clock {
    display: grid;
    place-items: center;
    padding: 0 var(--sp-2);
    min-width: 72px;
    font-variant-numeric: tabular-nums;
    text-align: center;
    line-height: 1.15;
  }
  .z-tray__clock b { display: block; font-size: var(--fs-xs); font-weight: var(--fw-normal); color: inherit; }
  .z-tray__clock span { display: block; font-size: var(--fs-xs); color: inherit; }

  /* The show-desktop sliver at the very end of the bar. */
  .z-showdesk {
    flex: none;
    width: 7px;
    height: 100%;
    border: 0;
    border-left: 1px solid var(--border-strong);
    background: transparent;
    cursor: default;
    transition: background var(--dur-fast) var(--ease-decel);
  }
  .z-showdesk:hover { background: var(--surface-raise-3); }

  /* ── flyouts ───────────────────────────────────────────────────────────────────────────────
     Everything that pops out of the taskbar shares one recipe: acrylic, square, flush against
     the bar, sliding up 12px as it fades in. */
  .z-flyout,
  .z-tray-flyout,
  .z-cal-flyout,
  .z-startmenu {
    position: fixed;
    bottom: var(--taskbar-h);
    border-radius: 0;
    background: var(--acrylic-noise), var(--start-bg);
    -webkit-backdrop-filter: var(--acrylic-filter);
    backdrop-filter: var(--acrylic-filter);
    border: 1px solid var(--border-strong);
    border-bottom: 0;
    box-shadow: var(--shadow-4);
    color: var(--text-primary);
    opacity: 0;
    transform: translateY(12px);
    pointer-events: none;
    visibility: hidden;
    transition: opacity var(--dur) var(--ease-decel), transform var(--dur) var(--ease-decel),
                visibility 0s linear var(--dur);
  }
  .z-flyout.is-open,
  .z-tray-flyout.is-open,
  .z-cal-flyout.is-open,
  .z-startmenu.is-open {
    opacity: 1;
    transform: none;
    pointer-events: auto;
    visibility: visible;
    transition: opacity var(--dur) var(--ease-decel), transform var(--dur) var(--ease-decel), visibility 0s;
  }
  [data-accent-chrome~="taskbar"] .z-startmenu,
  [data-accent-chrome~="taskbar"] .z-tray-flyout,
  [data-accent-chrome~="taskbar"] .z-cal-flyout {
    background: var(--acrylic-noise), color-mix(in srgb, var(--accent-dark2) 88%, transparent);
    color: #fff;
  }

  .z-tray-flyout {
    right: 0;
    width: 300px;
    padding: var(--sp-3);
    z-index: var(--z-dropdown);
  }
  .z-tray-flyout__rpg {
    display: flex;
    justify-content: space-around;
    padding: var(--sp-2) var(--sp-3);
    margin-bottom: var(--sp-3);
    background: var(--surface-raise-1);
    border: 1px solid var(--border-subtle);
    border-radius: 0;
    font-size: var(--fs-sm);
  }
  .z-tray-flyout__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-2); }
  .z-tray-flyout__btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-1);
    padding: var(--sp-2) var(--sp-1);
    border: 1px solid transparent;
    border-radius: 0;
    background: var(--surface-raise-1);
    color: inherit;
    font: inherit;
    font-size: var(--fs-2xs);
    cursor: default;
    transition: background var(--dur-fast) var(--ease-decel), border-color var(--dur-fast) var(--ease-decel);
  }
  .z-tray-flyout__btn span { font-size: 1.25rem; line-height: 1; }
  .z-tray-flyout__btn:hover { background: var(--surface-raise-2); border-color: var(--border-strong); }
  .z-tray-flyout__btn[aria-pressed="true"] { background: var(--accent); color: var(--accent-contrast); }


  /* ══ action center ════════════════════════════════════════════════════════════════════════
     Slides in from the right edge, full height above the taskbar: notifications on top, the
     quick-action tiles along the bottom. */
  .z-ac {
    position: fixed;
    top: 0;
    right: 0;
    bottom: var(--taskbar-h);
    width: min(var(--ac-w), 100vw);
    display: flex;
    flex-direction: column;
    background: var(--acrylic-noise), var(--start-bg);
    -webkit-backdrop-filter: var(--acrylic-filter);
    backdrop-filter: var(--acrylic-filter);
    border-left: 1px solid var(--border-strong);
    box-shadow: var(--shadow-4);
    color: var(--text-primary);
    z-index: var(--z-actioncenter);
    transform: translateX(100%);
    visibility: hidden;
    transition: transform var(--dur-slow) var(--ease-decel), visibility 0s linear var(--dur-slow);
  }
  .z-ac.is-open {
    transform: none;
    visibility: visible;
    transition: transform var(--dur-slow) var(--ease-decel), visibility 0s;
  }
  [data-accent-chrome~="taskbar"] .z-ac {
    background: var(--acrylic-noise), color-mix(in srgb, var(--accent-dark2) 88%, transparent);
    color: #fff;
  }

  .z-ac__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-4) var(--sp-4) var(--sp-2);
  }
  .z-ac__title { font-size: var(--fs-md); font-weight: var(--fw-semi); }
  .z-ac__link {
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    font-size: var(--fs-xs);
    opacity: 0.8;
    cursor: default;
  }
  .z-ac__link:hover { opacity: 1; text-decoration: underline; }

  .z-ac__list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0 var(--sp-3) var(--sp-3);
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
  }
  .z-ac__empty { margin: auto; font-size: var(--fs-sm); color: var(--text-muted); text-align: center; }

  /* Do Not Disturb line under the head, and the per-app groups the list is stacked into. */
  .z-ac__dnd {
    margin: 0 var(--sp-4) var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    border-left: 3px solid var(--warning);
    background: var(--surface-raise-1);
    font-size: var(--fs-xs);
    color: var(--text-secondary);
  }
  .z-ac__dnd[hidden] { display: none; }

  /* The journal card above the list: one line into today's journal page. */
  .z-ac__note {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    margin: 0 var(--sp-3) var(--sp-2);
    padding: var(--sp-3);
    background: var(--surface-raise-1);
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--accent);
  }
  .z-ac__note-label {
    font-size: var(--fs-2xs);
    font-weight: var(--fw-semi);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--text-muted);
  }
  .z-ac__note-text {
    width: 100%;
    resize: vertical;
    min-height: 52px;
    font: inherit;
    font-size: var(--fs-sm);
    color: var(--text-primary);
    background: var(--surface-inset);
    border: 1px solid var(--border-default);
    padding: var(--sp-2);
  }
  .z-ac__note-text:focus { outline: none; border-color: var(--accent); }
  .z-ac__note-row { display: flex; align-items: center; justify-content: space-between; }
  .z-ac__group { display: flex; flex-direction: column; gap: var(--sp-1); }
  .z-ac__group + .z-ac__group { margin-top: var(--sp-2); }
  .z-ac__group-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--sp-1) var(--sp-1) 0;
    font-size: var(--fs-2xs);
    font-weight: var(--fw-semi);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--text-muted);
  }
  .z-ac__group-head .z-ac__link { text-transform: none; letter-spacing: 0; font-weight: var(--fw-normal); }
  .z-tray__badge.is-dnd { background: var(--surface-raise-3); color: var(--text-primary); min-width: 16px; }
  .z-tray__badge.is-dnd:empty::before { content: '🌙'; font-size: 9px; }
  :root[data-dnd="1"] .z-tray__ac .z-icon { opacity: 0.7; }
  .z-ac__list:not(:has(.z-ac__card)) .z-ac__empty { display: block; }
  .z-ac__list:has(.z-ac__card) .z-ac__empty { display: none; }

  /* One notification: an app line, a title, a body and a time, with a close on hover. */
  .z-ac__card {
    position: relative;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: var(--sp-1) var(--sp-3);
    padding: var(--sp-3) var(--sp-3) var(--sp-3);
    background: var(--surface-raise-1);
    border: 1px solid var(--border-subtle);
    border-left: 3px solid var(--tone, var(--accent));
    font-size: var(--fs-sm);
  }
  .z-ac__card:hover { background: var(--surface-raise-2); }
  .z-ac__card-icon { grid-row: 1 / span 2; font-size: 1.2rem; line-height: 1.2; }
  .z-ac__card-title { font-weight: var(--fw-semi); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .z-ac__card-body  { grid-column: 2; color: var(--text-secondary); font-size: var(--fs-xs); }
  .z-ac__card-time  { grid-column: 3; grid-row: 1; font-size: var(--fs-2xs); color: var(--text-muted); white-space: nowrap; }
  .z-ac__card-close {
    grid-column: 3;
    grid-row: 2;
    justify-self: end;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    opacity: 0;
    cursor: default;
  }
  .z-ac__card-close .z-icon { width: 14px; height: 14px; }
  .z-ac__card:hover .z-ac__card-close, .z-ac__card-close:focus-visible { opacity: 1; }
  .z-ac__card-close:hover { background: var(--surface-raise-3); }

  .z-ac__foot {
    padding: var(--sp-2) var(--sp-3) var(--sp-3);
    border-top: 1px solid var(--border-subtle);
  }
  .z-ac__foot > .z-ac__link { display: block; margin: 0 0 var(--sp-2) auto; width: max-content; }
  .z-ac__quick { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; }
  .z-ac__tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 68px;
    padding: var(--sp-1);
    border: 1px solid var(--border-strong);
    border-radius: 0;
    background: var(--surface-raise-1);
    color: inherit;
    font: inherit;
    font-size: var(--fs-2xs);
    cursor: default;
    transition: background var(--dur-fast) var(--ease-decel), border-color var(--dur-fast) var(--ease-decel);
  }
  .z-ac__tile > span { display: grid; place-items: center; line-height: 1; font-size: 1.1rem; }
  .z-ac__tile .z-icon { width: 20px; height: 20px; }
  .z-ac__tile small { font-size: inherit; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
  .z-ac__tile:hover { background: var(--surface-raise-2); border-color: var(--text-muted); }
  .z-ac__tile.is-on, .z-ac__tile[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
  :root:not([data-transparency="0"]) #z-qa-transparency { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }


  /* ══ tray calendar flyout ══════════════════════════════════════════════════════════════
     The clock's flyout: the time in large light figures, the month, and the day's agenda. */
  .z-cal-flyout {
    right: 0;
    width: min(var(--flyout-w), 100vw);
    max-height: min(680px, calc(100vh - var(--taskbar-h)));
    display: flex;
    flex-direction: column;
    overflow: hidden;
    z-index: var(--z-dropdown);
    user-select: none;
  }

  .z-cal-flyout__clock-pane {
    padding: var(--sp-5) var(--sp-5) var(--sp-4);
    border-bottom: 1px solid var(--border-subtle);
  }
  .z-cal-flyout__live-time {
    font-size: 2.75rem;
    font-weight: var(--fw-light);
    color: inherit;
    font-family: var(--font-display);
    letter-spacing: -0.01em;
    line-height: 1.05;
    font-variant-numeric: tabular-nums;
  }
  .z-cal-flyout__live-date {
    font-size: var(--fs-sm);
    color: var(--accent-light1);
    margin-top: 4px;
  }
  [data-accent-chrome~="taskbar"] .z-cal-flyout__live-date { color: #fff; opacity: 0.85; }

  .z-cal-flyout__divider { height: 1px; background: var(--border-subtle); }

  .z-cal-flyout__month-pane { padding: var(--sp-3) var(--sp-4); }
  .z-cal-flyout__month-nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--sp-2);
  }
  .z-cal-flyout__month-nav .btn { min-height: 28px; }
  .z-cal-flyout__month-label { font-size: var(--fs-sm); font-weight: var(--fw-semi); }
  .z-cal-flyout__weekdays {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    text-align: center;
    font-size: var(--fs-2xs);
    color: var(--text-muted);
    margin-bottom: 4px;
  }
  .z-cal-flyout__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
  .z-cal-flyout__cell {
    aspect-ratio: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-xs);
    color: inherit;
    border-radius: 0;
    cursor: default;
    position: relative;
    transition: background var(--dur-fast), color var(--dur-fast);
    background: transparent;
    border: 1px solid transparent;
    padding: 0;
  }
  .z-cal-flyout__cell:hover { border-color: var(--border-strong); }
  .z-cal-flyout__cell.is-other-month { opacity: 0.35; }
  .z-cal-flyout__cell.is-today { background: var(--accent); color: var(--accent-contrast); }
  .z-cal-flyout__cell.is-selected { border-color: var(--accent); }
  .z-cal-flyout__cell.is-selected.is-today { border-color: transparent; box-shadow: inset 0 0 0 1px #fff; }
  .z-cal-flyout__cell-dot {
    position: absolute;
    bottom: 3px;
    width: 4px;
    height: 4px;
    border-radius: var(--r-full);
    background: var(--accent-light1);
  }
  .z-cal-flyout__cell.is-today .z-cal-flyout__cell-dot { background: var(--accent-contrast); }

  .z-cal-flyout__agenda-pane {
    padding: var(--sp-3) var(--sp-4);
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 150px;
    max-height: 230px;
    overflow: hidden;
    border-top: 1px solid var(--border-subtle);
  }
  .z-cal-flyout__agenda-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: var(--sp-2);
  }
  .z-cal-flyout__agenda-title { font-size: var(--fs-xs); font-weight: var(--fw-semi); color: var(--text-secondary); }
  .z-cal-flyout__agenda-list {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .z-cal-flyout__item {
    padding: 6px 10px;
    background: var(--surface-raise-1);
    border: 1px solid transparent;
    border-radius: 0;
    font-size: var(--fs-xs);
    display: flex;
    align-items: center;
    gap: 8px;
    transition: background var(--dur-fast);
  }
  .z-cal-flyout__item:hover { background: var(--surface-raise-2); }
  .z-cal-flyout__item--block { border-left: 3px solid var(--accent); }
  .z-cal-flyout__item--task  { border-left: 3px solid var(--warning); }
  .z-cal-flyout__item--task.is-completed { opacity: 0.55; }
  .z-cal-flyout__item--task.is-completed .z-cal-flyout__item-name { text-decoration: line-through; }
  .z-cal-flyout__item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .z-cal-flyout__item-meta { font-size: var(--fs-2xs); color: var(--text-muted); white-space: nowrap; }
  .z-cal-flyout__empty { text-align: center; color: var(--text-muted); font-size: var(--fs-xs); padding: var(--sp-4) var(--sp-2); }

  .z-cal-flyout__foot {
    padding: var(--sp-2) var(--sp-3);
    border-top: 1px solid var(--border-subtle);
    display: flex;
    gap: var(--sp-2);
    justify-content: flex-end;
  }
  .z-cal-flyout__full-btn { flex: 1; justify-content: center; }


  /* ══ start menu ═══════════════════════════════════════════════════════════════════════════
     Three panes: the rail (48px, widens on the hamburger), the all-apps list, and the pinned
     tiles. Flush against the taskbar's bottom-left corner. */
  .z-startmenu {
    left: 0;
    width: min(calc(var(--start-w) + 264px), 100vw);
    height: min(var(--start-h), calc(100vh - var(--taskbar-h)));
    display: grid;
    grid-template-columns: var(--rail-w-collapsed) 248px 264px minmax(0, 1fr);
    overflow: hidden;
    z-index: var(--z-dropdown);
    transition: opacity var(--dur) var(--ease-decel), transform var(--dur) var(--ease-decel),
                visibility 0s linear var(--dur), grid-template-columns var(--dur) var(--ease-decel);
  }
  .z-startmenu.is-open {
    transition: opacity var(--dur) var(--ease-decel), transform var(--dur) var(--ease-decel), visibility 0s,
                grid-template-columns var(--dur) var(--ease-decel);
  }
  .z-startmenu.is-searching { grid-template-columns: var(--rail-w-collapsed) minmax(0, 1fr) 0 0; }

  /* ── rail ──────────────────────────────────────────────────────────────────────────────── */
  .z-startmenu__rail {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--surface-raise-1);
    overflow: visible;
    z-index: 2;
  }
  .z-rail__spacer { flex: 1; }
  .z-rail__btn {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    width: var(--rail-w-collapsed);
    height: 48px;
    padding: 0 0 0 15px;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: var(--fs-sm);
    white-space: nowrap;
    cursor: default;
    overflow: hidden;
    transition: background var(--dur-fast) var(--ease-decel), width var(--dur) var(--ease-decel);
  }
  .z-rail__btn .z-icon { width: 18px; height: 18px; flex: none; }
  .z-rail__btn:hover { background: var(--surface-raise-2); }
  .z-rail__btn:active { background: var(--surface-raise-3); }
  .z-rail__label { opacity: 0; transition: opacity var(--dur-fast) var(--ease-decel); }
  .z-startmenu.is-wide .z-rail__btn { width: 240px; }
  .z-startmenu.is-wide .z-rail__label { opacity: 1; }
  .z-startmenu.is-wide .z-startmenu__rail {
    position: absolute;
    inset-block: 0;
    left: 0;
    background: var(--acrylic-tint-deep);
    box-shadow: var(--shadow-3);
  }
  .z-rail__avatar {
    width: 28px;
    height: 28px;
    margin-left: -5px;
    border-radius: var(--r-full);
    flex: none;
    display: grid;
    place-items: center;
    background: var(--accent) center / cover no-repeat;
    color: var(--accent-contrast);
    font-size: var(--fs-xs);
    font-weight: var(--fw-semi);
    overflow: hidden;
  }

  .z-power-menu {
    position: absolute;
    left: var(--rail-w-collapsed);
    bottom: 0;
    min-width: 160px;
    display: flex;
    flex-direction: column;
    padding: var(--sp-1) 0;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    box-shadow: var(--shadow-3);
    z-index: 3;
  }
  .z-startmenu.is-wide .z-power-menu { left: 240px; }
  .z-power-menu[hidden] { display: none; }
  .z-power-menu__item {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-4);
    border: 0;
    background: none;
    color: var(--text-primary);
    font: inherit;
    font-size: var(--fs-sm);
    text-align: left;
    cursor: default;
  }
  .z-power-menu__item .z-icon { width: 16px; height: 16px; }
  .z-power-menu__item:hover { background: var(--surface-raise-2); }

  /* ── all apps ──────────────────────────────────────────────────────────────────────────── */
  .z-startmenu__apps { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
  .z-startmenu__search {
    position: relative;
    display: flex;
    align-items: center;
    padding: var(--sp-3) var(--sp-3) var(--sp-2);
  }
  .z-startmenu__search .z-icon {
    position: absolute;
    left: calc(var(--sp-3) + 10px);
    width: 16px;
    height: 16px;
    color: var(--text-muted);
    pointer-events: none;
  }
  .z-startmenu__search .form-control { padding-left: 34px; }

  .z-startmenu__list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0 var(--sp-2) var(--sp-3);
  }
  .z-startmenu__letter {
    padding: var(--sp-3) var(--sp-2) var(--sp-1);
    font-size: var(--fs-md);
    font-weight: var(--fw-semilight);
    color: var(--accent-light1);
  }
  [data-accent-chrome~="taskbar"] .z-startmenu__letter { color: #fff; }
  .z-startmenu__group {
    padding: var(--sp-3) var(--sp-2) var(--sp-2);
    font-size: var(--fs-sm);
    font-weight: var(--fw-semi);
    color: inherit;
    letter-spacing: 0;
    text-transform: none;
  }

  /* What the Start menu found in your data, files and the App Store, below the app list. */
  .z-startmenu__deep { margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px solid var(--border-subtle); }
  .z-startmenu__deep[hidden] { display: none; }
  .z-startmenu__deep .palette-group { padding-left: var(--sp-2); }
  .z-startmenu__deep .palette-item { border-radius: 0; }

  .z-app {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    width: 100%;
    height: 36px;
    padding: 0 var(--sp-2);
    border: 1px solid transparent;
    border-radius: 0;
    background: none;
    color: inherit;
    font: inherit;
    font-size: var(--fs-sm);
    text-align: left;
    cursor: default;
    transition: background var(--dur-fast) var(--ease-decel), border-color var(--dur-fast) var(--ease-decel);
  }
  .z-app:hover, .z-app.is-sel { background: var(--surface-raise-2); border-color: var(--border-strong); transform: none; color: inherit; }
  .z-app:active { background: var(--surface-raise-3); }
  .z-app__icon { flex: none; width: 24px; height: 24px; font-size: 0.85rem; }
  .z-app__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* ── tiles ─────────────────────────────────────────────────────────────────────────────── */
  .z-startmenu__tiles {
    min-width: 0;
    overflow-y: auto;
    padding: var(--sp-3) var(--sp-4) var(--sp-4) var(--sp-2);
  }
  .z-startmenu.is-searching .z-startmenu__tiles { visibility: hidden; padding: 0; }

  /* ── Today ────────────────────────────────────────────────────────────────────────────────
     The pane between the app list and the tiles: rituals, focus and due tasks, with the
     quick-add forms. renderStartToday() in os.js fills it from the ritual-start-today island
     on first paint and from get_start_today while the menu is open. */
  .z-startmenu__today {
    min-width: 0;
    overflow-y: auto;
    padding: var(--sp-3) var(--sp-3) var(--sp-4);
    border-left: 1px solid var(--border-subtle);
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    font-size: var(--fs-xs);
  }
  .z-startmenu__today[hidden] { display: none; }
  .z-startmenu.is-searching .z-startmenu__today { visibility: hidden; padding: 0; }
  .z-today__greet { font-size: var(--fs-lg); font-weight: var(--fw-semilight); line-height: 1.2; }
  .z-today__date { color: var(--text-muted); }
  .z-today__motto { color: var(--accent-text); font-weight: var(--fw-semi); margin-top: 2px; }
  .z-today__sec { display: flex; flex-direction: column; gap: var(--sp-2); }
  .z-today__title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: var(--fs-2xs);
    font-weight: var(--fw-semi);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    color: var(--text-muted);
  }
  .z-today__title .z-ac__link { text-transform: none; letter-spacing: 0; font-weight: var(--fw-normal); }
  .z-today__list { display: flex; flex-direction: column; gap: 2px; }
  .z-today__list .z-list__item {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-1) var(--sp-2);
    background: var(--surface-raise-1);
    border-left: 2px solid var(--tone, transparent);
    transition: opacity var(--dur) var(--ease-decel);
  }
  .z-today__list .z-list__item.is-danger  { --tone: var(--danger); }
  .z-today__list .z-list__item.is-warning { --tone: var(--warning); }
  .z-today__list .z-list__item.is-done { opacity: 0; }
  .z-today__list .z-list__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .z-today__list .z-list__meta { color: var(--text-muted); font-size: var(--fs-2xs); white-space: nowrap; }
  .z-today__empty { color: var(--text-muted); padding: var(--sp-1) var(--sp-2); }
  .z-qa { display: flex; gap: var(--sp-1); }
  .z-qa .form-control { flex: 1; min-width: 0; font-size: var(--fs-xs); padding: var(--sp-1) var(--sp-2); }
  .z-qa .z-qa__amount { flex: 0 0 68px; }
  .z-qa select.form-control { flex: 0 1 38%; }
  .z-startmenu__tiles-empty { padding: var(--sp-4) var(--sp-2); font-size: var(--fs-xs); color: var(--text-muted); }
  .z-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, 96px);
    gap: 4px;
    margin-bottom: var(--sp-3);
  }
  .z-tile-app {
    position: relative;
    width: 96px;
    height: 96px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: var(--sp-2);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 0;
    background: var(--hue, var(--accent));
    color: #fff;
    font: inherit;
    cursor: default;
    overflow: hidden;
    transition: filter var(--dur-fast) var(--ease-decel), border-color var(--dur-fast) var(--ease-decel);
  }
  .z-tile-app:hover { filter: brightness(1.1); border-color: rgba(255, 255, 255, 0.5); }
  .z-tile-app:active { filter: brightness(0.92); }
  .z-tile-app__icon { font-size: 2rem; line-height: 1; }

  /* Live faces. A pinned tile with figures behind its icon cycles through them the way a
     Windows 10 live tile does: face 0 is the icon and label, the rest come from
     ritual_tile_faces(); one is visible at a time and the incoming one slides up. */
  .z-tile-app__face {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: var(--sp-2);
    opacity: 0;
    pointer-events: none;
  }
  .z-tile-app__face.is-active { opacity: 1; animation: z-tile-flip var(--dur-slower) var(--ease-decel); }
  .z-tile-app__headline { font-size: var(--fs-xl); font-weight: var(--fw-semi); line-height: 1.1; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35); }
  .z-tile-app__sub { font-size: var(--fs-2xs); opacity: 0.85; margin-top: 2px; }
  @keyframes z-tile-flip { from { transform: translateY(60%); opacity: 0; } to { transform: none; opacity: 1; } }
  @media (prefers-reduced-motion: reduce) { .z-tile-app__face.is-active { animation: none; } }
  .z-tile-app__label {
    position: absolute;
    left: 8px;
    right: 8px;
    bottom: 6px;
    font-size: var(--fs-2xs);
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  }


  /* ══ window switcher ══════════════════════════════════════════════════════════════════════
     Ctrl+Alt+Tab (the Windows key and plain Alt+Tab belong to the host OS). A centred acrylic
     panel of thumbnails; the selected one carries a 2px border in the text colour. */
  .z-flip {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal);
    display: none;
    place-items: center;
    background: rgba(0, 0, 0, 0.35);
  }
  .z-flip.is-open { display: grid; }

  .z-flip__stack {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--sp-3);
    max-width: min(1100px, 90vw);
    max-height: 70vh;
    overflow: auto;
    padding: var(--sp-4);
    background: var(--acrylic-noise), var(--start-bg);
    -webkit-backdrop-filter: var(--acrylic-filter);
    backdrop-filter: var(--acrylic-filter);
    border: 1px solid var(--border-strong);
    box-shadow: var(--shadow-4);
  }

  .z-flip__card {
    width: 240px;
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    padding: var(--sp-2);
    border: 2px solid transparent;
    background: transparent;
    cursor: default;
    transition: background var(--dur-fast) var(--ease-decel), border-color var(--dur-fast) var(--ease-decel);
  }
  .z-flip__card:hover { background: var(--surface-raise-2); }
  .z-flip__card.is-front { border-color: var(--text-primary); background: var(--surface-raise-2); }
  .z-flip__card header {
    all: unset;
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: var(--fs-xs);
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .z-flip__name { overflow: hidden; text-overflow: ellipsis; }
  .z-flip__shot {
    position: relative;
    height: 140px;
    overflow: hidden;
    background: var(--surface-1);
    border: 1px solid var(--border-subtle);
  }
  .z-flip__shot iframe {
    width: 200%;
    height: 200%;
    border: 0;
    transform: scale(0.5);
    transform-origin: 0 0;
    pointer-events: none;
  }
  .z-flip__hint {
    position: fixed;
    bottom: calc(var(--taskbar-h) + 24px);
    left: 0; right: 0;
    text-align: center;
    color: var(--text-muted);
    font-size: var(--fs-xs);
  }


  /* ══ small screens ════════════════════════════════════════════════════════════════════════
     On phone viewports windows go full-bleed, the search box collapses to its icon and the
     Start menu takes the whole width. */
  @media (max-width: 1099px) {
    .z-startmenu { width: min(var(--start-w), 100vw); grid-template-columns: var(--rail-w-collapsed) 248px minmax(0, 1fr); }
    .z-startmenu__today { display: none; }
  }
  @media (max-width: 999px) {
    .z-tb-search { width: 48px; padding: 0; justify-content: center; }
    .z-tb-search__label { display: none; }
    .z-workspaces-pill .z-ws-pill__name { display: none; }
  }
  @media (max-width: 767px) {
    .z-startmenu { width: 100vw; grid-template-columns: var(--rail-w-collapsed) minmax(0, 1fr); }
    .z-startmenu__tiles { display: none; }
    .z-cal-flyout, .z-tray-flyout { width: 100vw; }
  }
  @media (max-width: 599px) {
    .z-win {
      inset: 0 !important;
      width: auto !important;
      height: auto !important;
      border: none;
    }
    .z-win__resize { display: none; }
    .z-task__peek { display: none; }
    .z-workspaces-pill { display: none; }
  }

  /* The identity sheet gives every direct child of .app-container a rise-in animation.
     On the desktop the chrome opts out and the gadgets animate instead. */
  body.is-desktop .app-container > * { animation: none; }
  .z-gadgets > * { animation: z-rise var(--dur-slow) var(--ease-decel) backwards; }
  .z-gadgets > *:nth-child(2) { animation-delay: 30ms; }
  .z-gadgets > *:nth-child(3) { animation-delay: 60ms; }
  .z-gadgets > *:nth-child(4) { animation-delay: 90ms; }
  .z-gadgets > *:nth-child(n+5) { animation-delay: 120ms; }

  @media (prefers-reduced-motion: reduce) {
    .z-gadgets > * { animation: none; }
    .z-win, .z-win.is-min, .z-win.is-closing { animation: none; transition: none; }
  }


  /* ══ desktop gadgets ══════════════════════════════════════════════════════════════════════ */
  .z-gadget { display: flex; flex-direction: column; min-width: 0; }
  /* Width is the size button's job now -- see the footprint classes at the end of this file.
     These two are kept as aliases of the old hardcoded gadgets, and --tall controls height
     only, because when it also set grid-column the two rules fought over the same property. */
  .z-gadget--wide { grid-column: 1 / -1; }
  .z-gadget--tall { grid-row: span 2; }

  button.z-stat {
    font: inherit;
    text-align: left;
    cursor: pointer;
    align-items: stretch;
  }

  .z-hero { display: flex; align-items: center; gap: var(--sp-6); flex-wrap: wrap; }
  .z-hero__who { flex: 1; min-width: 220px; }
  .z-hero__who h2 { font-size: var(--fs-2xl); }
  .z-hero__summary { color: var(--text-secondary); margin-top: var(--sp-1); }
  .z-hero__xp { flex: 1; min-width: 240px; display: flex; align-items: center; gap: var(--sp-4); }
  .z-hero__xp .z-bar { flex: 1; }
  .z-hero__coins {
    font-family: var(--font-display);
    font-size: var(--fs-lg);
    color: var(--warning-text);
    white-space: nowrap;
    text-shadow: 0 0 14px color-mix(in srgb, var(--warning) 45%, transparent);
  }

  .z-launcher {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
    gap: var(--sp-2);
  }

  .z-launch {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-2);
    border: 1px solid transparent;
    border-radius: var(--r-md);
    background: none;
    color: var(--text-secondary);
    font-size: var(--fs-xs);
    text-align: center;
    cursor: pointer;
    transition: background var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out),
                transform var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
  }
  .z-launch:hover {
    background: linear-gradient(180deg, var(--accent-soft), transparent);
    border-color: var(--accent-line);
    color: var(--text-primary);
    transform: translateY(-3px);
    box-shadow: var(--glow-soft);
  }
  .z-launch__icon {
    font-size: 1.6rem;
    line-height: 1;
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.45));
  }
  .z-launch__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }

  /* An agenda row leads with a time, which does not fit the 1.6rem icon slot. */
  .z-list__lead--time {
    width: auto;
    min-width: 3.4rem;
    text-align: left;
    font-size: var(--fs-xs);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
  }

  /* A finished Do Now row fades out rather than vanishing. */
  .z-list__item.is-done {
    opacity: 0;
    transform: translateX(24px);
    transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
  }

  /* == widgets ==============================================================================
     The desktop surface is now a grid of widgets from app/lib/widgets.php rather than six
     hand-written gadgets. Everything below styles the frame they share: a header that names
     the module it belongs to, a body the renderer fills, and the controls that appear only
     while the desktop is being rearranged.

     A widget carries .card, so aero.css gives it the whole glass treatment by selector list
     and none of it is repeated here. */

  .z-widget {
    position: relative;
    gap: var(--sp-3);
    /* The module's own hue, as a hairline along the top edge. Enough to tell two widgets
       apart at a glance without turning the desktop into a colour chart. */
    border-top: 1px solid color-mix(in srgb, var(--hue, var(--accent)) 42%, var(--glass-edge));
    transition: box-shadow var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
  }
  .z-widget:hover { box-shadow: var(--shadow-3), var(--glow-soft); }

  .z-widget__head {
    gap: var(--sp-2);
    margin-bottom: 0;
    min-height: 1.9rem;
  }

  /* The title is the only thing in a widget that opens the module. Putting data-open on the
     frame would launch it on every click inside, including the Done buttons. */
  .z-widget__title {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    min-width: 0;
    padding: 0;
    border: 0;
    background: none;
    font-family: var(--font-display);
    font-size: var(--fs-md);
    font-weight: var(--fw-semi);
    color: var(--text-primary);
    text-align: left;
  }
  button.z-widget__title { cursor: pointer; }
  button.z-widget__title:hover { color: var(--accent-text); }
  .z-widget__title > span:last-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* The same tinted plate the launcher tiles and window titlebars use. */
  .z-widget__icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: var(--r-sm);
    font-size: var(--fs-sm);
    line-height: 1;
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--hue, var(--accent)) 26%, transparent),
      color-mix(in srgb, var(--hue, var(--accent)) 8%, transparent));
    border: 1px solid color-mix(in srgb, var(--hue, var(--accent)) 34%, transparent);
  }

  .z-widget__body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    flex: 1;
  }
  /* A tall widget has a row height to fill, so its list scrolls inside the card rather than
     stretching the grid. min-height: 0 is what lets a flex child shrink far enough for
     overflow to engage -- and it is scoped here deliberately: applied to every widget it let
     short cards collapse under their own contents instead of sizing to them. */
  .z-gadget--tall .z-widget__body { min-height: 0; }
  .z-gadget--tall .z-widget__body > .z-list { overflow-y: auto; }

  .z-widget__stat { border: 0; padding: 0; background: none; }
  .z-widget__foot { align-self: flex-start; margin-top: auto; }

  /* == edit mode ============================================================================
     Never display:none on the controls -- that reflows every header the moment the desktop
     enters edit mode, which reads as the page breaking rather than as a mode changing. */

  .z-widget__edit {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-1);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) var(--ease-out);
  }
  .z-desktop.is-editing .z-widget__edit { opacity: 1; pointer-events: auto; }

  .z-widget__grip {
    padding: 0 var(--sp-1);
    border: 0;
    background: none;
    color: var(--text-muted);
    font-size: var(--fs-sm);
    letter-spacing: -0.18em;
    line-height: 1;
    cursor: grab;
    touch-action: none;      /* or the browser scrolls the grid instead of dragging the card */
  }
  .z-widget__grip:hover { color: var(--text-primary); }
  .z-widget__grip:active { cursor: grabbing; }

  .z-desktop.is-editing .z-widget {
    outline: 1px dashed var(--accent-line);
    outline-offset: -2px;
    cursor: default;
  }
  /* The title stops being a launcher while you are rearranging -- os.js suppresses the click,
     and the cursor should say so before the click happens. */
  .z-desktop.is-editing .z-widget__title,
  .z-desktop.is-editing .z-launch { cursor: default; }

  @keyframes z-jiggle {
    0%, 100% { transform: rotate(-0.22deg); }
    50%      { transform: rotate(0.22deg); }
  }
  .z-desktop.is-editing .z-widget:not(.is-dragging-gadget) {
    animation: z-jiggle 2.6s var(--ease-in-out) infinite;
  }

  /* aero.css gives every gadget a z-rise entrance with fill-mode: both, and a filled animation
     value beats an inline transform -- so the drag would set style.transform and nothing would
     move. Same class of collision as the one recorded further up this file. */
  .z-desktop.is-editing .z-gadgets > *,
  .z-gadgets > *.is-dragging-gadget { animation: none; }

  .z-gadget.is-dragging-gadget {
    position: fixed;
    z-index: var(--z-dropdown);
    opacity: 0.94;
    cursor: grabbing;
    box-shadow: var(--shadow-4), var(--glow-accent);
    backdrop-filter: var(--glass-filter);
    pointer-events: none;
  }
  /* The window manager already sets this while a window is dragged; a gadget drag needs it for
     the same reason -- the pointer must not be captured by anything it passes over. */
  .z-desktop.is-dragging .z-widget__body { pointer-events: none; }

  .z-widget-slot {
    border: 1px dashed var(--accent-line);
    border-radius: var(--r-lg);
    background: var(--accent-softer);
    min-height: 80px;
  }

  .z-widget--skel .z-widget__body { gap: var(--sp-2); padding-block: var(--sp-2); }

  /* A link tile: a big tinted plate and a sentence. Settings, Profile, the Admin console and
     the sound board have no state that could say "do this today", so their widgets say so by
     having nothing to say -- rather than inventing a number to fill the space. */
  .z-widget__link {
    display: flex;
    flex: 1;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    padding: var(--sp-4) var(--sp-2);
    border: 1px dashed var(--border-subtle);
    border-radius: var(--r-md);
    background: none;
    color: var(--text-secondary);
    font: inherit;
    text-align: center;
    cursor: pointer;
    transition: background var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
  }
  .z-widget__link:hover {
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--hue, var(--accent)) 12%, transparent), transparent);
    border-color: color-mix(in srgb, var(--hue, var(--accent)) 45%, transparent);
    color: var(--text-primary);
  }
  .z-widget__link-icon {
    font-size: 2rem;
    line-height: 1;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.4));
  }

  /* == launcher =============================================================================
     Recently used first, pinned ones above that. A button cannot contain a button, so the pin
     is a sibling laid over the tile. */

  .z-launch-wrap { position: relative; }
  .z-launch-wrap .z-launch { width: 100%; }

  .z-launch__pin {
    position: absolute;
    top: var(--sp-1);
    right: var(--sp-1);
    padding: 0 3px;
    border: 0;
    border-radius: var(--r-sm);
    background: none;
    color: var(--text-faint);
    font-size: var(--fs-2xs);
    line-height: 1.4;
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
  }
  .z-launch-wrap:hover .z-launch__pin,
  .z-launch__pin:focus-visible { opacity: 1; }
  .z-launch__pin:hover { color: var(--warning-text); }
  /* A pinned tile keeps its star visible: the state has to be readable without hovering every
     tile in turn to find out which ones are pinned. */
  .z-launch-wrap.is-pinned .z-launch__pin { opacity: 1; color: var(--warning-text); }
  .z-launch-wrap.is-pinned .z-launch { border-color: var(--warning-line); }

  .z-launcher__all { margin-top: var(--sp-3); }

  /* == the customise panel ================================================================== */

  .z-panel {
    position: absolute;
    inset-block: 0;
    right: 0;
    width: min(380px, 92vw);
    z-index: var(--z-drawer);
    display: flex;
    flex-direction: column;
    background: var(--glass-2);
    backdrop-filter: var(--glass-filter);
    border-left: 1px solid var(--glass-edge);
    box-shadow: var(--shadow-4);
    transform: translateX(101%);
    visibility: hidden;
    transition: transform var(--dur-slow) var(--ease-spring),
                visibility 0s linear var(--dur-slow);
  }
  /* visibility, not just transform: a panel that is only translated off-screen still takes
     focus from the keyboard, which is how you end up tabbing into an invisible dialog. */
  .z-panel.is-open {
    transform: none;
    visibility: visible;
    transition: transform var(--dur-slow) var(--ease-spring), visibility 0s;
  }

  .z-panel__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-2);
    padding: var(--sp-4) var(--sp-4) var(--sp-2);
    border-bottom: 1px solid var(--border-subtle);
  }
  .z-panel__intro {
    padding: var(--sp-3) var(--sp-4) 0;
    margin: 0;
    color: var(--text-secondary);
    font-size: var(--fs-xs);
  }
  .z-panel__intro kbd {
    padding: 0 4px;
    border: 1px solid var(--border-default);
    border-radius: var(--r-xs);
    background: var(--surface-inset);
    font-family: var(--font-mono);
    font-size: var(--fs-2xs);
  }
  .z-panel__body { flex: 1; overflow-y: auto; padding: var(--sp-4); }
  .z-panel__foot {
    display: flex;
    justify-content: space-between;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--sp-4);
    border-top: 1px solid var(--border-subtle);
  }
  .z-panel__note { margin: var(--sp-2) 0 0; }

  .z-panel__group { margin-bottom: var(--sp-5); }
  .z-panel__group > .z-section__title { margin-bottom: var(--sp-2); }

  .z-gallery__item {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    cursor: pointer;
  }
  .z-gallery__body { flex: 1; min-width: 0; display: block; }
  .z-gallery__title {
    display: block;
    font-weight: var(--fw-medium);
    color: var(--text-primary);
  }

  /* == announcements ========================================================================
     Dragging and the arrow keys both reorder something the eye can see and a screen reader
     cannot. This is where os.js says what moved where. */

  .z-live {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* == footprints ===========================================================================
     Quantised to the auto-fill grid rather than freely resizable: a pixel width would fight
     the column count and land differently at every viewport. --wide and --tall are kept as
     aliases so anything still emitting them keeps working. */

  .z-gadget--s  { grid-column: span 1; }
  .z-gadget--m  { grid-column: span 2; }
  .z-gadget--l  { grid-column: span 3; }
  .z-gadget--xl { grid-column: 1 / -1; }

  /* Below roughly four columns a three-wide widget is the whole row anyway, and below two a
     two-wide one is. Clamping here rather than letting the span overflow is what stops the
     grid inventing implicit columns and pushing the desktop sideways. */
  @media (max-width: 1279px) {
    .z-gadget--l { grid-column: span 2; }
  }
  @media (max-width: 979px) {
    .z-gadget--m,
    .z-gadget--l { grid-column: 1 / -1; }
    .z-gadget--tall { grid-row: auto; }
    .z-panel { width: 100%; }
  }

  /* == Virtual Desktops & Task View ========================================================= */

  /* Windows on other desktops are simply not shown. */
  .z-win.is-ws-hidden, .z-task.is-ws-hidden { display: none !important; }

  /* Desktop switch: the windows slide in from the side the desktop came from. */
  .z-desktop.is-ws-sliding-left .z-win:not(.is-ws-hidden)  { animation: z-ws-slide-in-left var(--dur-slow) var(--ease-decel) backwards; }
  .z-desktop.is-ws-sliding-right .z-win:not(.is-ws-hidden) { animation: z-ws-slide-in-right var(--dur-slow) var(--ease-decel) backwards; }
  @keyframes z-ws-slide-in-left  { from { transform: translateX(60px); opacity: 0.2; } to { transform: none; opacity: 1; } }
  @keyframes z-ws-slide-in-right { from { transform: translateX(-60px); opacity: 0.2; } to { transform: none; opacity: 1; } }

  /* The on-screen name of the desktop just switched to. */
  .z-workspace-hud {
    position: fixed;
    top: 20%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0.95);
    padding: var(--sp-3) var(--sp-6);
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    background: var(--acrylic-tint-deep);
    -webkit-backdrop-filter: var(--acrylic-filter);
    backdrop-filter: var(--acrylic-filter);
    border: 1px solid var(--border-strong);
    box-shadow: var(--shadow-4);
    color: var(--text-primary);
    font-size: var(--fs-xl);
    font-weight: var(--fw-semilight);
    font-family: var(--font-display);
    pointer-events: none;
    z-index: 9999;
    opacity: 0;
    transition: opacity var(--dur) var(--ease-decel), transform var(--dur) var(--ease-decel);
  }
  .z-workspace-hud.is-active { opacity: 1; transform: translate(-50%, -50%); }
  .z-ws-hud__icon { font-size: 1.3rem; }

  /* ── Task View ─────────────────────────────────────────────────────────────────────────────
     The desktops in a strip along the top, the open windows as thumbnails below. */
  .z-taskview-overlay {
    position: fixed;
    inset: 0;
    bottom: var(--taskbar-h);
    z-index: 9000;
    background: rgba(0, 0, 0, 0.55);
    -webkit-backdrop-filter: var(--acrylic-filter);
    backdrop-filter: var(--acrylic-filter);
    display: flex;
    flex-direction: column;
    padding: var(--sp-6) var(--sp-8);
    gap: var(--sp-6);
    color: var(--text-primary);
    opacity: 0;
    transition: opacity var(--dur) var(--ease-decel);
    overflow-y: auto;
  }
  .z-taskview-overlay.is-open { opacity: 1; }
  [data-theme="light"] .z-taskview-overlay { background: rgba(243, 243, 243, 0.7); }

  .z-taskview-header { display: flex; flex-direction: column; gap: var(--sp-4); }
  .z-taskview-title {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    font-size: var(--fs-md);
    font-weight: var(--fw-semi);
  }
  .z-taskview-hint { font-size: var(--fs-xs); color: var(--text-muted); font-weight: var(--fw-normal); }
  .z-taskview-hint kbd {
    padding: 1px 5px;
    border: 1px solid var(--border-strong);
    background: var(--surface-raise-1);
    font-family: inherit;
    font-size: inherit;
  }

  .z-taskview-workspaces-bar { display: flex; align-items: stretch; gap: var(--sp-3); overflow-x: auto; padding-bottom: var(--sp-1); }
  .z-taskview-workspaces { display: flex; align-items: stretch; gap: var(--sp-3); }

  .z-ws-card {
    width: 176px;
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding: var(--sp-2);
    border: 2px solid transparent;
    background: transparent;
    cursor: default;
    user-select: none;
    transition: background var(--dur-fast) var(--ease-decel), border-color var(--dur-fast) var(--ease-decel);
  }
  .z-ws-card:hover { background: var(--surface-raise-2); }
  .z-ws-card.is-active { border-color: var(--text-primary); }
  .z-ws-card.is-drag-over { background: var(--accent-soft); border-color: var(--accent); }
  .z-ws-card__preview {
    height: 96px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 6px;
    background: var(--wallpaper) center / cover no-repeat, var(--theme-bg-start);
    border: 1px solid var(--border-strong);
    overflow: hidden;
  }
  .z-ws-card__win-mini {
    width: 34px;
    height: 28px;
    display: grid;
    place-items: center;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    font-size: 0.85rem;
  }
  .z-ws-card__empty-hint { font-size: var(--fs-2xs); color: rgba(255, 255, 255, 0.7); }
  .z-ws-card__meta { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; font-size: var(--fs-xs); }
  .z-ws-card__icon { font-size: 0.9rem; }
  .z-ws-card__name {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    border: 1px solid transparent;
    padding: 1px 3px;
  }
  .z-ws-card__name[contenteditable="true"] { background: var(--surface-1); border-color: var(--accent); outline: none; }
  .z-ws-card__close {
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-muted);
    font-size: 0.8rem;
    cursor: default;
    opacity: 0;
    transition: opacity var(--dur-fast) var(--ease-decel);
  }
  .z-ws-card:hover .z-ws-card__close { opacity: 1; }
  .z-ws-card__close:hover { background: var(--close-red); color: #fff; }

  .z-taskview-add-ws {
    flex: none;
    width: 176px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    padding: var(--sp-2);
    border: 2px solid transparent;
    background: transparent;
    color: var(--text-secondary);
    font: inherit;
    font-size: var(--fs-xs);
    cursor: default;
    transition: background var(--dur-fast) var(--ease-decel);
  }
  .z-taskview-add-ws:hover { background: var(--surface-raise-2); color: var(--text-primary); }
  .z-taskview-add-ws__plus {
    display: grid;
    place-items: center;
    width: 100%;
    height: 96px;
    border: 1px dashed var(--border-strong);
    background: var(--surface-raise-1);
    font-size: 2rem;
    font-weight: var(--fw-light);
  }

  .z-taskview-body { flex: 1; display: flex; flex-direction: column; gap: var(--sp-3); }
  .z-taskview-section-label { font-size: var(--fs-sm); color: var(--text-secondary); }

  .z-taskview-win-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: var(--sp-5) var(--sp-4);
    align-content: start;
  }
  .z-taskview-win-card {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    padding: var(--sp-2);
    border: 2px solid transparent;
    background: transparent;
    cursor: default;
    user-select: none;
    transition: background var(--dur-fast) var(--ease-decel), border-color var(--dur-fast) var(--ease-decel);
  }
  .z-taskview-win-card:hover { background: var(--surface-raise-2); border-color: var(--border-strong); }
  .z-taskview-win-card.is-dragging { opacity: 0.5; }
  .z-taskview-win-card__head {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    min-height: 26px;
    font-size: var(--fs-xs);
  }
  .z-taskview-win-card__icon { font-size: 0.9rem; line-height: 1; }
  .z-taskview-win-card__title { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .z-taskview-win-card__close {
    width: 26px;
    height: 26px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-muted);
    font-size: 0.85rem;
    cursor: default;
    opacity: 0;
    transition: opacity var(--dur-fast) var(--ease-decel);
  }
  .z-taskview-win-card:hover .z-taskview-win-card__close { opacity: 1; }
  .z-taskview-win-card__close:hover { background: var(--close-red); color: #fff; }
  .z-taskview-win-card__thumb {
    position: relative;
    height: 170px;
    overflow: hidden;
    background: var(--surface-1);
    border: 1px solid var(--border-strong);
  }
  .z-taskview-win-card__thumb iframe {
    width: 200%;
    height: 200%;
    border: 0;
    transform: scale(0.5);
    transform-origin: 0 0;
    pointer-events: none;
  }
  .z-taskview-win-card__actions {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    min-height: 26px;
    opacity: 0;
    transition: opacity var(--dur-fast) var(--ease-decel);
  }
  .z-taskview-win-card:hover .z-taskview-win-card__actions { opacity: 1; }
  .z-taskview-pin-btn.is-pinned { color: var(--accent-light1); }
  .z-taskview-move-sel { width: auto; min-height: 24px; padding: 0 var(--sp-2); font-size: var(--fs-2xs); }

  @media (prefers-reduced-motion: reduce) {
    .z-desktop.is-ws-sliding-left .z-win,
    .z-desktop.is-ws-sliding-right .z-win,
    .z-taskview-overlay,
    .z-workspace-hud { animation: none !important; transition: none !important; }
  }

  /* ══ boot ═════════════════════════════════════════════════════════════════════════════════
     Black, the mark, a ring of five dots chasing each other, a line of text. Then "Welcome",
     then the desktop fades up through it. */
  .z-boot {
    position: fixed;
    inset: 0;
    z-index: var(--z-lock);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-6);
    background: #000;
    color: #fff;
    user-select: none;
    transition: opacity var(--dur-slower) var(--ease-accel);
  }
  .z-boot__logo { display: grid; place-items: center; margin-bottom: var(--sp-8); }
  .z-boot__logo .ritual-mark { width: 88px; height: 88px; }

  .z-boot__spinner {
    position: relative;
    width: 44px;
    height: 44px;
  }
  .z-boot__spinner span {
    position: absolute;
    inset: 0;
    animation: z-boot-orbit 2.2s cubic-bezier(0.4, 0.15, 0.6, 0.85) infinite;
  }
  .z-boot__spinner span::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    width: 6px;
    height: 6px;
    margin-left: -3px;
    border-radius: 50%;
    background: #fff;
  }
  .z-boot__spinner span:nth-child(2) { animation-delay: 0.12s; }
  .z-boot__spinner span:nth-child(3) { animation-delay: 0.24s; }
  .z-boot__spinner span:nth-child(4) { animation-delay: 0.36s; }
  .z-boot__spinner span:nth-child(5) { animation-delay: 0.48s; }
  @keyframes z-boot-orbit {
    0%   { transform: rotate(0deg); opacity: 0; }
    8%   { opacity: 1; }
    50%  { transform: rotate(540deg); opacity: 1; }
    92%  { opacity: 1; }
    100% { transform: rotate(1080deg); opacity: 0; }
  }

  .z-boot__stage {
    font-size: var(--fs-md);
    font-weight: var(--fw-light);
    letter-spacing: 0.02em;
    min-height: 1.5em;
    text-align: center;
  }
  .z-boot__detail { font-size: var(--fs-xs); color: rgba(255, 255, 255, 0.55); min-height: 1.4em; text-align: center; }

  .z-boot__skip {
    position: absolute;
    right: var(--sp-6);
    bottom: var(--sp-6);
    padding: var(--sp-1) var(--sp-3);
    border: 1px solid rgba(255, 255, 255, 0.25);
    background: transparent;
    color: rgba(255, 255, 255, 0.6);
    font: inherit;
    font-size: var(--fs-xs);
    cursor: default;
    opacity: 0;
    animation: z-lock-hint 400ms var(--ease-decel) 1.2s forwards;
  }
  .z-boot__skip:hover { color: #fff; border-color: #fff; }

  /* "Welcome": the spinner and text give way to one word, then everything fades. */
  .z-boot.is-welcome .z-boot__spinner,
  .z-boot.is-welcome .z-boot__detail,
  .z-boot.is-welcome .z-boot__skip { opacity: 0; transition: opacity var(--dur) var(--ease-accel); }
  .z-boot.is-welcome .z-boot__stage { font-size: var(--fs-2xl); font-weight: var(--fw-light); }

  .z-boot.is-finished { opacity: 0; pointer-events: none; }
  .z-boot.is-instant-hidden { display: none !important; }

  @media (prefers-reduced-motion: reduce) {
    .z-boot { transition: none; }
    .z-boot__spinner span { animation: none; opacity: 1; }
    .z-boot__spinner span::before { display: none; }
    .z-boot__spinner { border: 2px solid rgba(255, 255, 255, 0.4); border-radius: 50%; }
    .z-boot__skip { animation: none; opacity: 1; }
  }


  /* ══ Sandboxed App Crash Boundary ══════════════════════════════════════════════════════ */
  .z-win__crash {
    position: absolute;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--sp-4);
    background: rgba(11, 15, 25, 0.88);
    backdrop-filter: blur(20px) saturate(1.6);
    -webkit-backdrop-filter: blur(20px) saturate(1.6);
    overflow-y: auto;
  }

  .z-win__crash-card {
    max-width: 520px;
    width: 100%;
    background: var(--surface-1);
    border: 1px solid var(--border-subtle);
    border-top: 3px solid var(--danger);
    border-radius: var(--r-lg);
    padding: var(--sp-6);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.6), 0 0 20px rgba(239, 68, 68, 0.15);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--sp-3);
  }

  .z-win__crash-icon {
    font-size: 2.4rem;
    line-height: 1;
    filter: drop-shadow(0 0 12px rgba(239, 68, 68, 0.4));
  }

  .z-win__crash-title {
    font-size: var(--fs-lg);
    font-weight: var(--fw-bold);
    color: var(--text-primary);
    margin: 0;
  }

  .z-win__crash-desc {
    font-size: var(--fs-sm);
    color: var(--text-secondary);
    line-height: 1.5;
    margin: 0;
  }

  .z-win__crash-detail {
    width: 100%;
    background: var(--surface-inset);
    border: 1px solid var(--border-subtle);
    border-radius: var(--r-md);
    padding: var(--sp-3);
    text-align: left;
    font-size: var(--fs-xs);
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    margin-top: var(--sp-2);
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.5);
  }

  .z-win__crash-msg {
    color: var(--danger);
    font-family: var(--font-mono, monospace);
    word-break: break-word;
  }

  .z-win__crash-meta {
    color: var(--text-muted);
    font-family: var(--font-mono, monospace);
    word-break: break-all;
  }

  .z-win__crash-stack {
    max-height: 120px;
    overflow-y: auto;
    background: rgba(0, 0, 0, 0.4);
    padding: var(--sp-2);
    border-radius: var(--r-xs);
    color: var(--text-secondary);
    font-family: var(--font-mono, monospace);
    font-size: 0.75rem;
    line-height: 1.4;
    white-space: pre-wrap;
    word-break: break-word;
    margin: 0;
  }

  .z-win__crash-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    justify-content: center;
    margin-top: var(--sp-2);
    width: 100%;
  }
}


