:root {
  /* UI scale: every size in this file (fonts, icons, tiles, menus, dialogs, the notch, gaps, radii) is multiplied
     by --s, and the script reads it too, so tile positions and the snap grid follow. 1 = normal, 1.26 = 26% bigger. */
  --s: 1.25;
  --tile-w: calc(84px * var(--s));
  --tile-h: calc(92px * var(--s));
}

/* ---- themes ----
   Every colour the app uses is one of these tokens; nothing below this block (and nothing in app.js) writes a
   colour literal. The dark theme is the default. Another theme redefines the same tokens under its own selector,
   e.g. :root[data-theme="light"] { color-scheme: light; --bg: ...; ... }, and is switched on with
   document.documentElement.dataset.theme = 'light'. */
:root, :root[data-theme="dark"] {
  color-scheme: dark;
  /* surfaces */
  --bg: #191e28;                          /* desktop background (a desktop with no colour of its own), active notch buttons */
  --panel: #262d3b;                       /* menus, dialogs, notch, toast */
  --notch-shade: rgba(255,255,255,.025);  /* laid over --panel on the notch, a little lighter than the other panels */
  --panel-border: #3a4356;                /* borders, separators, the switch track when off */
  --field: #1a2029;                       /* inputs, secondary buttons, code */
  --backdrop: rgba(0,0,0,.5);             /* behind a dialog */
  /* text */
  --fg: #e6e9ef;
  --muted: #8893a8;                       /* headings in menus, hints, idle icons */
  --fg-dim: #d9dde6;                      /* a tile's title when the tile needs attention */
  --on-accent: #fff;                      /* text and marks drawn on --accent or --danger */
  --bubble-text: #000;                    /* the launcher box's text while it is a blue message bubble */
  /* accents */
  --accent: #5b9cff;
  --danger: #ff6b6b;
  --brand: #f5b400;                       /* the logo's yellow: attention badge, the launcher's "+" */
  --on-brand: #1a1a1a;                    /* text on --brand */
  /* widgets */
  --note: #2b3446;                        /* a note without a colour of its own */
  --note-grip: rgba(255,255,255,.22);     /* the drag strip's handle on a note */
  --note-grip-on-light: rgba(0,0,0,.25);  /* the same on a light-coloured note; also rules and borders in a note */
  --note-code: rgba(0,0,0,.2);            /* behind code in a note */
  --note-code-on-light: rgba(0,0,0,.07);  /* the same on a light-coloured note */
  --group: rgba(0,0,0,.25);               /* behind a group tile's mini grid of icons */
  --rss: #262d3b;                         /* an RSS widget's card */
  --rss-icon: #f78422;                    /* the RSS symbol in its header (RSS orange) */
  --spotify: #121212;                     /* behind a Spotify player (Spotify's own dark) */
  --spotify-handle: rgba(255,255,255,.55); /* the drag handle over a Spotify player */
  /* coloured squares (desktop colours in the notch and launcher) */
  --glyph-fg: #fff;
  --glyph-fg-on-light: #1a1a1a;           /* when the square's colour is light */
  /* interaction tints */
  --hover: rgba(255,255,255,.08);
  --pressed: rgba(255,255,255,.12);       /* a tile while dragged */
  --focus: rgba(255,255,255,.16);         /* a tile with keyboard focus */
  --selected: rgba(91,156,255,.28);       /* a selected tile */
  --marquee-border: rgba(91,156,255,.9);
  --marquee-fill: rgba(91,156,255,.18);
  --ring: rgba(255,255,255,.6);           /* the current / hovered launcher tile */
  --swatch-edge: rgba(255,255,255,.15);
  /* switches */
  --switch-knob: #c9d1e0;
  --switch-track-hover: rgba(0,0,0,.28);
  /* shadows */
  --talk: #ff5c5c;                        /* the push-to-talk button while it listens */
  --talk-ring: rgba(255,92,92,.35);       /* its ring, which grows with the voice level */
  --badge-shadow: rgba(0,0,0,.6);
  --text-shadow: rgba(0,0,0,.8);          /* tile titles over the desktop */
}
html, body { margin: 0; height: 100%; font: calc(14px * var(--s))/1.4 system-ui, sans-serif; color: var(--fg); }
html { background: var(--bg); } /* overridden by the page with the desktop's colour */
/* no pinch or double-tap zoom anywhere (iOS ignores user-scalable=no); one-finger panning still scrolls dialogs */
html, body { touch-action: pan-x pan-y; }
/* no text highlighting anywhere in the app (form fields excepted, so typed text can still be selected and edited),
   and no iOS long-press callout: a long press opens our own menu */
* { user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
input, textarea, [contenteditable] { user-select: text; -webkit-user-select: text; -webkit-touch-callout: default; }
/* Hover and focus styles are drawn only on devices that can hover (see the @media (hover: hover) rules): on a
   touch screen a tap, or the script focusing a tile or menu item, would leave them stuck. That includes the
   browser's own focus ring; form fields keep theirs from their own :focus rules. */
@media (hover: none) { :focus-visible { outline: none; } }
/* The page itself scrolls down when the tiles reach below the screen, never sideways: the root element being the
   scroller is what lets iOS scroll to the top on a tap of the status bar and the browser pull to refresh. No
   scrollbar is drawn; the wheel, keys and a finger still scroll. The safe-area insets (iPhone notch, rounded
   corners, home bar, a home screen app's status bar) are exposed to the script so tiles keep clear of them. */
html { overflow-x: hidden; overscroll-behavior-x: none; scrollbar-width: none; }
html::-webkit-scrollbar { display: none; }
#safe-probe {
  position: fixed; top: 0; left: 0; width: 0; height: 0; visibility: hidden; pointer-events: none;
  padding: env(safe-area-inset-top, calc(0px * var(--s))) env(safe-area-inset-right, calc(0px * var(--s))) env(safe-area-inset-bottom, calc(0px * var(--s))) env(safe-area-inset-left, calc(0px * var(--s)));
}
/* at least one screen tall; tiles below the screen make the page longer */
#desktop {
  position: relative; min-height: 100%; isolation: isolate;
  background: var(--bg);
  /* A finger on empty space scrolls the page and pulls to refresh natively, so the browser keeps vertical pans;
     long press still opens menus, and the two-finger selection box works as long as it does not start a pan. */
  touch-action: pan-y;
}
#desktop.viewer .tile { touch-action: pan-y; } /* tiles of a locked webtop do not drag, so they scroll too */
/* the far end of a webtop that scrolls; placed by the script */
.scroll-end { position: absolute; width: calc(1px * var(--s)); height: calc(1px * var(--s)); pointer-events: none; }
/* image layer under the tiles; blur is a filter on it alone, scaled a little so the blurred edges stay off-screen */
#desktop .bg {
  position: fixed; inset: 0; /* stays put while the tiles scroll */ z-index: 0; pointer-events: none;
  background-position: center; background-size: cover; background-repeat: no-repeat;
}
#desktop .bg.blur { filter: blur(calc(14px * var(--s))); transform: scale(1.06); }
#desktop.empty::after {
  content: 'Right-click to add a shortcut';
  position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--muted); pointer-events: none;
}

