/* ============ DESK LAUNCHER ============
   The desktop-style app grid on the desk space (dl-). One flat, uncategorised
   set of tiles that fills down the left edge and continues into a new column to
   the right once a column is full, the way icons fill a real desktop.

   The launcher stays click-through: .tab-canvas turns pointer events off and
   only the tiles turn them back on, so the empty desk keeps working as empty
   desk. Scoped to .desk-launcher throughout; the one reduced-motion block lives
   at the end of this file. */

/* The grid hangs in the gap between the two pieces of chrome that share the
   desk, so both edges are written as "where that thing ends, plus air" rather
   than as a measured pixel that only holds at one window size.

   The first two are measurements, not settings. They describe where something
   else already sits, so moving the grid by editing one only makes it lie:

     --dl-nav-bottom   .control-nav sits at top 2.4% and is 50px tall
     --dl-tray-top     the taskbar pill sits at bottom 32px and is 52px tall

   The other two are the settings, and there is one per edge because the two
   edges are not the same kind of problem. The nav is a bar across the top, so
   the grid clears the whole of it and --dl-air is simply the gap left under it.
   The taskbar is a 50px pill in the bottom-left corner, so holding the entire
   floor at arm's length would waste a band of desk the pill never occupies;
   --dl-hem measures up from the desk edge instead, and only refuses to come
   nearer than the pill so a bottom-row icon can never slide underneath it.

   Both follow the window height, stop growing on a tall display, and stop
   shrinking before a short one squeezes the column down to a couple of tiles
   and sends the grid running off the right edge instead.

   The inset also gives the grid a definite height, which is what lets auto-fill
   work out how many tiles a column holds before it wraps into the next one. */
.desk-launcher {
  --dl-nav-bottom: calc(2.4% + 50px);
  --dl-tray-top: 84px;
  --dl-air: clamp(30px, 6%, 72px);
  --dl-hem: clamp(var(--dl-tray-top), 9.5%, 110px);
  --dl-tile: 83px;
  position: absolute;
  inset: calc(var(--dl-nav-bottom) + var(--dl-air)) 20px var(--dl-hem) 27px;
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(auto-fill, var(--dl-tile));
  grid-auto-columns: var(--dl-tile);
  justify-content: start;
  align-content: start;
  gap: 10px;
  user-select: none;
  -webkit-user-select: none;
  font-family: var(--font-sans, "Inter", "SF Pro Display", system-ui, sans-serif);
  -webkit-font-smoothing: antialiased;
}
.desk-launcher * {
  box-sizing: border-box;
}

/* --------------------------------------------------------------- apps -- */

/* The tile is the whole app: glyph, name and power dot all live inside one
   square. It wears the widget glass unchanged, so a tile and a widget card are
   the same material at two sizes: no border, only the gradient and the blur. */
.dl-app {
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 7px;
  width: var(--dl-tile);
  height: var(--dl-tile);
  padding: 9px 7px;
  border: none;
  border-radius: 18px;
  background: linear-gradient(145deg, rgba(30, 33, 32, 0.14) 0%, rgba(16, 19, 18, 0.11) 100%);
  /* The widget cards blur at 25px, but a 25px blur on a tile this size reaches
     across the gap to its neighbour and the whole column smears into one plate.
     Same material, blur scaled to the pane. */
  backdrop-filter: blur(12px) saturate(120%);
  -webkit-backdrop-filter: blur(12px) saturate(120%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.09),
    0 4px 12px rgba(0, 0, 0, 0.18);
  font: inherit;
  color: inherit;
  cursor: pointer;
  touch-action: none;
  transition:
    transform 160ms var(--tab-anim-ease, ease),
    filter 160ms linear,
    box-shadow 160ms linear;
}
.dl-app:hover {
  filter: brightness(1.07);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    0 5px 14px rgba(0, 0, 0, 0.2);
}
.dl-app:active {
  transform: scale(0.98);
}
.dl-app.is-selected {
  filter: brightness(1.12);
}
.dl-app:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.55);
  outline-offset: 2px;
}

/* The glyph slot has no surface of its own — no plate, no ring, nothing behind
   the mark. The whole tile is the frame, so the drawing gets to be large and
   open, and one white for every app keeps the grid a set rather than a
   paintbox. Large is not the same as loud: the stroke is thinned in
   desktop.icons.js to land on screen at the same weight every other icon in the
   app is drawn with, so resizing here means revisiting that too. */
