/* ---------- Reset & viewport lock ---------- */
* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  height: 100%;
  overflow: hidden; /* static viewport — the page never scrolls */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* ---------- Desktop background ----------
   Blurred sky-to-grass photo, extracted from the supplied content/desktop-bg.svg
   (the SVG embeds it as a 701x438 raster; assets/desktop-bg.jpg is that image).
   Replaces the CSS mesh gradient used up to 2026-08-06. The gradient underneath
   is a fallback so the desktop is never bare while the image loads. */
.desktop {
  position: relative;
  width: 100vw;
  height: 100dvh;
  overflow: hidden;
  background-color: #9fc46a;
  /* One of six wallpapers, picked per page load by js/main.js, which sets
     --desktop-bg. The url() here is the fallback for the frame before the
     script runs (and if it never does), so the desktop is never bare. */
  background-image: var(--desktop-bg, url("../assets/desktop-bg-1.webp"));
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* Shared chrome tokens for the desktop furniture (header + dock), sampled
   from the design: cream fill, pure-black hairline, 10px corners. */
:root {
  --os-chrome: #F5F4F0;
  --os-line: #000000;
  --os-radius: 10px;
  --plum-red: #FF4052;

  /* The clear band a window may occupy: below the top bar, above the dock.
     Windows cap their height against this so they can never tuck under the
     dock on a short viewport. Keep in sync if the bar or dock is resized. */
  --topbar-bottom: 39.1px;             /* flush to the top (2026-08-08) + 39.1px chip (chip scaled 1.15x, 2026-08-07) */
  --dock-top: calc(1.6vh + 72.25px);   /* lower inset + 61.2px bar + ~11px icon overhang, all 85% of the 2026-08-07 scale (2026-08-08) */
  --desk-band: calc(100vh - var(--topbar-bottom) - var(--dock-top) - 20px);

  /* Literal gap between the two bars' own boxes (dock's 3.2vh inset + 72px
     bar, no icon-overhang buffer, no --desk-band's extra 20px margin) — used
     to vertically centre a window with genuinely equal padding to each bar.
     --desk-band deliberately over-reserves (buffer + margin) for the height
     CAP, which is the right call there, but using it for centring math
     produces unequal padding since that reserve isn't evenly distributed.
     Kept in sync with the dock's own bottom/height whenever those change
     (2026-08-08: bottom 3.2vh -> 1.6vh, bar 72px -> 61.2px). */
  --nav-gap: calc(100vh - var(--topbar-bottom) - 1.6vh - 61.2px);
}

/* ---------- Top bar ----------
   2026-08-07 (one complete nav): per the supplied reference
   (`Group 1000004601.svg`), the whole bar is ONE continuous strip of
   edge-sharing segments — flat top edge running the full width, each
   segment rounding only its own bottom two corners, borders collapsed so
   no seam is ever doubled. This replaces the 2026-08-06 "two pills with a
   gap" version. `.topbar-group` no longer draws a box (`display: contents`)
   so all 7 chips — brand, nav, wifi, bluetooth, volume, weather, clock —
   lay out as one flat flex row; `.topbar-nav` flex-grows to swallow the
   space between the brand and the status cluster, exactly like the
   reference's huge (108→1423 of 1784px) nav segment. Every dimension below
   is the pre-existing value × 1.15 (top-nav scale-up, also 2026-08-07). */
.topbar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9500;
  display: flex;
  align-items: stretch;
  gap: 0;
  pointer-events: none;   /* the desktop stays draggable around it */
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

/* No box of its own — its children (chips) become direct flex items of
   .topbar, so the whole bar is one flat row with no group-level gap. */
.topbar-group { display: contents; }

.topbar-chip {
  display: flex;
  align-items: center;
  gap: 6.9px;
  height: 39.1px;
  padding: 0 11.5px;
  background: var(--os-chrome);
  border: 1px solid var(--os-line);
  /* Flat: square on all four corners. The bar used to round its bottom
     corners (0 0 10.35px 10.35px) per the original reference; it now ends in
     a straight edge. The 1px dividers BETWEEN segments stay — flattening was
     about the silhouette, not the segmentation. */
  border-radius: 0;
  font-size: 14.375px;
  font-weight: 600;
  color: #000;
  white-space: nowrap;
  pointer-events: auto;   /* re-enable clicks; .topbar-group no longer can */
  margin-left: -1px;      /* collapse this chip's left border into the
                              previous chip's right border (1px overlap) */
}
/* The very first chip in the bar has no previous border to collapse into. */
.topbar-brand { margin-left: 0; }

/* Supplied drawn wordmark (content/plum-logo.svg, 74x24) — not typeset.
   Needs .topbar-chip in the selector to outrank the status-icon svg rule
   below, which otherwise wins on source order at equal specificity. */
.topbar-brand { padding: 0 17.25px; text-decoration: none; }
.topbar-chip.topbar-brand svg { display: block; width: 66.7px; height: auto; }

/* Flex-grows to fill the space between the brand and the status cluster —
   this is what makes the bar read as one continuous strip instead of two
   clusters with a gap between them. Tabs stay left-aligned within it. */
.topbar-nav { gap: 16.1px; padding: 0 13.8px; flex: 1 1 auto; }

.topbar-icon { padding: 0; width: 39.1px; justify-content: center; }
/* The supplied status glyphs are not square (wifi 22x17, bluetooth 11x21,
   volume 24x18, weather 22x22), so a fixed square would squash them. Size by
   HEIGHT and let width follow the ratio — which needs the intrinsic width/
   height attributes kept on each <svg> in index.html: without them an inline
   SVG has no natural size, and the weather glyph (the only one in a chip that
   also holds text, so no fixed-width parent to inherit from) collapsed to 0. */
.topbar-chip svg { width: auto; height: 17px; display: block; }
.topbar-clock { font-variant-numeric: tabular-nums; }

@media (max-width: 1100px) { .topbar-weather { display: none; } }
@media (max-width: 940px)  { .topbar-nav { display: none; } }

/* ---------- Top-bar marketing mega-menus ----------
   Namespaced `topbar-mm-*` (not the shorter `tb-` — see the 2026-08-06 collision
   note above about `tb-*` clashing with the doc-editor toolbar; every class here
   lives under the already-safe `topbar-` prefix). One menu open at a time,
   closes on outside click — same interaction contract as the pllm "+" menu in
   components/pllm/pllm.js. Panels sit inside .topbar's own stacking context
   (position:absolute + z-index:9500 on .topbar), so they render above every
   window (dynamic z-index starting at 100) and the dock (9000) without needing
   a huge z-index of their own. */
.topbar-mm { position: relative; }

.topbar-mm-trigger {
  background: none;
  border: 0;
  /* Negative inline margin cancels the pill's own padding, so adding the
     open-state highlight below doesn't shift the row's spacing or widen the
     nav chip — the label sits exactly where it did with padding: 0. */
  padding: 5.75px 10.35px;
  margin: 0 -10.35px;
  border-radius: 8.05px;
  font: inherit;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 14.375px;
  font-weight: 600;
  color: #000;
  cursor: pointer;
}
.topbar-mm-trigger:hover { opacity: .6; }
/* Open menu: the trigger takes a filled pill rather than fading out, so it
   reads as the selected section while its panel is down. */
.topbar-mm.is-open .topbar-mm-trigger {
  opacity: 1;
  background: #DFDDD4;
}

.topbar-mm-panel {
  position: absolute;
  top: calc(100% + 9.2px);
  left: 0;
  display: none;
  background: var(--os-chrome);
  border: 1px solid var(--os-line);
  border-radius: 11.5px;
  box-shadow: 0 20.7px 46px rgba(0, 0, 0, .18);
  z-index: 10; /* only needs to beat sibling chips inside .topbar's own stack */
  pointer-events: auto; /* the panel hangs below the chip, outside .topbar-group's box */
}
/* Base hidden state stays `display: none` until `.is-open` sets the panel's
   OWN display (block for the product card, flex for the flat list) — setting
   `display` unconditionally on `--flat`/`--product` would tie with the base
   rule's specificity and win by source order, showing every panel at once. */
.topbar-mm.is-open .topbar-mm-panel--product { display: block; }
.topbar-mm.is-open .topbar-mm-panel--flat { display: flex; }

/* Experience / Solutions / Explore / Company. Structurally identical to
   Product's category column: the links sit in a `.topbar-mm-cats` box and
   are styled by the `.topbar-mm-cat` rules below, which the flat anchors
   join by selector. Only two things differ, and both are Product-specific
   values that have to relax here — the box's fixed 239.2px width (it is one
   of two columns there, the whole panel here) and the panel's flex gap. */
.topbar-mm-panel--flat {
  width: 257.6px;
  padding: 6.9px;
  flex-direction: column;
  gap: 0;
}
.topbar-mm-panel--flat .topbar-mm-cats { width: auto; }

/* Product — bordered card split into two equal-height boxed columns: category
   rows on the left, that category's links on the right. */
.topbar-mm-panel--product { width: 690px; padding: 11.5px; }
.topbar-mm-cols { display: flex; align-items: stretch; gap: 11.5px; }

.topbar-mm-cats {
  flex: none;
  width: 239.2px;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--os-line);
  border-radius: 9.2px;
  overflow: hidden;
}
/* Row treatment shared by Product's category buttons and the four flat
   panels' links, so every menu in the bar reads identically. The flat
   anchors need `text-decoration: none` on top; everything else already
   matches, and `justify-content: space-between` is inert on a row with no
   chevron. */