/* ---- tiles ---- */
.tile {
  position: absolute; width: var(--tile-w); height: var(--tile-h);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(4px * var(--s));
  padding: calc(6px * var(--s)); box-sizing: border-box; border-radius: calc(8px * var(--s));
  cursor: pointer; touch-action: none; outline: none;
}
@media (hover: hover) { .tile:hover { background: var(--hover); } }
@media (hover: hover) { .tile:focus-visible { background: var(--focus); } } /* keyboard focus is a stronger tint, no ring */
.tile.selected { background: var(--selected); }
.tile.dragging { opacity: .8; background: var(--pressed); z-index: 10; cursor: grabbing; }
.tile .icon {
  width: calc(48px * var(--s)); height: calc(48px * var(--s)); display: grid; place-items: center;
  font-size: calc(36px * var(--s)); line-height: 1; border-radius: calc(10px * var(--s));
}
.tile.attention .icon { position: relative; }
.tile.attention .icon::after {
  content: '!'; position: absolute; right: calc(-4px * var(--s)); bottom: calc(-4px * var(--s)); width: calc(18px * var(--s)); height: calc(18px * var(--s));
  border-radius: 50%; background: var(--brand); color: var(--on-brand); font: 700 calc(13px * var(--s))/calc(18px * var(--s)) system-ui, sans-serif;
  text-align: center; box-shadow: 0 calc(1px * var(--s)) calc(3px * var(--s)) var(--badge-shadow);
}
.tile.attention .title { color: var(--fg-dim); }
.tile .icon img { width: calc(48px * var(--s)); height: calc(48px * var(--s)); object-fit: contain; border-radius: calc(10px * var(--s)); pointer-events: none; }
/* a 2x2 shortcut: the same tile, drawn bigger */
.tile.size-2x2:not(.widget) { gap: calc(10px * var(--s)); }
.tile.size-2x2:not(.widget) .icon { width: calc(108px * var(--s)); height: calc(108px * var(--s)); font-size: calc(84px * var(--s)); border-radius: calc(20px * var(--s)); }
.tile.size-2x2:not(.widget) .icon img { width: calc(108px * var(--s)); height: calc(108px * var(--s)); border-radius: calc(20px * var(--s)); }
.tile.size-2x2:not(.widget) .title { font-size: calc(15px * var(--s)); }
.tile .title {
  font-size: calc(12px * var(--s)); text-align: center; line-height: 1.2; max-width: 100%;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  text-shadow: 0 calc(1px * var(--s)) calc(2px * var(--s)) var(--text-shadow); word-break: break-word;
}