.dl-app-tile {
  display: grid;
  flex: 0 0 auto;
  place-items: center;
}
.dl-app-tile svg {
  width: 29px;
  height: 29px;
  color: rgba(255, 255, 255, 0.72);
}

.dl-app.is-dragging {
  opacity: 0.3;
}

.dl-app-label {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  max-width: 100%;
  overflow: hidden;
  font-size: 10px;
  font-weight: 400;
  letter-spacing: 0.005em;
  line-height: 1.25;
  text-align: center;
  color: rgba(255, 255, 255, 0.8);
  overflow-wrap: anywhere;
}

/* machines carry a power dot: lit for the running one, dark for the rest */
.dl-app-dot {
  width: 5px;
  height: 5px;
  margin-top: -3px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.18);
}
.dl-app-dot.is-on {
  background: rgba(255, 255, 255, 0.95);
  box-shadow: 0 0 8px rgba(255, 255, 255, 0.7);
}

/* -------------------------------------------------------------- drag -- */

.dl-drag-clone {
  position: fixed;
  z-index: 60;
  margin: 0;
  pointer-events: none;
  opacity: 0.92;
  transform: translate(-50%, -50%) scale(1.04);
}
.dl-drag-clone.dl-app {
  box-shadow: 0 22px 46px rgba(0, 0, 0, 0.55);
}

/* -------------------------------------------------- running-apps tray -- */
/* Only on the desk does the collapsed cognitive pill wear the apps glyph and
   act as a start button; everywhere else it stays the chevron it always was. */

.cog-dev__apps-icon {
  display: none;
}
body[data-space="desk"] .cog-dev.is-collapsed .cog-dev__collapse > svg {
  display: none;
}
body[data-space="desk"] .cog-dev.is-collapsed .cog-dev__collapse > .cog-dev__apps-icon {
  display: block;
  width: 22px;
  height: 22px;
  transform: none;
}

/* Opening grows the pill itself rightwards, the way .search-field opens: the
   button keeps its place at the left edge and the icons appear beside it.

   The surface is chrome, not widget glass. It used to wear the app tiles' glass,
   which put two different materials next to each other along the same edge of
   the screen — the Neva dock a few pixels away is built from the --chrome-*
   tokens, the same recipe as the nav at the top of the frame. A taskbar is
   furniture, not a card on the desk, so it belongs to the frame.

   The height and the baseline come from the dock too: a 40px key plus its 6px
   of padding is 52, and 32px up from the edge is where the dock sits. */
body[data-space="desk"] .cog-dev.is-collapsed {
  display: flex;
  align-items: center;
  bottom: 32px;
  width: auto;
  max-width: min(720px, calc(100vw - 48px));
  height: 52px;
  overflow: hidden;
  border: none;
  border-radius: var(--chrome-radius, 10px);
  background: var(--chrome-glass, rgba(14, 17, 19, 0.55));
  backdrop-filter: var(--chrome-blur, blur(22px));
  -webkit-backdrop-filter: var(--chrome-blur, blur(22px));
  /* The dock carries its depth on a top highlight and a dark lip rather than a
     drop shadow, because the mask that cuts its notch would clip an outer shadow
     away to nothing. Matching it here is a choice rather than a constraint: the
     two stand on the same line and a shadow under only one of them would show. */
  box-shadow: var(--chrome-highlight), inset 0 -1px 0 rgba(0, 0, 0, 0.35);
}
body[data-space="desk"] .cog-dev.is-collapsed .cog-dev__head,
body[data-space="desk"] .cog-dev.is-collapsed .cog-dev__collapse {
  flex: 0 0 52px;
  width: 52px;
  height: 52px;
}

.desk-tray {
  display: none;
}
/* 0fr -> 1fr rather than a width, because the width the tray wants depends on
   how many windows are in it and `auto` is not a length a transition can travel
   to. The column measures the row for itself and only the fraction is animated,
   so this opens smoothly whether it is holding nothing or six windows. */