.topbar-mm-cat,
.topbar-mm-panel--flat .topbar-mm-cats a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  text-align: left;
  text-decoration: none;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--os-line);
  padding: 14.95px 16.1px;
  font-family: inherit;
  font-size: 14.375px;
  font-weight: 600;
  color: #000;
  cursor: pointer;
}
.topbar-mm-cat:last-child,
.topbar-mm-panel--flat .topbar-mm-cats a:last-child { border-bottom: 0; }
.topbar-mm-cat:hover,
.topbar-mm-cat.is-active,
.topbar-mm-panel--flat .topbar-mm-cats a:hover { background: #E7E5DF; }

/* Right-pointing chevron (supplied Icon (3).svg), one per category row —
   the "arrow" from the reference screenshot's Product sub-menu.
   Needs `.topbar-mm-cat` in the selector to outrank `.topbar-chip svg`
   (0,1,1 specificity), which otherwise wins on source order and forces
   every chevron to the 17.25px status-icon size. */
.topbar-mm-cat .topbar-mm-cat-arrow { flex: none; width: 5.75px; height: 10.35px; }

.topbar-mm-links {
  flex: 1;
  border: 1px solid var(--os-line);
  border-radius: 9.2px;
  padding: 9.2px;
}
.topbar-mm-linkset { display: none; flex-direction: column; gap: 1.15px; }
.topbar-mm-linkset.is-active { display: flex; }
.topbar-mm-linkset a {
  display: block;
  padding: 9.2px 11.5px;
  border-radius: 6.9px;
  color: #000;
  text-decoration: none;
  font-size: 14.375px;
  font-weight: 500;
}
.topbar-mm-linkset a:hover { background: #E8E6E0; }

/* ---------- Draggable windows ---------- */
.window {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  cursor: grab;
  touch-action: none; /* pointer events handle dragging */
  will-change: left, top;
}

.window.dragging { cursor: grabbing; }

/* Put away — reopened from the dock. */
.window.is-hidden { display: none; }

/* Only while animating into/out of the dock, so the transition never fights
   dragging (which writes --x/--y every pointermove). */
.window.is-animating {
  transition: transform .3s cubic-bezier(.4, 0, .55, 1), opacity .3s ease;
  pointer-events: none;
  will-change: transform, opacity;
}
@media (prefers-reduced-motion: reduce) {
  .window.is-animating { transition: none; }
}

/* Traffic lights injected by js/main.js into windows whose own title bar has
   none (Slack). Windows that ship their own keep theirs. */
.win-lights { display: flex; gap: 6px; flex: none; align-items: center; margin-right: 4px; }
.win-lights i {
  display: block;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1px solid #000;
}
.win-lights i:nth-child(1) { background: #FF8875; }
.win-lights i:nth-child(2) { background: #FFE78E; }
.win-lights i:nth-child(3) { background: #94E9BC; }

/* Every traffic-light cluster (this file and per-component CSS) is one hit
   target — js/main.js wires the whole cluster to close the window, matching
   .doc-dismiss's single-button behavior. Shared hover affordance so that's
   visible everywhere consistently. */
.pllm-lights:hover,
.flyer-lights:hover,
.folder-lights:hover,
.vv-lights:hover,
.br-lights:hover,
.talk-lights:hover,
.win-lights:hover { opacity: 0.75; }

.window img {
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* browser-frame.png ships its own baked-in glow, so shadows are per-window */
.shadow-soft { filter: drop-shadow(0 18px 40px rgba(60, 40, 80, 0.18)); }
.shadow-deep { filter: drop-shadow(0 24px 60px rgba(60, 40, 80, 0.28)); }

/* ---------- Desktop folders (old, unused — kept per the 2026-08-06 note that
   a return of desktop icons might reuse it; 2026-08-07's icons ended up
   needing labels + mixed aspect ratios instead, so .desktop-icon below is a
   fresh class rather than an extension of this one) ---------- */
.folder {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: clamp(44px, 3.4vw, 72px);
  cursor: grab;
  touch-action: none;
  filter: drop-shadow(0 6px 12px rgba(60, 40, 80, 0.20));
}

.folder.dragging { cursor: grabbing; }

.folder svg {
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
  user-select: none;
}

/* ---------- Desktop icons: rejects folder, product image, embedded videos.
   Draggable; some open a window on click via data-window (see
   js/main.js). Idle cursor stays default — only .dragging switches it to a
   grab cursor, so hovering an icon doesn't imply it's movable. ---------- */
.desktop-icon {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--w);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  cursor: default;
  touch-action: none;
  filter: drop-shadow(0 6px 12px rgba(0, 0, 0, 0.18));
}

.desktop-icon.dragging { cursor: grabbing; }

/* img as well as svg: the AI Secure.mp4 icon is an external file rather than
   inline markup (its export wraps a raster, and index.html ships as one raw
   string — see the comment on that icon). pointer-events: none is the
   load-bearing half — without it a pointerdown that lands on the artwork is
   targeted at the image, and the drag/tap handler in js/main.js is bound to
   the .desktop-icon wrapper. */
.desktop-icon svg,
.desktop-icon img {
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
  user-select: none;
}

.desktop-icon-label {
  max-width: 92px;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 12px;
  font-weight: 600;
  color: #16161f;
  text-align: center;
  text-shadow: 0 1px 2px rgba(255, 255, 255, .85), 0 0 6px rgba(255, 255, 255, .6);
  user-select: none;
  pointer-events: none;
}

/* ---------- Dock / taskbar ----------
   Hairline cream bar; the illustrated icons are taller than the bar and rise
   above its top edge, as in the design. Sized to its content rather than a
   fixed width so it stays centred whatever the icon count. */
.dock {
  position: absolute;
  left: 50%;
  bottom: 1.6vh;              /* lower than before (was 3.2vh), 2026-08-08 */
  transform: translateX(-50%);
  z-index: 9000;
  display: flex;
  align-items: flex-end;
  gap: 18.7px;                /* 85% of 22px, 2026-08-08 */
  height: 61.2px;              /* 85% of 72px */
  padding: 0 22.1px 11.9px;   /* 85% of 26px/14px */
  border-radius: var(--os-radius);
  background: var(--os-chrome);
  border: 1px solid var(--os-line);
  overflow: visible;      /* icons deliberately overhang the top edge */
}

.dock-item {
  position: relative;
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  line-height: 0;
  transition: transform .16s ease;
}

.dock-item svg {
  display: block;
  height: 59.5px;              /* 85% of 70px, 2026-08-08 */
  width: auto;
  pointer-events: none;
  filter: drop-shadow(0 3px 5px rgba(0, 0, 0, .16));
}

.dock-item:hover { transform: translateY(-5.1px); }
.dock-item:active { transform: translateY(-1px); }

/* Running indicator — the small pill under the icon. Present whenever the
   window is open (like macOS), darker when it is also the frontmost one. */
.dock-item .dot {
  position: absolute;
  left: 50%;
  bottom: -8.5px;              /* 85% of -10px, 2026-08-08 */
  transform: translateX(-50%);
  width: 22.1px;
  height: 4.25px;
  border-radius: 2.125px;
  background: transparent;
  transition: background .16s ease;
}

.dock-item.is-open .dot { background: #9A9A9A; }
.dock-item.is-open.active .dot { background: #454545; }

/* Name shown on hover — the icons alone would lose the window titles */
.dock-item .dock-label {
  position: absolute;
  bottom: calc(100% + 8.5px);
  left: 50%;
  transform: translateX(-50%);
  padding: 4.25px 9.35px;
  border-radius: 6.8px;
  background: var(--os-chrome);
  border: 1px solid var(--os-line);
  font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 11.73px;
  font-weight: 600;
  line-height: 1.2;
  color: #000;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .14s ease;
}

.dock-item:hover .dock-label,
.dock-item:focus-visible .dock-label { opacity: 1; }

/* ---------- Status-chip notes ----------
   Wi-Fi / Bluetooth / Volume / Weather / Clock each open a small card saying
   what the indicator "really" means. Same interaction contract as the
   mega-menus above (one open at a time, outside click closes, Escape closes)
   and the same panel treatment, so the bar reads as one system.

   Desktop only in effect, with no breakpoint of its own: css/mobile.css
   already hides .topbar-icon, .topbar-weather and .topbar-clock on phones,
   so there is nothing left to click there. */
.topbar-status { position: relative; cursor: pointer; font: inherit; }
.topbar-status[aria-expanded="true"] { background: #DFDDD4; }

.topbar-status-panel {
  position: absolute;
  top: calc(100% + 6px);
  /* Anchored to the chip's RIGHT edge: these sit at the end of the bar, and
     a left-anchored card would run off the viewport on the clock. */
  right: -1px;
  z-index: 10;
  display: none;
  flex-direction: column;
  gap: 12px;
  width: 232px;
  padding: 13.8px 16.1px;
  background: var(--os-chrome);
  border: 1px solid var(--os-line);
  border-radius: 10.35px;
  box-shadow: 0 20.7px 46px rgba(0, 0, 0, .18);
  font-size: 13.225px;
  font-weight: 500;
  line-height: 1.35;
  color: #000;
  text-align: left;
  white-space: normal;   /* .topbar-chip sets nowrap for the bar itself */
  cursor: default;
}
.topbar-status[aria-expanded="true"] .topbar-status-panel { display: flex; }

/* ---------- Boot entrance ----------
   The doc arrives ~700ms after load (js/main.js), and this is how. Desktop
   gets a plain fade: the window is already centred, so anything positional
   would read as a second, competing motion next to the wallpaper settling.
   css/mobile.css overrides the same class with a slide up from the bottom
   edge, which is the phone idiom. Distinct from .is-animating, which is the
   genie scale a DOCK click plays. */
@keyframes boot-fade { from { opacity: 0; } to { opacity: 1; } }

.window.is-booting {
  animation: boot-fade .42s ease-out both;
  will-change: opacity;
}

@media (prefers-reduced-motion: reduce) {
  .window.is-booting { animation: none; }
}