/* ---- widgets: tiles with their own size (set inline from WIDGETS in app.js) and their own body ---- */
.tile.widget { align-items: stretch; justify-content: flex-start; gap: 0; padding: 0; cursor: default; }
/* Note: tinted with its colour; selection, hover and focus are drawn as an inner wash so the colour stays visible */
.tile.note {
  background: var(--note-color); color: var(--fg); border-radius: calc(12px * var(--s)); overflow: hidden;
}
.tile.note.light { color: var(--glyph-fg-on-light); }
.tile.note.dragging { background: var(--note-color); }
@media (hover: hover) { .tile.note:focus-visible { background: var(--note-color); } }
@media (hover: hover) { .tile.note:hover { background: var(--note-color); } }
@media (hover: hover) { .tile.note:hover { box-shadow: inset 0 0 0 100vmax var(--hover); } }
@media (hover: hover) { .tile.note:focus-visible { box-shadow: inset 0 0 0 100vmax var(--focus); } }
.tile.note.selected { background: var(--note-color); box-shadow: inset 0 0 0 100vmax var(--selected); }
/* RSS: a card with a header (title, refresh) to drag it by and a scrolling list of items */
.tile.rss {
  background: var(--rss); color: var(--fg); border-radius: calc(12px * var(--s)); overflow: hidden;
}
.tile.rss.dragging { background: var(--rss); }
@media (hover: hover) { .tile.rss:hover, .tile.rss:focus-visible { background: var(--rss); } }
@media (hover: hover) { .tile.rss:hover { box-shadow: inset 0 0 0 100vmax var(--hover); } }
@media (hover: hover) { .tile.rss:focus-visible { box-shadow: inset 0 0 0 100vmax var(--focus); } }
.tile.rss.selected { background: var(--rss); box-shadow: inset 0 0 0 100vmax var(--selected); }
.rss-head {
  flex: 0 0 auto; display: flex; align-items: center; gap: calc(6px * var(--s));
  padding: calc(6px * var(--s)) calc(6px * var(--s)) calc(4px * var(--s)) calc(12px * var(--s));
  font-size: calc(13px * var(--s)); font-weight: 600;
}
.rss-head.movable { cursor: grab; } /* only editors can move it */
.rss-icon { flex: 0 0 auto; display: grid; color: var(--rss-icon); }
.rss-icon svg { width: calc(14px * var(--s)); height: calc(14px * var(--s)); }
.rss-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rss-refresh {
  flex: 0 0 auto; display: grid; place-items: center; width: calc(26px * var(--s)); height: calc(26px * var(--s));
  padding: 0; border: 0; border-radius: calc(6px * var(--s)); background: none; color: var(--muted); cursor: pointer;
}
@media (hover: hover) { .rss-refresh:hover { background: var(--hover); color: var(--fg); } }
@media (hover: hover) {
  .rss-refresh:focus-visible { box-shadow: 0 0 0 calc(2px * var(--s)) var(--accent); outline: none; }
}
.rss-refresh:disabled { opacity: .4; cursor: default; }
.rss-refresh svg { width: calc(16px * var(--s)); height: calc(16px * var(--s)); }
.rss-refresh.loading svg { animation: rss-spin .8s linear infinite; }
@keyframes rss-spin { to { transform: rotate(360deg); } }
.rss-body {
  flex: 1; min-height: 0; overflow: auto; padding: 0 calc(6px * var(--s)) calc(8px * var(--s));
  font-size: calc(12.5px * var(--s)); line-height: 1.3;
  touch-action: pan-y; /* the list scrolls under a finger; the tile itself takes no touch gestures */
}
.rss-list { list-style: none; margin: 0; padding: 0; }
.rss-item {
  display: block; padding: calc(5px * var(--s)) calc(6px * var(--s)); border-radius: calc(6px * var(--s));
  color: inherit; text-decoration: none;
}
@media (hover: hover) { a.rss-item:hover { background: var(--hover); } }
@media (hover: hover) {
  a.rss-item:focus-visible { box-shadow: inset 0 0 0 calc(2px * var(--s)) var(--accent); outline: none; }
}
.rss-item-title { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.rss-item-meta { margin-top: calc(2px * var(--s)); color: var(--muted); font-size: calc(11px * var(--s)); }
.rss-item-sum { display: none; margin-top: calc(2px * var(--s)); color: var(--muted); font-size: calc(11.5px * var(--s)); }
/* the wide sizes with height to spare have room for a line or two of each item's summary */
.tile.rss.size-3x2 .rss-item-sum, .tile.rss.size-3x4 .rss-item-sum {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.rss-note { margin: calc(4px * var(--s)) calc(6px * var(--s)); color: var(--muted); }
/* Spotify: Spotify's player in an iframe filling the card (its height is set by fitSpotify), with a small handle
   floating over its top edge for editors, since the iframe takes every pointer event over it */
.tile.spotify {
  background: var(--spotify); color: var(--fg); border-radius: calc(12px * var(--s)); overflow: hidden;
}
.tile.spotify.dragging { background: var(--spotify); }
@media (hover: hover) { .tile.spotify:hover, .tile.spotify:focus-visible { background: var(--spotify); } }
.tile.spotify.selected { background: var(--spotify); box-shadow: 0 0 0 calc(3px * var(--s)) var(--accent); }
.spotify-body { flex: 1; min-height: 0; display: flex; align-items: center; }
.spotify-body iframe {
  flex: 1; display: block; width: 100%; min-width: 0; border: 0; border-radius: calc(12px * var(--s));
}
.spotify-body iframe.zoomed { transform-origin: 0 50%; } /* scaled up around its middle (fitSpotify) */
.tile.dragging .spotify-body iframe { pointer-events: none; } /* the drag keeps the pointer over the iframe */
.spotify-handle {
  position: absolute; top: 0; left: 50%; transform: translateX(-50%); z-index: 1;
  width: calc(56px * var(--s)); height: calc(14px * var(--s)); display: grid; place-items: center; cursor: grab;
}
.spotify-handle::before {
  content: ''; width: calc(28px * var(--s)); height: calc(4px * var(--s)); border-radius: calc(2px * var(--s));
  background: var(--spotify-handle);
}
.spotify-note {
  margin: calc(4px * var(--s)) calc(8px * var(--s)); color: var(--muted); font-size: calc(12.5px * var(--s));
}
.note-grip { flex: 0 0 auto; height: calc(16px * var(--s)); display: grid; place-items: center; }
.note-grip.movable { cursor: grab; } /* only editors can move a note */
.note-grip::before { content: ''; width: calc(28px * var(--s)); height: calc(4px * var(--s)); border-radius: calc(2px * var(--s)); background: var(--note-grip); }
.tile.note.light .note-grip::before { background: var(--note-grip-on-light); }
.note-text, .note-view {
  flex: 1; min-height: 0; resize: none; border: 0; outline: none; background: none; color: inherit;
  font: inherit; font-size: calc(13.5px * var(--s)); line-height: 1.45;
  padding: calc(2px * var(--s)) calc(12px * var(--s)) calc(12px * var(--s)); cursor: text;
  touch-action: pan-y; /* the tile itself takes no touch gestures; the text may still scroll */
}
/* A note shows its Markdown rendered, and the plain text only while it is being edited. */
.tile.note.editing .note-view, .tile.note:not(.editing) .note-text { display: none; }
.note-view { overflow: auto; overflow-wrap: anywhere; }
#desktop.viewer .note-view { cursor: default; }
.note-view:empty::before { content: 'Write a note'; opacity: .5; }
.note-view > :first-child { margin-top: 0; }
.note-view > :last-child { margin-bottom: 0; }
.note-view :is(p, ul, ol, pre, blockquote, table, h1, h2, h3, h4, h5, h6) { margin: 0 0 calc(6px * var(--s)); }
.note-view :is(h1, h2, h3, h4, h5, h6) { font-weight: 600; line-height: 1.25; }
.note-view h1 { font-size: 1.35em; }
.note-view h2 { font-size: 1.2em; }
.note-view h3 { font-size: 1.05em; }
.note-view :is(h4, h5, h6) { font-size: 1em; }
.note-view :is(ul, ol) { padding-left: calc(18px * var(--s)); }
.note-view li > :is(ul, ol) { margin: 0; }
.note-view li.task { list-style: none; margin-left: calc(-16px * var(--s)); }
.note-view li.task input { margin: 0 calc(4px * var(--s)) 0 0; vertical-align: -0.1em; }
.note-view li.task input:not(:disabled) { cursor: pointer; }
.note-view a { color: inherit; text-decoration: underline; }
.note-view img { max-width: 100%; border-radius: calc(4px * var(--s)); }
.note-view code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .9em; padding: 0 calc(3px * var(--s)); border-radius: calc(3px * var(--s)); background: var(--note-code); }
.note-view pre { padding: calc(6px * var(--s)) calc(8px * var(--s)); border-radius: calc(6px * var(--s)); overflow: auto; background: var(--note-code); }
.note-view pre code { padding: 0; background: none; }
.note-view blockquote { padding-left: calc(8px * var(--s)); border-left: calc(3px * var(--s)) solid var(--note-grip); opacity: .85; }
.note-view hr { border: 0; border-top: calc(3px * var(--s)) solid var(--note-grip); }
.note-view table { border-collapse: collapse; }
.note-view :is(th, td) { padding: calc(2px * var(--s)) calc(6px * var(--s)); border: calc(1px * var(--s)) solid var(--note-grip); }
.tile.note.light .note-view :is(blockquote, hr, th, td) { border-color: var(--note-grip-on-light); }
.tile.note.light .note-view :is(code, pre) { background: var(--note-code-on-light); }
.tile.note.light .note-view pre code { background: none; }
.note-text::placeholder { color: inherit; opacity: .5; }
.note-text[readonly] { cursor: default; }

/* ---- context menu ---- */
.menu {
  position: fixed; z-index: 100; min-width: calc(220px * var(--s)); margin: 0; padding: calc(8px * var(--s)); list-style: none;
  background: var(--panel); border: 0; border-radius: calc(16px * var(--s));
}
.menu li { padding: calc(9px * var(--s)) calc(14px * var(--s)); border-radius: calc(10px * var(--s)); cursor: default; white-space: nowrap; }
.menu li + li:not(.sep) { margin-top: calc(2px * var(--s)); }
@media (hover: hover) { .menu li:focus-visible { background: var(--accent); color: var(--on-accent); outline: none; } }
@media (hover: hover) { .menu li:hover { background: var(--accent); color: var(--on-accent); outline: none; } }
@media (hover: hover) { .menu:hover li:focus-visible:not(:hover) { background: none; color: inherit; } }
.menu li.sep { height: calc(1px * var(--s)); padding: 0; margin: calc(6px * var(--s)) calc(8px * var(--s)); background: var(--panel-border); pointer-events: none; }
@media (hover: hover) { .menu li.danger:hover { background: var(--danger); } }
.menu li.head { color: var(--muted); font-size: calc(12px * var(--s)); padding-bottom: calc(5px * var(--s)); pointer-events: none; }
/* toggle items: label on the left, a switch on the right (the ::after draws the track, its knob is a gradient) */
.menu li.checked, .menu li.unchecked {
  display: flex; align-items: center; justify-content: space-between; gap: calc(18px * var(--s));
  --track: var(--panel-border); --knob: var(--switch-knob);
}
.menu li.checked { --track: var(--accent); --knob: var(--on-accent); }
@media (hover: hover) { .menu li.unchecked:focus-visible { --track: var(--switch-track-hover); --knob: var(--on-accent); } }
@media (hover: hover) { .menu li.unchecked:hover { --track: var(--switch-track-hover); --knob: var(--on-accent); } }
@media (hover: hover) { .menu li.checked:focus-visible { --track: var(--on-accent); --knob: var(--accent); } }
@media (hover: hover) { .menu li.checked:hover { --track: var(--on-accent); --knob: var(--accent); } }
.menu li.checked::after, .menu li.unchecked::after {
  content: ''; flex: 0 0 auto; width: calc(34px * var(--s)); height: calc(20px * var(--s)); border-radius: calc(999px * var(--s));
  background: radial-gradient(circle, var(--knob) calc(7px * var(--s)), transparent calc(7.5px * var(--s))) 0 0 / calc(20px * var(--s)) calc(20px * var(--s)) no-repeat, var(--track);
  transition: background-position .15s, background-color .15s;
}
.menu li.checked::after { background-position: calc(14px * var(--s)) 0; }
/* items that open a submenu: a thin right chevron at the far end */
.menu li.has-sub { display: flex; align-items: center; justify-content: space-between; gap: calc(18px * var(--s)); }
.menu li.has-sub::after {
  content: ''; flex: 0 0 auto; width: calc(14px * var(--s)); height: calc(14px * var(--s)); background: currentColor; opacity: .55;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 5 7 7-7 7'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 5 7 7-7 7'/%3E%3C/svg%3E") center / contain no-repeat;
}
@media (hover: hover) { .menu li.has-sub:focus-visible::after { opacity: 1; } }
@media (hover: hover) { .menu li.has-sub:hover::after { opacity: 1; } }
/* radio items: a dot on the left, filled for the selected one */
.menu li.radio::before {
  content: ''; display: inline-block; width: calc(8px * var(--s)); height: calc(8px * var(--s)); margin: 0 calc(10px * var(--s)) calc(1px * var(--s)) calc(-2px * var(--s)); border-radius: 50%;
  box-shadow: 0 0 0 calc(2px * var(--s)) var(--muted); vertical-align: middle;
}
.menu li.radio.on::before { background: var(--accent); box-shadow: 0 0 0 calc(2px * var(--s)) var(--accent); }
@media (hover: hover) { .menu li.radio:focus-visible::before { box-shadow: 0 0 0 calc(2px * var(--s)) var(--on-accent); } }
@media (hover: hover) { .menu li.radio:hover::before { box-shadow: 0 0 0 calc(2px * var(--s)) var(--on-accent); } }
@media (hover: hover) { .menu li.radio.on:focus-visible::before { background: var(--on-accent); } }
@media (hover: hover) { .menu li.radio.on:hover::before { background: var(--on-accent); } }
.menu li.back { color: var(--muted); }
@media (hover: hover) { .menu li.back:focus-visible { color: var(--on-accent); } }
@media (hover: hover) { .menu li.back:hover { color: var(--on-accent); } }
.menu li.back::before { content: '↑'; display: inline-block; width: calc(16px * var(--s)); margin-left: calc(-4px * var(--s)); }
.menu li.unchecked::before { visibility: hidden; }

/* ---- dialog ---- */
dialog {
  background: var(--panel); color: var(--fg); border: calc(1px * var(--s)) solid var(--panel-border);
  border-radius: calc(12px * var(--s)); padding: 0; width: min(calc(420px * var(--s)), 92vw); box-sizing: border-box;
  max-height: calc(100vh - calc(32px * var(--s))); max-height: calc(100dvh - calc(32px * var(--s))); overflow: auto; /* tall forms scroll inside */
}
dialog::backdrop { background: var(--backdrop); }
dialog h2 { margin: 0 0 calc(14px * var(--s)); font-size: calc(16px * var(--s)); }
dialog form { display: flex; flex-direction: column; gap: calc(12px * var(--s)); padding: calc(20px * var(--s)) calc(22px * var(--s)); }
dialog label { display: flex; flex-direction: column; gap: calc(4px * var(--s)); font-size: calc(13px * var(--s)); }
dialog .row { display: flex; gap: calc(8px * var(--s)); align-items: center; }
dialog .row > input, dialog .row > select { flex: 1; min-width: 0; }
dialog input[type=text], dialog input:not([type]), dialog input[type=url], dialog input[type=search], dialog input[type=password], dialog select {
  background: var(--field); color: var(--fg); border: calc(1px * var(--s)) solid var(--panel-border); border-radius: calc(6px * var(--s));
  padding: calc(7px * var(--s)) calc(9px * var(--s)); font: inherit;
}
dialog input:focus, dialog select:focus { outline: calc(2px * var(--s)) solid var(--accent); outline-offset: calc(-1px * var(--s)); }
dialog .muted { color: var(--muted); font-weight: normal; }
dialog code { font-size: calc(12px * var(--s)); background: var(--field); padding: calc(1px * var(--s)) calc(4px * var(--s)); border-radius: calc(4px * var(--s)); }
.icon-preview { width: calc(36px * var(--s)); height: calc(36px * var(--s)); flex: 0 0 calc(36px * var(--s)); display: grid; place-items: center; font-size: calc(26px * var(--s)); line-height: 1; overflow: hidden; }
.icon-preview img { width: calc(32px * var(--s)); height: calc(32px * var(--s)); object-fit: contain; }
dialog menu { display: flex; justify-content: flex-end; gap: calc(8px * var(--s)); margin: calc(6px * var(--s)) 0 0; padding: 0; }
dialog button {
  font: inherit; padding: calc(7px * var(--s)) calc(14px * var(--s)); border-radius: calc(6px * var(--s)); border: calc(1px * var(--s)) solid var(--panel-border);
  background: var(--field); color: var(--fg); cursor: pointer;
}
dialog button.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.error { color: var(--danger); margin: 0; font-size: calc(13px * var(--s)); }
dialog .hint { margin: calc(-6px * var(--s)) 0 0; font-size: calc(13px * var(--s)); line-height: 1.4; }
dialog menu .spacer { flex: 1; }
dialog button.danger { color: var(--danger); }
@media (hover: hover) { dialog button.danger:hover { background: var(--danger); border-color: var(--danger); color: var(--on-accent); } }
dialog button.primary.danger-fill { background: var(--danger); border-color: var(--danger); }

/* ---- lock screen (password-protected desktop, not yet unlocked) ---- */
#desktop.locked { display: grid; place-items: center; }
.lock-screen { text-align: center; color: var(--muted); }
.lock-screen .lock-icon { font-size: calc(48px * var(--s)); line-height: 1; margin-bottom: calc(12px * var(--s)); }
.lock-screen p { margin: 0 0 calc(14px * var(--s)); }
.lock-screen button {
  font: inherit; padding: calc(8px * var(--s)) calc(18px * var(--s)); border-radius: calc(6px * var(--s)); border: calc(1px * var(--s)) solid var(--accent);
  background: var(--accent); color: var(--on-accent); cursor: pointer;
}

/* ---- misc ---- */
.offscreen { position: fixed; left: calc(-9999px * var(--s)); top: 0; width: calc(1px * var(--s)); height: calc(1px * var(--s)); opacity: 0; }

/* ---- color panel: a custom item inside the context menu ---- */
.menu li.custom { padding: calc(4px * var(--s)) calc(6px * var(--s)) calc(6px * var(--s)); cursor: default; }
@media (hover: hover) { .menu li.custom:hover { background: none; color: inherit; } }
.color-panel { display: flex; flex-direction: column; gap: calc(10px * var(--s)); }
.color-panel[hidden] { display: none; }
.color-panel .swatches { display: grid; grid-template-columns: repeat(6, calc(26px * var(--s))); gap: calc(6px * var(--s)); }
.color-panel .swatch { width: calc(26px * var(--s)); height: calc(26px * var(--s)); border-radius: calc(9px * var(--s)); border: calc(1px * var(--s)) solid var(--swatch-edge); cursor: pointer; padding: 0; }
@media (hover: hover) { .color-panel .swatch:hover { transform: scale(1.1); } }
/* the Clear swatch: no colour, drawn as a slashed empty tile */
.color-panel .swatch.clear { background: linear-gradient(135deg, transparent 44%, var(--danger) 44%, var(--danger) 56%, transparent 56%), var(--field); }
.color-panel .swatch.current { outline: calc(2px * var(--s)) solid var(--accent); outline-offset: calc(1px * var(--s)); }
.color-panel .row { display: flex; gap: calc(8px * var(--s)); align-items: center; }
.color-panel input[type=color] { width: calc(36px * var(--s)); height: calc(30px * var(--s)); padding: 0; border: calc(1px * var(--s)) solid var(--panel-border); border-radius: calc(9px * var(--s)); background: none; cursor: pointer; }
.color-panel input[type=text] {
  flex: 1; width: calc(100px * var(--s)); min-width: 0; background: var(--field); color: var(--fg); border: calc(1px * var(--s)) solid var(--panel-border);
  border-radius: calc(9px * var(--s)); padding: calc(6px * var(--s)) calc(10px * var(--s)); font: inherit; font-family: ui-monospace, Menlo, monospace;
}
.color-panel input[type=text]:focus { outline: calc(2px * var(--s)) solid var(--accent); outline-offset: calc(-1px * var(--s)); }
/* ---- notifications ---- */
.toasts {
  position: fixed; left: 50%; bottom: calc(calc(78px * var(--s)) + env(safe-area-inset-bottom)); transform: translateX(-50%);
  z-index: 200; /* above the notch, the launcher and dialogs' backdrops */
  display: flex; flex-direction: column; align-items: center; gap: calc(8px * var(--s));
  width: max-content; max-width: calc(100vw - calc(32px * var(--s))); pointer-events: none;
}
.toast {
  display: flex; align-items: center; gap: calc(10px * var(--s)); max-width: calc(440px * var(--s));
  padding: calc(10px * var(--s)) calc(16px * var(--s)) calc(10px * var(--s)) calc(12px * var(--s));
  background: var(--panel); border: 0; border-radius: calc(12px * var(--s)); /* as the notch */
  color: var(--fg); /* also beats the form-message .error rule */
  font-size: calc(13.5px * var(--s)); line-height: 1.35; pointer-events: auto; cursor: pointer;
  animation: toast-in .22s cubic-bezier(.2, .9, .3, 1.2) both;
}
.toast.leaving { animation: toast-out .18s ease-in both; }
.toast.bump { animation: toast-bump .25s ease-out; }
.toast-icon { flex: 0 0 auto; width: calc(18px * var(--s)); height: calc(18px * var(--s)); }
.toast.success .toast-icon { color: var(--accent); }
.toast.error .toast-icon { color: var(--danger); }
.toast.info .toast-icon { color: var(--muted); }
.toast.busy .toast-icon { color: var(--muted); animation: toast-spin .8s linear infinite; }
@keyframes toast-in { from { opacity: 0; transform: translateY(calc(10px * var(--s))) scale(.96); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(calc(6px * var(--s))) scale(.97); } }
@keyframes toast-bump { 40% { transform: scale(1.04); } }
@keyframes toast-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .toast, .toast.leaving, .toast.bump { animation-duration: .01s; }
  .toast.busy .toast-icon { animation: none; }
}