body[data-space="desk"] .cog-dev.is-collapsed .desk-tray {
  display: grid;
  flex: 0 1 auto;
  grid-template-columns: 0fr;
  min-width: 0;
  opacity: 0;
  transition:
    grid-template-columns 340ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 200ms ease;
}
body[data-space="desk"] .cog-dev.is-collapsed.has-tray-open .desk-tray {
  grid-template-columns: 1fr;
  opacity: 1;
}
.desk-tray__inner {
  display: flex;
  align-items: center;
  gap: 14px;
  height: 52px;
  min-width: 0;
  padding: 0 14px 0 4px;
  overflow: hidden;
}
.desk-tray__apps {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.desk-tray__empty {
  margin: 0;
  padding: 0 6px;
  font-size: 12px;
  white-space: nowrap;
  color: var(--text-muted, rgba(255, 255, 255, 0.38));
}

/* One button per open window. The dot underneath is the running light: lit for
   a window on screen, dim for one that has been minimised down here. */
.desk-tray__app {
  position: relative;
  display: grid;
  flex: 0 0 auto;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: none;
  border-radius: 11px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
  cursor: pointer;
  transition: background-color 140ms linear;
}
.desk-tray__app:hover {
  background: rgba(255, 255, 255, 0.14);
}
.desk-tray__app.is-focused {
  background: rgba(255, 255, 255, 0.18);
}
.desk-tray__app svg {
  width: 23px;
  height: 23px;
}
.desk-tray__dot {
  position: absolute;
  bottom: 3px;
  width: 12px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  opacity: 0.9;
}
.desk-tray__app.is-minimised .desk-tray__dot {
  width: 4px;
  opacity: 0.45;
}
/* A window has just landed here. The icon takes the weight and springs back, so
   the flight arrives on something instead of merely stopping. */
.desk-tray__app.is-landing {
  animation: desk-tray-land 460ms cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes desk-tray-land {
  0% {
    transform: translateY(7px) scale(0.7);
  }
  40% {
    transform: translateY(-3px) scale(1.16);
  }
  100% {
    transform: none;
  }
}

.desk-tray__clock {
  display: flex;
  flex: 0 0 auto;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  padding-left: 14px;
  border-left: 1px solid rgba(255, 255, 255, 0.1);
  line-height: 1.2;
  white-space: nowrap;
}
.desk-tray__time {
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
}
.desk-tray__date {
  font-size: 10px;
  color: var(--text-secondary, rgba(255, 255, 255, 0.6));
}


/* --------------------------------------------------------- the one bar -- */
/* Three zones on one surface, read left to right: the start button with the
   windows it holds, the four Neva keys with the orb threaded between them, and
   the clock. dock-row.js gathers the parts; everything here is what they need
   once they are standing in the same box.

   THE ORB IS THE ANCHOR, NOT THE ROW. A centred row re-centres itself every
   time it changes width, so opening the recents drawer dragged the keys, the
   orb and the clock sideways under the pointer, and the particle field, which
   is drawn on its own full-screen canvas and only re-aimed when it is told to,
   was left behind at the orb's old place. The row hangs off its right edge
   instead and dock-row.js writes --row-right to stand the orb on the screen's
   axis. Everything from the drawer rightwards is then fixed for good: the
   drawer is the only thing that moves, and it grows away to the left.

   THE BAR IS THE FRAME, NOT A CARD ON IT. Every window stacks under 1380, and a
   maximised one takes the whole viewport, so the row it was minimised into used
   to end up buried: the start button, the keys and the clock all sat under the
   very things they control. It stands over them now, and still gives way to the
   desk context menu at 1400 so a menu opened near the bottom edge stays whole. */
.dock-row {
  position: fixed;
  right: var(--row-right, 50%);
  bottom: 32px;
  z-index: 1390;
  display: flex;
  align-items: center;
  max-width: calc(100vw - 48px);
  transition: bottom 320ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* A WINDOW FILLING THE SCREEN PUTS THE BAR ON THE FLOOR. Floating is right for a
   desk you can see: the row hangs over the wallpaper, clear of both edges. Behind
   a full-screen window there is no wallpaper left to hang over, and a short bar
   in the middle of the bottom edge only leaves two strips of desk showing either
   side of it. So the glass runs edge to edge and sits flush on the floor, a
   little shorter, with the sphere lifted clear of the bottom edge rather than
   shrunk into the bar. Nothing in the row changes place. */
body.has-max-window .dock-row {
  left: 0;
  right: 0;
  bottom: 0;
  max-width: none;
  /* THE SURFACE STRETCHES, THE SPHERE DOES NOT MOVE. The row is pinned to both
     edges and then held off the right one by the same distance it used to hang
     from, so the glass is wider and the orb is still on the screen's axis. */
  justify-content: flex-end;
  /* --row-clock is the width the clock took with it when the corner strip
     borrowed it (desk-shell.js). Handed back as padding, the keys and the
     sphere keep the exact place they hold while the bar floats. */
  padding-right: calc(var(--row-right, 24px) + var(--row-clock, 0px));
}
body.has-max-window .dock-row::before {
  border-radius: 0;
  /* No notch down here. A hole wide enough to clear the sphere is wider than the
     bar it would be cut in, and the slivers left above and below it read as a
     surface snapped in half over the very window it is meant to cover. */
  -webkit-mask: none;
  mask: none;
}
/* THE START BUTTON AND THE WINDOWS IT HOLDS GO AWAY. There is one window and you
   are inside it, so a drawer holding the others is a shelf with nothing on it,
   and 52px of start button under a full-screen window is a door back out of it
   nobody asked for. What stays is the sphere on the axis and, in the far corner,
   the clock and the keys that drive the window.

   Hidden rather than emptied, and hidden at the pill rather than at the tray:
   the tray is the pill's own child, so one rule puts both away and neither has
   to be told anything. Both come back holding exactly what they held. */
body.has-max-window .dock-row .cog-dev {
  display: none;
}
body.has-max-window .dock-row .neva-dock {
  padding: 2px 10px;
}
/* The sphere comes up rather than down into the bar. It hangs 18px below its own
   box while the bar floats, and that overhang is the one thing that kept the bar
   off the floor; stood on the foot of that box it clears the bottom edge and
   still rises out of the top of the bar, which is where it belongs.
   Three tenths off 76 to sit with the shorter bar. The box around it keeps its
   own width, so the keys either side do not close in and the sphere stays on the
   screen's axis. */
body.has-max-window .dock-row .neva-orb-stage {
  bottom: 0;
  width: 53px;
  height: 53px;
}
/* The hole for the orb is measured rather than named: the start button is
   narrow, the clock is wide and the tray between them changes width with every
   window, so the orb is never the middle of the row. dock-row.js writes
   --row-notch-x and this only draws where it says.

   No drop shadow, and that is forced rather than chosen — an outer shadow is
   painted outside the border box and the mask is clipped to it, so the shadow
   would be masked away to nothing. The depth is a top highlight and a dark lip
   along the bottom instead, which is the trade the dock already made alone. */
.dock-row::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: var(--chrome-radius, 10px);
  background: var(--chrome-glass, rgba(14, 17, 19, 0.55));
  backdrop-filter: var(--chrome-blur, blur(22px));
  -webkit-backdrop-filter: var(--chrome-blur, blur(22px));
  box-shadow: var(--chrome-highlight), inset 0 -1px 0 rgba(0, 0, 0, 0.35);
  -webkit-mask: radial-gradient(circle 44px at var(--row-notch-x, 50%) 50%, transparent 43px, #000 44px);
  mask: radial-gradient(circle 44px at var(--row-notch-x, 50%) 50%, transparent 43px, #000 44px);
}

/* Inside the row nothing owns a surface of its own — the row is the surface,
   and glass sitting on glass is the same material twice. */
.dock-row .neva-dock {
  position: static;
  z-index: auto;
  transform: none;
}
.dock-row .neva-dock::before {
  display: none;
}
/* The border-right is the divider between the first zone and the keys, and it
   has to be set here rather than in a rule of its own: the desk override a few
   blocks up says `border: none` with a specificity this has to clear. */
body[data-space="desk"] .dock-row .cog-dev.is-collapsed {
  position: static;
  /* Reversed, so the start button keeps the divider and the drawer opens away
     from it. In source order the tray follows the button, which put the open
     windows between the button and the keys and shoved the keys along as they
     arrived. The button is what the pointer is resting on when they arrive, so
     the button is the one thing that must not move. */
  flex-direction: row-reverse;
  border-right: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 0;
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: none;
}
/* The keys rest away until a hand comes down to the bottom of the frame, which
   is the right rule while the orb is the only thing down here. It is the wrong
   one now: the bar is already standing, because a start button has to be
   reachable, and keys dissolving in and out of a surface that never leaves
   reads as a fault rather than as an arrival. */
.dock-row .neva-dock-group {
  opacity: 1;
  filter: none;
  transform: none;
  pointer-events: auto;
}

/* Two hairlines divide the three zones, and they are the rule the tray was
   already using to hold the clock off the apps — borrowed outwards rather than
   invented, so the row divides in a single voice. The clock keeps its own; the
   start button carries the other, so the divider travels with the tray as it
   opens rather than sitting in the middle of it.

   Both ends of the row are inset by the same 18px: the clock states it, and the
   start button arrives at it by centring a 22px glyph in 58px. */
.dock-row .desk-tray__clock {
  height: 52px;
  justify-content: center;
  padding: 0 18px 0 16px;
}
body[data-space="desk"] .dock-row .cog-dev.is-collapsed .cog-dev__head,
body[data-space="desk"] .dock-row .cog-dev.is-collapsed .cog-dev__collapse {
  flex: 0 0 58px;
  width: 58px;
}
/* Held to the right, against the start button, so the windows are uncovered
   from the button outwards as the column widens rather than sliding along with
   its leading edge. A drawer that opens has things appear in it; a drawer whose
   contents travel with the door is a panel being dragged.

   The inset at this end of the row is the strip's own padding and not the
   inner's, because the inner is the box being narrowed to nothing and padding
   is the one part of a box that will not shrink: on the inner it would leave a
   permanent sliver of bar sticking out past the start button. */
.dock-row .desk-tray__inner {
  justify-content: flex-end;
  padding: 0;
}
.dock-row .desk-tray__apps {
  padding: 0 8px 0 18px;
}
/* What the keys open belongs to the bar and rides with it. A row standing over a
   window whose panels open behind that same window is two surfaces, not one. */
body[data-space="desk"] .neva-panel,
body[data-space="desk"] .neva-prompt {
  z-index: 1391;
}

/* ------------------------------------------ machine session windows --- */
/* A Windows/Ubuntu session opened from a Machines tile. These are windows, not
   modals: no scrim, no scroll lock, and the workspace behind stays clickable.
   Sits above the app (max z-index 1000) and below World Select (2000) and
   sign-in (3000), so both of those still cover it. */

.desk-window {
  position: fixed;
  z-index: 1200;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  /* No stroke, and the frame's own corner. The house style is explicit that
     persistent chrome is a panel: fill, blur, shadow, one highlight along the
     top and no line of any kind. A window is the largest panel on the desk, so
     it reads from the same numbers as the nav and the bar. */
  border: none;
  border-radius: var(--chrome-radius, 10px);
  background: var(--panel-bg-strong, rgba(24, 26, 25, 0.78));
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
  box-shadow: var(--shadow-panel, 0 24px 60px rgba(0, 0, 0, 0.55));
}
/* Hidden, not closed. visibility keeps the frame's box — so the session is
   never resized to 0x0 — while dropping the whole window out of hit-testing.
   Nothing inside may set visibility back, or it would keep eating clicks. */
.desk-window.is-hidden {
  visibility: hidden;
  pointer-events: none;
}
/* With the stroke gone, the window in front says so by standing further off the
   desk rather than by lighting an edge. */
.desk-window.is-focused {
  box-shadow: 0 34px 80px rgba(0, 0, 0, 0.62);
}
.desk-window.is-max {
  border-radius: 0;
}
/* Leaving and coming back — minimise, close, reopen from the dock. The window
   drifts left, sinks and dissolves towards the dock; it is hidden while
   invisible, and reversed on the way back. Transform-only, so the inline
   left/top/width/height stay authoritative. */
/* Minimising travels to the taskbar rather than in a fixed direction: the
   window manager measures the pill at the bottom-left and writes the distance
   into --dw-fly-x / --dw-fly-y before adding the class. */
.desk-window.is-shifting {
  transform:
    translate(var(--dw-fly-x, -48px), var(--dw-fly-y, 72px))
    scale(var(--dw-fly-scale, 0.94));
  transform-origin: top left;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
  /* The fade waits. A window that starts dissolving on the first frame is gone
     before it has gone anywhere, so it stays solid for the first half of the
     flight and only gives out as it reaches the bar. */
  transition:
    transform 320ms cubic-bezier(0.5, 0, 0.75, 0.35),
    opacity 140ms ease-in 180ms;
}
/* Coming back the other way it arrives sharp at once and the scale overshoots a
   hair at the end, so it lands rather than stops. */
.desk-window.is-settling {
  transform: none;
  opacity: 1;
  pointer-events: none;
  will-change: transform, opacity;
  transition:
    transform 300ms cubic-bezier(0.16, 1.02, 0.3, 1),
    opacity 160ms ease-out;
}
/* Resizing in place — fullscreen and back. The new box is applied at once and
   the window is transformed back over its old one, so it visibly sweeps right
   and rises into the viewport instead of jumping. Never fades: something
   growing has no reason to disappear first. */
.desk-window.is-morphing {
  transform-origin: top left;
  transition: transform 340ms cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
}
.desk-window.is-morphing .desk-window__frame {
  pointer-events: none;
}

.desk-window__bar {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border-softer, rgba(255, 255, 255, 0.05));
  /* The same charcoal and the same top highlight as the nav at the top of the
     frame and the bar at the bottom of it. A title bar is chrome, so it is the
     one part of a window that wears the chrome's own colour. */
  background: var(--chrome-glass, rgba(14, 17, 19, 0.55));
  box-shadow: var(--chrome-highlight, inset 0 1px 0 rgba(255, 255, 255, 0.06));
  cursor: grab;
  user-select: none;
  touch-action: none;
}
.desk-window.is-interacting .desk-window__bar {
  cursor: grabbing;
}
/* Filling the screen, a window has no title bar at all. There is nothing left to
   drag it by, nothing about which window this is that the screen is not already
   saying, and no reason for a strip of chrome between the frame and the app. The
   three buttons it carried are drawn in the corner of the bar instead. */
.desk-window.is-max .desk-window__bar {
  display: none;
}
.desk-window__icon {
  display: grid;
  flex: 0 0 auto;
  place-items: center;
  margin-right: -4px;
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
}
.desk-window__icon svg {
  width: 16px;
  height: 16px;
}
.desk-window__title {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
}
.desk-window__status {
  flex: 1 1 auto;
  font-size: 12px;
  color: var(--text-secondary, rgba(255, 255, 255, 0.6));
}
.desk-window__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
  cursor: pointer;
  transition: background 0.2s ease;
}
.desk-window__btn:hover {
  background: rgba(255, 255, 255, 0.14);
}
.desk-window__btn svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---- the corner of the bar ---- */
/* Where the bottom edge ends up once a window fills the screen: the clock, the
   key that takes the whole browser with it, and the three a window is driven by
   now that it has no title bar to carry them.
   Standing on the bar rather than in it: the row is hung so the orb sits on the
   screen's axis, and anything added inside it would push the sphere off. Only
   the corner is ever covered, which is glass and nothing else. */
.desk-wincontrols {
  position: fixed;
  right: 0;
  bottom: 0;
  z-index: 1391;
  display: none;
  align-items: center;
  height: 44px;
  padding: 0 12px 0 0;
}
.desk-wincontrols.is-on {
  display: flex;
}
/* The clock is the bar's own, moved here by desk-shell.js rather than drawn
   twice. Its divider went with it and is dropped: the segment beside it already
   holds the keys apart from it, and a line as well would be saying it twice. */
.desk-wincontrols .desk-tray__clock {
  height: 44px;
  justify-content: center;
  padding: 0 12px 0 0;
  border-left: none;
}
/* THE FOUR KEYS ARE ONE OBJECT. Loose on the glass they were four unrelated
   marks in a corner, each one asking to be read on its own; in a single tray
   with a hairline through it they are what they actually are — a control with
   four positions, the browser on one side of the line and the window on the
   other. The fill is the faintest step up from the bar it stands on, which is
   all a group needs to be a group. */
.desk-wincontrols__keys {
  display: flex;
  align-items: center;
  padding: 2px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.05);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.desk-wincontrols__rule {
  width: 1px;
  height: 16px;
  margin: 0 3px;
  background: rgba(255, 255, 255, 0.1);
}
.desk-wincontrols__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  border-radius: 8px;
  background: none;
  color: var(--text-secondary, rgba(255, 255, 255, 0.6));
  cursor: pointer;
  transition: background-color 140ms linear, color 140ms linear;
}
.desk-wincontrols__btn:hover {
  background: var(--chrome-fill-hover, rgba(255, 255, 255, 0.09));
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
}
.desk-wincontrols__btn--close:hover {
  background: rgba(216, 68, 68, 0.9);
  color: #fff;
}
/* Thinner than the title bar's, because these are smaller and sit on a lighter
   fill: the same stroke would come out heavier here than it does up there. */
.desk-wincontrols__btn svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.desk-window__stage {
  position: relative;
  flex: 1 1 auto;
  overflow: hidden;
  background: #0a0c0b;
}
.desk-window__frame {
  display: block;
  width: 100%;
  height: 100%;
  border: none;
}
/* The iframe would otherwise swallow every pointermove once a drag or resize
   crossed into it. */
.desk-window.is-interacting .desk-window__frame {
  pointer-events: none;
}

/* ---- resize grips: four edges, four corners ---- */
.desk-window__grip {
  position: absolute;
  touch-action: none;
}
.desk-window.is-max .desk-window__grip {
  display: none;
}
.desk-window__grip--n,
.desk-window__grip--s {
  right: 10px;
  left: 10px;
  height: 8px;
  cursor: ns-resize;
}
.desk-window__grip--e,
.desk-window__grip--w {
  top: 10px;
  bottom: 10px;
  width: 8px;
  cursor: ew-resize;
}
.desk-window__grip--n { top: -3px; }
.desk-window__grip--s { bottom: -3px; }
.desk-window__grip--e { right: -3px; }
.desk-window__grip--w { left: -3px; }

.desk-window__grip--ne,
.desk-window__grip--nw,
.desk-window__grip--se,
.desk-window__grip--sw {
  width: 16px;
  height: 16px;
}
.desk-window__grip--ne { top: -3px; right: -3px; cursor: nesw-resize; }
.desk-window__grip--nw { top: -3px; left: -3px; cursor: nwse-resize; }
.desk-window__grip--se { right: -3px; bottom: -3px; cursor: nwse-resize; }
.desk-window__grip--sw { bottom: -3px; left: -3px; cursor: nesw-resize; }

/* Faint corner hint on the one people reach for first. */
.desk-window__grip--se::after {
  content: "";
  position: absolute;
  right: 4px;
  bottom: 4px;
  width: 8px;
  height: 8px;
  border-right: 2px solid rgba(255, 255, 255, 0.26);
  border-bottom: 2px solid rgba(255, 255, 255, 0.26);
  border-bottom-right-radius: 3px;
}
/* ------------------------------------------------------- snap hint --- */
/* Drawn while a window is dragged against an edge, showing the box it will
   take when released. Under every window so it never covers the one moving. */

.desk-snap-hint {
  position: fixed;
  z-index: 1150;
  border: 1.5px solid rgba(255, 255, 255, 0.5);
  border-radius: var(--chrome-radius, 10px);
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 140ms linear;
}
.desk-snap-hint.is-on {
  opacity: 1;
}

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

.desk-menu {
  position: fixed;
  z-index: 1400;
  display: flex;
  flex-direction: column;
  min-width: 190px;
  padding: 5px;
  border-radius: 12px;
  background: linear-gradient(145deg, rgba(30, 33, 32, 0.86) 0%, rgba(16, 19, 18, 0.82) 100%);
  backdrop-filter: blur(25px) saturate(120%);
  -webkit-backdrop-filter: blur(25px) saturate(120%);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
}
.desk-menu__item {
  padding: 8px 11px;
  border: none;
  border-radius: 8px;
  background: none;
  font: inherit;
  font-size: 13px;
  text-align: left;
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
  cursor: pointer;
}
.desk-menu__item:hover {
  background: rgba(255, 255, 255, 0.1);
}
.desk-menu__rule {
  height: 1px;
  margin: 4px 6px;
  background: rgba(255, 255, 255, 0.1);
}

/* ------------------------------------------------------ app panels --- */
/* What a non-machine window shows. Every app is built from the same handful of
   pieces (see desk-apps.js), which is why sixteen screens fit in one short
   block: a two-pane shell, rows, figures, bars, an editor. */

.desk-window__panel {
  height: 100%;
  overflow: auto;
  padding: 18px 20px 22px;
  font-family: var(--font-sans, "Inter", "SF Pro Display", system-ui, sans-serif);
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
}
.desk-window__panel * {
  box-sizing: border-box;
}

.dw-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
}
.dw-toolbar__gap {
  flex: 1 1 auto;
}
.dw-toolbar__text {
  font-size: 12px;
  color: var(--text-secondary, rgba(255, 255, 255, 0.6));
}
.dw-btn {
  padding: 7px 13px;
  border: none;
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.08);
  font: inherit;
  font-size: 12px;
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
  cursor: pointer;
  transition: background-color 140ms linear;
}
.dw-btn:hover {
  background: rgba(255, 255, 255, 0.16);
}
.dw-btn--primary {
  background: rgba(91, 155, 213, 0.28);
}
.dw-btn--primary:hover {
  background: rgba(91, 155, 213, 0.42);
}