/* type=search is used so password managers skip these fields; hide the search chrome */
dialog input[type=search] { appearance: textfield; -webkit-appearance: textfield; }
dialog input[type=search]::-webkit-search-decoration,
dialog input[type=search]::-webkit-search-cancel-button,
dialog input[type=search]::-webkit-search-results-button { display: none; -webkit-appearance: none; }

/* ---- notch (bottom centre) and the launcher it opens ---- */
.notch {
  position: fixed; left: 50%; transform: translateX(-50%); z-index: 95; /* above the launcher so the button can close it */
  bottom: calc(calc(10px * var(--s)) + env(safe-area-inset-bottom)); /* floats calc(10px * var(--s)) above the bottom (and above a phone's home bar) */
  display: flex; align-items: center; gap: calc(4px * var(--s));
  padding: calc(4px * var(--s)); background: var(--panel); border: 0;
  border-radius: calc(12px * var(--s));
}
/* A shader over the notch's own background: the notch keeps its solid panel colour, and this layer tints it a
   little. The notch is its own stacking context (fixed, z-index), so z-index -1 puts the shade above its background
   but below its buttons; it never takes a click. */
.notch::before {
  content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  background: var(--notch-shade); pointer-events: none;
}
/* the Home desktop: root, or the one this browser pinned */
.notch-home { display: flex; align-items: center; }
.notch button svg { display: block; }
/* up to three recent desktops (the most recent three, in alphabetical order), then the launcher button */
.notch-recent { display: flex; gap: calc(4px * var(--s)); }
.notch-recent:empty { display: none; }
.notch-recent button { padding: calc(6px * var(--s)); border: 0; border-radius: calc(9px * var(--s)); background: none; cursor: pointer; }
@media (hover: hover) { .notch-recent button:focus-visible { background: var(--hover); outline: none; } }
@media (hover: hover) { .notch-recent button:hover { background: var(--hover); } } /* no sticky hover after a tap */
@media (hover: hover) { .notch-recent button:focus-visible { box-shadow: 0 0 0 calc(2px * var(--s)) var(--accent); } }
.notch-recent .glyph {
  width: calc(32px * var(--s)); height: calc(32px * var(--s)); border-radius: calc(8px * var(--s)); display: grid; place-items: center;
  font-size: calc(16px * var(--s)); font-weight: 600; line-height: 1; color: var(--glyph-fg); background: var(--glyph-color);
}
.notch-recent .glyph.light { color: var(--glyph-fg-on-light); }
.notch-recent button.current { background: var(--bg); } /* same as an active notch button */
.notch button {
  display: block; padding: calc(6px * var(--s)); border: 0; border-radius: calc(9px * var(--s));
  background: none; color: var(--fg); cursor: pointer;
}
.notch button img { display: block; }
@media (hover: hover) { .notch button:focus-visible { background: var(--hover); outline: none; } }
@media (hover: hover) { .notch button:hover { background: var(--hover); } }
@media (hover: hover) { .notch button:focus-visible { box-shadow: 0 0 0 calc(2px * var(--s)) var(--accent); } }
/* open/current state is shown by the button background alone; no rings or borders */
.notch button.active { background: var(--bg); }
/* Push to talk: held, not clicked, so a long press must not select text, open a callout or scroll. While it listens
   it turns red and a ring grows with the voice level (--level, 0 to 1, set by the script). */
.notch .talk-btn[hidden] { display: none; }
.notch .talk-btn { touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.notch .talk-btn svg { width: calc(30px * var(--s)); height: calc(30px * var(--s)); }
.notch .talk-btn.talking {
  background: var(--talk); color: var(--on-accent);
  box-shadow: 0 0 0 calc((2px + var(--level, 0) * 12px) * var(--s)) var(--talk-ring);
  transition: box-shadow .06s linear;
}

.launcher {
  position: fixed; inset: 0; z-index: 90; box-sizing: border-box; padding: calc(24px * var(--s)) calc(24px * var(--s)) calc(74px * var(--s)); /* keeps clear of the notch */
  display: flex; flex-direction: column; align-items: center; gap: calc(28px * var(--s));
  /* centred while it fits; once search results make it taller than the screen it scrolls from the top instead of
     being cut off above */
  justify-content: safe center; overflow-y: auto;
  animation: launcher-in .16s ease-out;
}
/* The launcher has no backdrop of its own: while it is open the desktop's tiles (and its empty hint) are hidden,
   so only the desktop's own background shows behind it. */
body.launcher-open #desktop .tile, body.launcher-open #desktop.empty::after { visibility: hidden; }
/* the notch keeps only the launcher button while the launcher is open */
body.launcher-open .notch-home, body.launcher-open .notch-recent { display: none; }
.launcher[hidden] { display: none; }
/* Settings: an overlay like the launcher, with one card per preference */
.settings-title { margin: 0; font-size: calc(20px * var(--s)); font-weight: 600; }
.settings-list { display: flex; flex-direction: column; gap: calc(12px * var(--s)); width: 100%; max-width: calc(520px * var(--s)); animation: launcher-pop .18s ease-out; }
.settings-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: calc(16px * var(--s)); padding: calc(14px * var(--s)) calc(16px * var(--s));
  border: calc(1px * var(--s)) solid var(--panel-border); border-radius: calc(12px * var(--s)); background: var(--panel);
}
/* The text keeps at least a readable width and takes all the spare room (the 999); once it would get narrower than
   that, the controls move under it instead of squeezing it into a tall column. */