.dw-panes {
  display: grid;
  grid-template-columns: 168px 1fr;
  gap: 20px;
  align-items: start;
}
.dw-aside {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-right: 18px;
  border-right: 1px solid rgba(255, 255, 255, 0.07);
}
.dw-main {
  min-width: 0;
}

.dw-nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.dw-nav__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  padding: 7px 10px;
  border: none;
  border-radius: 8px;
  background: none;
  font: inherit;
  font-size: 13px;
  text-align: left;
  color: var(--text-secondary, rgba(255, 255, 255, 0.6));
  cursor: pointer;
}
.dw-nav__item:hover {
  background: rgba(255, 255, 255, 0.06);
}
.dw-nav__item.is-current {
  background: rgba(255, 255, 255, 0.1);
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
}
.dw-nav__count {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted, rgba(255, 255, 255, 0.38));
}

.dw-heading {
  margin-bottom: 12px;
}
.dw-heading + .dw-heading {
  margin-top: 22px;
}
.dw-heading__title {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
}
.dw-heading__sub {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--text-secondary, rgba(255, 255, 255, 0.6));
}

.dw-rows {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}
.dw-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 10px;
  border-radius: 10px;
}
.dw-row:hover {
  background: rgba(255, 255, 255, 0.05);
}
.dw-row.is-done .dw-row__title {
  color: var(--text-muted, rgba(255, 255, 255, 0.38));
  text-decoration: line-through;
}
.dw-row__mark {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.3);
}
.dw-row__mark[data-tone="blue"] { background: #4a90e2; }
.dw-row__mark[data-tone="green"] { background: #3ddc84; }
.dw-row__mark[data-tone="amber"] { background: #f5a623; }
.dw-row__mark[data-tone="red"] { background: #f0584e; }
.dw-row__mark[data-tone="pink"] { background: #ec4899; }
.dw-row__text {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.dw-row__title {
  font-size: 13px;
}
.dw-row__note {
  font-size: 11px;
  color: var(--text-secondary, rgba(255, 255, 255, 0.6));
}
.dw-row__meta {
  flex: 0 0 auto;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted, rgba(255, 255, 255, 0.38));
}

.dw-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
  margin-bottom: 20px;
}
.dw-figure {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
}
.dw-figure__value {
  font-size: 22px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.dw-figure__label {
  font-size: 11px;
  color: var(--text-secondary, rgba(255, 255, 255, 0.6));
}

.dw-bars {
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.dw-bar {
  display: grid;
  grid-template-columns: 42px 1fr 58px;
  align-items: center;
  gap: 12px;
}
.dw-bar__label {
  font-size: 11px;
  color: var(--text-secondary, rgba(255, 255, 255, 0.6));
}
.dw-bar__track {
  height: 8px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
}
.dw-bar__fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, rgba(74, 144, 226, 0.85), rgba(61, 220, 132, 0.85));
}
.dw-bar__value {
  font-size: 11px;
  text-align: right;
  color: var(--text-muted, rgba(255, 255, 255, 0.38));
}

.dw-input {
  width: 100%;
  padding: 9px 12px;
  border: none;
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.07);
  font: inherit;
  font-size: 13px;
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
}
.dw-input::placeholder {
  color: var(--text-muted, rgba(255, 255, 255, 0.38));
}
.dw-input:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.35);
  outline-offset: 1px;
}
.dw-input--search {
  margin-bottom: 4px;
}

.dw-editor {
  display: block;
  width: 100%;
  min-height: 260px;
  padding: 14px 16px;
  border: none;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  font: inherit;
  font-size: 13px;
  line-height: 1.65;
  color: var(--text-primary, rgba(255, 255, 255, 0.92));
  resize: none;
}
.dw-editor:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.3);
  outline-offset: 1px;
}