.settings-row .text { flex: 999 1 calc(200px * var(--s)); min-width: 0; }
.settings-row h3 { margin: 0 0 calc(4px * var(--s)); font-size: calc(15px * var(--s)); font-weight: 600; }
.settings-row p { margin: 0; font-size: calc(13px * var(--s)); line-height: 1.4; color: var(--muted); }
.settings-row button {
  flex: none; padding: calc(8px * var(--s)) calc(16px * var(--s)); border: calc(1px * var(--s)) solid var(--panel-border);
  border-radius: 999px; background: var(--field); color: var(--fg); font: inherit; font-weight: 600; cursor: pointer;
}
/* the audio cards: a device list and a Test button over a meter; beside the text they keep about their own width,
   under it they fill the card */
.settings-row .audio { display: flex; flex-direction: column; gap: calc(10px * var(--s)); flex: 1 1 calc(240px * var(--s)); min-width: 0; }
.settings-row .controls { display: flex; align-items: center; gap: calc(8px * var(--s)); }
.settings-row .controls select { flex: 1; min-width: 0; }
/* a one-button card's button: beside the text on the right, under it on the right too */
.settings-row > button { margin-left: auto; }
/* Test turns into Stop while the microphone is tested: one width for both words, so the button never jumps */
.settings-row .controls button { min-width: calc(72px * var(--s)); }
.settings-row select {
  padding: calc(7px * var(--s)) calc(10px * var(--s)); border: calc(1px * var(--s)) solid var(--panel-border);
  border-radius: calc(8px * var(--s)); background: var(--field); color: var(--fg); font: inherit; font-size: calc(13px * var(--s));
  appearance: none; -webkit-appearance: none; cursor: pointer; /* no chevron: a plain field that opens the list */
}
.settings-row select:focus { outline: calc(2px * var(--s)) solid var(--accent); outline-offset: calc(-1px * var(--s)); }
.settings-row .settings-note { margin-top: calc(6px * var(--s)); color: var(--muted); font-style: italic; }
/* the Speech to Text card's words, in the device list's place: one line, right to left so the newest words stay in
   view and the oldest end in an ellipsis (the script ends the text with a left-to-right mark so trailing punctuation
   stays at the end) */
.settings-row .transcript {
  flex: 1; min-width: 0; color: var(--fg); font-size: calc(13px * var(--s));
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl;
}
.settings-row .transcript.empty { color: var(--muted); }
/* the Notifications card's switches, one per row: the label, then a switch drawn like the menus' toggles */
.settings-row .switches { display: flex; flex-direction: column; gap: calc(10px * var(--s)); flex: 1 1 calc(240px * var(--s)); min-width: 0; }
.settings-row .setting-switch { display: flex; align-items: center; justify-content: space-between; gap: calc(10px * var(--s)); font-size: calc(13px * var(--s)); color: var(--fg); cursor: pointer; }
.settings-row button.switch {
  flex: none; min-width: 0; width: calc(34px * var(--s)); height: calc(20px * var(--s)); padding: 0; border: 0; border-radius: 999px;
  --track: var(--panel-border); --knob: var(--switch-knob);
  background: radial-gradient(circle, var(--knob) calc(7px * var(--s)), transparent calc(7.5px * var(--s))) 0 0 / calc(20px * var(--s)) calc(20px * var(--s)) no-repeat, var(--track);
  transition: background-position .15s, background-color .15s;
}
.settings-row button.switch[aria-checked="true"] { --track: var(--accent); --knob: var(--on-accent); background-position: calc(14px * var(--s)) 0; }
@media (hover: hover) { .settings-row button.switch:focus-visible { outline: calc(2px * var(--s)) solid var(--accent); outline-offset: calc(2px * var(--s)); } }
/* an audio card's live level (the microphone while testing, the speaker while its chime plays), dimmed when idle */
.level-meter { height: calc(6px * var(--s)); border-radius: 999px; background: var(--field); overflow: hidden; transition: opacity .2s ease; }
.level-meter.idle { opacity: .4; }
.level-meter span { display: block; height: 100%; width: calc(var(--level, 0) * 100%); border-radius: inherit; background: var(--accent); }
.settings-row button.danger { border-color: var(--danger); background: var(--danger); color: var(--on-accent); }
@media (hover: hover) { .settings-row button:hover { filter: brightness(1.1); } }
@media (hover: hover) { .settings-row button:focus-visible { outline: calc(2px * var(--s)) solid var(--accent); outline-offset: calc(2px * var(--s)); } }
@keyframes launcher-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes launcher-pop { from { transform: scale(1.06); opacity: 0; } to { transform: none; opacity: 1; } }
/* Columns of 120px where they fit; on a narrow screen they shrink so at least three still fit in a row */
.launcher-grid {
  --launch-w: min(calc(120px * var(--s)), calc((100% - 2 * 12px * var(--s)) / 3));
  display: grid; grid-template-columns: repeat(auto-fit, var(--launch-w)); justify-content: center; gap: calc(20px * var(--s)) calc(12px * var(--s));
  width: 100%; max-width: calc(820px * var(--s)); animation: launcher-pop .18s ease-out;
}
.launcher-grid:empty { display: none; }
.launch {
  display: flex; flex-direction: column; align-items: center; gap: calc(8px * var(--s)); width: 100%; min-width: 0; box-sizing: border-box; padding: calc(10px * var(--s)) calc(6px * var(--s));
  border: 0; border-radius: calc(12px * var(--s)); background: none; color: var(--fg); font: inherit; cursor: pointer;
}
/* hover, keyboard focus and the current desktop all show the same thing: a ring around the tile's square, no tint */
@media (hover: hover) { .launch:focus-visible { outline: none; } }
@media (hover: hover) { .launch:hover { outline: none; } }
.launch.current .glyph { outline: calc(2px * var(--s)) solid var(--ring); outline-offset: calc(3px * var(--s)); }
@media (hover: hover) { .launch:hover .glyph { outline: calc(2px * var(--s)) solid var(--ring); outline-offset: calc(3px * var(--s)); } }
@media (hover: hover) { .launch:focus-visible .glyph { outline: calc(2px * var(--s)) solid var(--accent); outline-offset: calc(3px * var(--s)); } }
.launch .glyph {
  width: min(calc(64px * var(--s)), 100%); aspect-ratio: 1; border-radius: calc(16px * var(--s)); display: grid; place-items: center; /* narrower on the narrowest phones */
  font-size: calc(30px * var(--s)); font-weight: 600; line-height: 1; color: var(--glyph-fg); background: var(--glyph-color);
}
/* the New Desktop tile: an outlined "+" instead of a coloured square */
.launch.add .glyph { background: none; color: var(--brand); box-shadow: inset 0 0 0 calc(2px * var(--s)) var(--panel-border); } 
@media (hover: hover) { .launch.add:focus-visible .glyph { box-shadow: inset 0 0 0 calc(2px * var(--s)) var(--muted); outline: none; } }
@media (hover: hover) { .launch.add:hover .glyph { box-shadow: inset 0 0 0 calc(2px * var(--s)) var(--muted); outline: none; } }
.launch.add .name { color: var(--muted); }
/* a built-in entry (Settings): an outlined square with a white mark, like New Webtop's */
.launch.cmd .glyph { background: none; color: var(--fg); box-shadow: inset 0 0 0 calc(2px * var(--s)) var(--panel-border); }
@media (hover: hover) { .launch.cmd:focus-visible .glyph { box-shadow: inset 0 0 0 calc(2px * var(--s)) var(--muted); outline: none; } }
@media (hover: hover) { .launch.cmd:hover .glyph { box-shadow: inset 0 0 0 calc(2px * var(--s)) var(--muted); outline: none; } }
.launch .glyph.light { color: var(--glyph-fg-on-light); }
.launch .name {
  font-size: calc(13px * var(--s)); text-align: center; line-height: 1.2; max-width: 100%; word-break: break-word;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
/* the search box and its Ask button: the box filters the tiles below; Return or Ask sends it to the assistant */
.launcher-ask {
  display: flex; align-items: center; gap: calc(8px * var(--s)); width: 100%; max-width: calc(520px * var(--s));
  animation: launcher-pop .18s ease-out;
}
.launcher-search {
  flex: 1; min-width: 0; box-sizing: border-box; padding: calc(10px * var(--s)) calc(16px * var(--s));
  border: calc(1px * var(--s)) solid var(--panel-border); border-radius: 999px; background: var(--panel); color: var(--fg);
  font: inherit; font-size: calc(16px * var(--s)); text-align: center;
  appearance: textfield; -webkit-appearance: textfield;
}
.launcher-search::-webkit-search-decoration, .launcher-search::-webkit-search-cancel-button { display: none; -webkit-appearance: none; }
.launcher-search::placeholder { color: var(--muted); }
.launcher-search:focus { outline: calc(2px * var(--s)) solid var(--accent); outline-offset: calc(-1px * var(--s)); }
.launcher-ask-btn {
  flex: none; padding: calc(10px * var(--s)) calc(22px * var(--s)); border: 0; border-radius: 999px;
  background: var(--accent); color: var(--on-accent); font: inherit; font-size: calc(16px * var(--s)); font-weight: 600;
  cursor: pointer; transition: transform .12s ease, filter .12s ease;
}
.launcher-ask-btn[hidden] { display: none; }
/* With Ask shown (the assistant is there) the box's right corners and Ask's left corners are square, so the two read
   as one piece */
.launcher-ask.with-ask .launcher-search { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.launcher-ask.with-ask .launcher-ask-btn { border-top-left-radius: 0; border-bottom-left-radius: 0; }
/* Nothing in the list matches and the assistant is there: the text reads as a message about to be sent, the box in
   the Ask button's colour with black text, and a Return hint after Ask */
.launcher-search { transition: background-color .15s ease, color .15s ease, border-color .15s ease; }
.launcher-ask.asking .launcher-search { background: var(--accent); border-color: var(--accent); color: var(--bubble-text); }
.launcher-ask.asking .launcher-search:focus { outline: none; } /* the filled bubble already shows where typing goes */
.launcher-enter { display: none; flex: none; color: var(--muted); }
.launcher-enter svg { display: block; width: calc(22px * var(--s)); height: calc(22px * var(--s)); }
.launcher-ask.asking .launcher-enter { display: block; }
.launcher-hint { display: none; margin: calc(-16px * var(--s)) 0 0; color: var(--muted); font-size: calc(14px * var(--s)); text-align: center; }
.launcher-ask.asking + .launcher-hint { display: block; }
.launcher-ask-btn:active { transform: scale(.94); }
@media (hover: hover) { .launcher-ask-btn:hover { transform: translateY(calc(-1px * var(--s))) scale(1.04); filter: brightness(1.08); } }
@media (hover: hover) { .launcher-ask-btn:focus-visible { outline: calc(2px * var(--s)) solid var(--on-accent); outline-offset: calc(2px * var(--s)); } }
/* a shortcut of this webtop: its own icon on a plain square instead of a coloured letter */
.launch.link .glyph { background: var(--field); overflow: hidden; }
.launch.link .glyph img { width: calc(40px * var(--s)); height: calc(40px * var(--s)); object-fit: contain; }

/* ---- groups: a tile with a mini grid of its members' icons, and the panel an open group shows them in ---- */
.tile.group .group-icons {
  /* The whole width, and all the height above the name (or the whole tile without one), with the previews centred
     in it. Each preview is the largest circle that fits --cols columns (2 per cell of width) by 2 rows of this box,
     measured with its container query units; .group-flow is one row (--per-row previews) wide, so they wrap into
     even rows. Both variables are set by the script. */
  --gap: calc(14px * var(--s));
  --size: min(calc((100cqw - (var(--cols, 2) - 1) * var(--gap)) / var(--cols, 2)), calc((100cqh - var(--gap)) / 2));
  container-type: size;
  flex: 1; width: 100%; height: auto; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  padding: calc(6px * var(--s)); box-sizing: border-box; background: var(--group); border-radius: calc(14px * var(--s));
}
.tile.group.size-1x1 .group-icons { --gap: calc(8px * var(--s)); } /* less room in narrower groups */
.tile.group.size-2x1 .group-icons { --gap: calc(10px * var(--s)); }
.tile.group .group-flow {
  display: flex; flex-wrap: wrap; justify-content: center; gap: var(--gap);
  width: calc(var(--per-row, 2) * var(--size) + (var(--per-row, 2) - 1) * var(--gap));
}
.tile.group .group-icon {
  flex: 0 0 auto; width: var(--size); height: var(--size); display: grid; place-items: center; overflow: hidden;
  font-size: calc(var(--size) * .75); border-radius: 50%; /* round previews */
}
.tile.group .group-icon img { width: 100%; height: 100%; border-radius: 50%; }
.tile.group.untitled .title { display: none; } /* no name: the previews take the whole tile */
.group-panel {
  position: fixed; inset: 0; z-index: 90; box-sizing: border-box;
  padding: calc(24px * var(--s)) calc(24px * var(--s)) calc(74px * var(--s)); /* keeps clear of the notch */
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: calc(20px * var(--s));
  animation: launcher-in .16s ease-out;
}
.group-panel[hidden] { display: none; }
/* like the launcher: no backdrop of its own; the webtop's tiles are hidden while a group is open */
body.group-open #desktop .tile, body.group-open #desktop.empty::after { visibility: hidden; }
.group-panel-title {
  color: var(--fg); font-size: calc(17px * var(--s)); font-weight: 600; text-shadow: 0 1px 3px var(--text-shadow);
}
.group-panel-grid {
  display: grid; grid-template-columns: repeat(auto-fit, var(--tile-w)); justify-content: center;
  gap: calc(12px * var(--s)); width: 100%; max-width: calc(820px * var(--s)); max-height: 70vh; overflow: auto;
  animation: launcher-pop .18s ease-out;
}
.group-panel .tile { position: relative; }
.group-panel .tile.leaving { opacity: .3; }
.group-ghost { position: fixed; z-index: 99; pointer-events: none; } /* above the panel and the notch */

/* ---- selection marquee ---- */
.marquee {
  position: fixed; z-index: 50; pointer-events: none;
  border: calc(1px * var(--s)) solid var(--marquee-border); background: var(--marquee-fill); border-radius: calc(2px * var(--s));
}

/* icons whose size is set by width/height attributes in the markup follow the scale too */
#home-btn svg { width: calc(30px * var(--s)); height: calc(30px * var(--s)); }
#launcher-btn img { width: calc(32px * var(--s)); height: calc(32px * var(--s)); }
.launch.add .glyph svg, .launch.cmd .glyph svg { width: calc(30px * var(--s)); height: calc(30px * var(--s)); }