.dw-chat {
  display: flex;
  flex-direction: column;
  gap: 14px;
  height: 100%;
}
.dw-chat__thread {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
}
.dw-bubble {
  max-width: 78%;
  margin: 0;
  padding: 11px 14px;
  border-radius: 14px;
  font-size: 13px;
  line-height: 1.5;
}
.dw-bubble--them {
  background: rgba(168, 85, 247, 0.18);
}
.dw-bubble--you {
  align-self: flex-end;
  background: rgba(255, 255, 255, 0.08);
}
.dw-chat__compose {
  display: flex;
  flex: 0 0 auto;
  gap: 8px;
}

.dw-spaces {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px;
}
.dw-space {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px;
  border: none;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  font: inherit;
  text-align: left;
  color: inherit;
  cursor: pointer;
  transition: background-color 140ms linear;
}
.dw-space:hover {
  background: rgba(255, 255, 255, 0.11);
}
.dw-space__label {
  font-size: 14px;
}
.dw-space__note {
  font-size: 11px;
  color: var(--text-secondary, rgba(255, 255, 255, 0.6));
}

/* --------------------------------------------------- reduced motion --- */

@media (prefers-reduced-motion: reduce) {
  .dl-app,
  .desk-tray,
  .desk-window__btn,
  .desk-window.is-shifting,
  .desk-window.is-settling,
  .desk-window.is-morphing,
  .desk-tray__app,
  .desk-snap-hint {
    transition: none;
  }
  .desk-tray__app.is-landing {
    animation: none;
  }
}
