/* Pekan OS 2031, round 6 wave 3: visual craft.

   An independent design review said the narrative was excellent and the
   pixels were not. This sheet is the pixels. It is craft only: no features,
   no copy, no funnel logic. Every rule here answers a number that was
   measured in the running browser before it was written, and the numbers
   are recorded in docs/evidence/round6/craft.md.

   WHY A SEPARATE SHEET. pekan/os2031.css owns the tokens and the grammar,
   and pekan/authenticity.css is being extended by another agent in the same
   round. This sheet loads after both, restates nothing either of them got
   right, and only lands where a measurement said the painted result was
   wrong. That keeps three agents out of each other's diffs.

   THE LIGHT MODEL, stated once and obeyed everywhere.
   One sun, high and slightly to the left, at roughly 11 o'clock. Therefore:
     every drop shadow has a positive Y and a zero or slightly positive X,
     every lit edge is the TOP edge and it is an inset highlight,
     every surface gets TWO drop layers, a tight contact shadow that says
     where the object touches and a wide ambient shadow that says how far it
     floats, and the ambient is always the lower alpha of the two.
   A surface that floats higher gets more Y, more blur, and more spread on
   the ambient, never a darker contact.

   Measured before: 11 elements carried a drop shadow, only 3 of them had
   two layers, and only 1 of the 14 blurred surfaces carried a top rim. The
   whole point of the depth system was therefore invisible.

   No em dashes anywhere in this file. */

/* ===========================================================================
   1. THE LIGHT AND DEPTH SCALE

   Four steps. Each is a two layer shadow on the one light direction, and
   each carries the rim highlight that belongs to its depth. The rim is a
   separate token so a surface that must draw its own rim on a child (a
   window draws it on the title bar, because the window clips) can reach it.

   The ambient blur roughly triples between steps while the contact shadow
   grows slowly. That ratio is what reads as height rather than as darkness.
   =========================================================================== */
:root {
  /* the light, declared so a future rule cannot quietly disagree with it */
  --os-light-x: 0;
  --os-light-deg: 11;

  /* ROUND 11. Every token below is an alias onto the glass recipe declared
     in pekan/os2031.css. This sheet used to carry its own copy of the scale
     and the two copies disagreed by a few points at every depth, which is
     one of the reasons the owner saw a set of unrelated panels rather than
     one material. The names stay so the rules below read as they did; the
     numbers live in one place. */

  /* rim highlights: the top edge catching the sun */
  --rim-1: var(--glass-rim-1);
  --rim-2: var(--glass-rim-2);
  --rim-3: var(--glass-rim-3);
  --rim-4: var(--glass-rim-4);

  /* the outer dark hairline that stops glass dissolving into the wallpaper.
     Drawn as a shadow rather than a border so it never eats layout. */
  --hair: var(--glass-edge);

  /* depth 1.5: a resting object on the desk. Desktop icon well, dock tile. */
  --sh-1: var(--glass-shadow-rest);
  /* depth 2: floating. Dock, sticky note, inactive window. */
  --sh-2: var(--glass-shadow);
  /* depth 2 focused: the window that is listening. */
  --sh-2f: var(--glass-shadow-focus);
  /* depth 3: lifted clear. Menus, sheets, dialogs, toasts. */
  --sh-3: var(--glass-shadow-lift);
  /* depth 4: modal over everything. */
  --sh-4: var(--glass-shadow-modal);

  /* the neutral ramp, finding 9. Four genuine elevation steps rather than
     four surfaces within a few points of each other. Each step is a real
     lightness move so a sidebar, a header and a content area separate
     without a border doing the work. */
  --el-0: #0E0B14;   /* sunk: app background, table well */
  --el-1: #14111C;   /* base: content area */
  --el-2: #1B1726;   /* raised: header, sidebar */
  --el-3: #232032;   /* raised more: hovered row, active tab */
  --el-4: #2C2840;   /* highest: selected row, pressed control */
}

/* under a reduced transparency preference the shadows stay (they are not
   the expensive part) but they tighten, because a flat surface with a huge
   ambient shadow reads as a sticker */
@media (prefers-reduced-transparency: reduce) {
  :root {
    --sh-2: 0 2px 6px rgba(0, 0, 0, 0.42), 0 10px 26px rgba(0, 0, 0, 0.34);
    --sh-2f: 0 3px 9px rgba(0, 0, 0, 0.46), 0 18px 42px rgba(0, 0, 0, 0.42);
    --sh-3: 0 3px 10px rgba(0, 0, 0, 0.48), 0 20px 48px rgba(0, 0, 0, 0.44);
  }
}

/* ===========================================================================
   2. REAL GLASS

   Finding 2 said there is no glass. Measured: the Task Manager painted
   backdrop-filter blur(20px) saturate(1.35), so blur existed, but it
   carried no rim, no outer hairline, and nothing readable sat behind it,
   so the effect was invisible and the panel read as a flat slab.

   Real glass here is four things at once:
     blur plus a saturation lift, so colour behind it survives,
     a 1px inner light stroke along the TOP edge only,
     a 1px outer dark hairline so the panel has an edge against a bright
       patch of aurora,
     and a fine noise film over the blur, because a wide blur of a near
       black gradient banks into visible steps without one.

   The noise is a 96px tiled SVG at 3.5 percent, drawn on a ::before that is
   pinned to the surface and cannot take pointer events. It is applied by an
   explicit class list rather than a wildcard so nothing pays for it twice.
   =========================================================================== */
/* NOTE ON POSITION. An earlier draft of this rule set position: relative on
   the list below so the noise pseudo element would have something to anchor
   to. That was a real bug and the browser caught it: #dock-box and .msg are
   position: fixed, and relative took them out of fixed positioning, which
   dropped the dock to the top of the document. Measured: dock y went from
   824 to -12.

   Every surface in this list is already positioned by the shell (fixed or
   absolute), so the pseudo element has an anchor without help. This rule
   therefore sets isolation only, which is what the blend mode needs, and
   never touches position. */
.window,
#dock-box,
#os-menubar,
#start-menu,
#cm,
#dp,
.os-note,
.pk-toast,
#notice,
#os-note-undo,
#os-setup .card,
#loginback > .lock-core,
.clut-dlg,
.msg.update {
  isolation: isolate;
}

.window::before,
#dock-box::before,
#start-menu::before,
#cm::before,
.os-note::before,
.pk-toast::before,
#notice::before,
#os-note-undo::before,
#os-setup .card::before,
#loginback > .lock-core::before,
.clut-dlg::before,
.msg.update::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  opacity: 0.55;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='96' height='96'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.035 0'/></filter><rect width='100%' height='100%' filter='url(%23g)'/></svg>");
  background-repeat: repeat;
  mix-blend-mode: overlay;
}

/* a maximised window has no floating edge, so it takes no film and no rim */
.window.max::before { display: none; }

/* ===========================================================================
   3. THE FLOATING SURFACES, one by one, on the one light direction

   Each rule below sets: two drop layers, the outer hairline, and the rim
   that belongs to the depth. Where os2031.css or authenticity.css already
   used an !important on box-shadow, this sheet answers in kind, because
   that is the only way a later rule lands. Every other rule is plain
   specificity.
   =========================================================================== */

/* windows. Depth 2, and the focused one is the only thing that rises.
   A window clips its own overflow at the 10px radius, so the rim is drawn
   on the title bar (which is the window's top edge) and the hairline plus
   the two drop layers are drawn on the frame. */
/* ONE outer stroke. The white 1px border IS the edge of the glass; the
   old --hair ring drew a second, darker outline immediately outside it,
   which is the doubled border the pixel review reported on the dock and
   the window. The hairline now survives only where there is no border
   (see the depth 3 block below). */
.window:not(.foc),
:root.mica .window:not(.foc) {
  box-shadow: var(--sh-2), var(--glass-inner) !important;
}

.window.foc,
:root.mica .window.foc {
  box-shadow: var(--sh-2f), var(--glass-inner) !important;
}

/* the title bar is the lit top edge of the glass. It also has to carry the
   blur, or the bar reads as an opaque strip laid on a translucent box. */
.window > .titbar,
.window.webapp > .titbar,
.window.webapp.foc > .titbar,
.window.chrome > .titbar,
:root.mica .window.webapp > .titbar,
:root.mica .window.webapp.foc > .titbar {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.028)) !important;
  box-shadow: var(--rim-3);
  backdrop-filter: blur(var(--g2-blur)) saturate(var(--g2-sat));
  -webkit-backdrop-filter: blur(var(--g2-blur)) saturate(var(--g2-sat));
}

.window:not(.foc) > .titbar {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.042), rgba(255, 255, 255, 0.016)) !important;
  box-shadow: var(--rim-1);
}

.window.max > .titbar { box-shadow: none; }

/* the dock. Depth 2. One border, one top light, one drop. The --hair ring
   and --rim-3 both ran here as well as --glass-inner's own top inset, which
   is three light strokes stacked on a 1px edge. */
#dock-box {
  box-shadow: var(--sh-2), var(--glass-inner);
}

/* the status pill and the system bar. The pill is depth 3 because it
   floats over everything; the bar it lives in is a depth 2 shelf. */
#os-menubar {
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.45), 0 8px 26px rgba(0, 0, 0, 0.22), var(--rim-2);
}

/* The status pill.

   NOTE, and this one matters for coordination: the markup agent moved the
   pill INSIDE the system bar in wave 2 (authenticity.css line 421,
   "#os-menubar #os-halo { position: static; background: none; box-shadow:
   none }"). That is a deliberate and correct decision: a pill floating over
   the wallpaper next to a bar that also spans the top is two status
   surfaces, and one is right.

   So the pill does not get its own glass while it lives in the bar. The
   BAR carries the glass, the rim and the shadow, and the pill is a region
   inside it. Giving the pill a second shadow here would draw a box around a
   box, which is exactly the kind of thing the review was calling out.

   The rule below therefore only applies when the pill is NOT in the bar,
   which is the lock screen and any state where the bar is hidden. */
#os-halo:not(#os-menubar #os-halo) {
  box-shadow: var(--sh-3), var(--rim-4);
}

/* inside the bar it takes a quiet separator instead, so the status group
   still reads as a group without becoming a second floating island */
#os-menubar #os-halo {
  box-shadow: none;
}

/* sticky notes stay paper. Do not put glass rims or a noise film on them. */
.os-note {
  background: var(--note-bg, #F4D35E);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.18), 0 12px 28px rgba(0, 0, 0, 0.28);
}

.os-note.foc {
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.22), 0 16px 36px rgba(0, 0, 0, 0.28);
}

.os-note::before {
  display: none;
}

.os-note::after {
  display: none;
}

/* a folded corner, the one cheap tell that this is paper */
.os-note {
  background-image: linear-gradient(-36deg, rgba(0, 0, 0, 0.12) 9px, transparent 9px);
  background-repeat: no-repeat;
  background-position: 100% 0;
  background-size: 18px 18px;
}

/* depth 3: everything that is lifted clear of the desk. Same single
   stroke discipline as depth 2: the surface's own border is the edge. */
#start-menu,
#cm,
#dp,
.pk-toast,
#notice,
#os-note-undo,
#open-dock,
.clut-dlg {
  box-shadow: var(--sh-3), var(--glass-inner);
}

/* the desktop edit bar. It was the one floating surface still carrying
   the shell's original 3px 3px offset shadow, which is light from the top
   LEFT and therefore disagreed with every other surface in the OS. It is a
   depth 3 toolbar. */
#desktop-editbar {
  box-shadow: var(--sh-3), var(--rim-3);
}

/* form controls inside a glass dialog. A field is sunk, not floating,
   so it takes an inset shadow rather than a drop shadow. The clutter dialog
   inputs were painting a flat 0 0 0 ring, which reads as neither. */
.clut-input,
.clut-dlg input,
.clut-dlg textarea {
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.35), inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}

.clut-input:focus-visible,
.clut-dlg input:focus-visible {
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.35), 0 0 0 6px var(--os-focus-halo);
}

/* the primary button in a dialog is a raised control, so it takes the
   resting two layer shadow rather than a single tight one */
.clut-btn.clut-pri,
.msg .a.btn.main {
  box-shadow: var(--sh-1);
}

/* depth 4: modal. The lock card and the setup assistant are the only
   two things that stop the whole OS, so they are the only two here. */
#loginback > .lock-core,
#os-setup .card {
  box-shadow: var(--sh-4), var(--glass-inner), inset 0 -1px 0 rgba(0, 0, 0, 0.26);
}

/* Round 9. The lock card is the first surface anyone sees, so it gets the
   specular sweep the flat depth 4 rim cannot give it: one soft highlight down
   the top left shoulder, over the glass and under the content.

   It rides background-image rather than a pseudo element on purpose. Both of
   this card's pseudo elements are already spent on the grain film, ::before
   here at line 147 and ::after in os2031.css at 1308, and a third layer would
   have to take one of them away. */
/* Round 9. DO NOT "fix" flat lock glass by raising the card's backdrop-filter.
   Measured: the region behind it had sd 1.09/255, so blur 44px and blur 4px
   gave identical pixels. There was nothing to transmit. This aurora is the
   light the glass reads; evidence in docs/evidence/round9/lock/GLASS.md.
   ::after because ::before is login.css's contrast-measured vignette. */
#loginback::after {
  content: ""; position: fixed; inset: -12%; z-index: 0; pointer-events: none;
  background:
    radial-gradient(40% 36% at 20% 22%, rgba(150, 105, 255, 0.70), rgba(150, 105, 255, 0) 66%),
    radial-gradient(36% 32% at 82% 72%, rgba(78, 195, 255, 0.56), rgba(78, 195, 255, 0) 64%),
    radial-gradient(30% 26% at 68% 8%, rgba(255, 110, 190, 0.36), rgba(255, 110, 190, 0) 68%),
    radial-gradient(34% 30% at 8% 82%, rgba(96, 235, 200, 0.30), rgba(96, 235, 200, 0) 66%);
  animation: pk-aurora 46s ease-in-out infinite alternate;
  will-change: transform;
}
/* One slow drift on one compositor layer. It is a transform, never a
   background-position, so the aurora does not repaint the gradients each
   frame: that was measurably the difference between a free ride and a
   constant repaint behind every glass surface on the screen. */
@keyframes pk-aurora {
  from { transform: translate3d(-1.6%, -1.1%, 0) scale(1.02); }
  to   { transform: translate3d(1.8%, 1.4%, 0) scale(1.07); }
}
/* the horizon: one wide band low on the screen, the way a utopian skyline
   sits under a sky rather than floating in it */
#loginback::before {
  background:
    radial-gradient(ellipse 78% 62% at 50% 46%, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 44%, rgba(6, 4, 12, 0.42) 82%, rgba(6, 4, 12, 0.62) 100%),
    linear-gradient(0deg, rgba(150, 120, 255, 0.16) 0%, rgba(150, 120, 255, 0) 26%);
}
@media (prefers-reduced-motion: reduce) {
  #loginback::after { animation: none; }
}
/* Round 9. NOT redundant with the card's backdrop-filter. Measured: 0.96% of
   pixels along the card's top and right edge carried a ghost of the desktop
   filenames, because backdrop-filter samples outside its own box at the
   border. Raising fill opacity does not fix it (tested to 0.42); filtering the
   source does. See docs/evidence/round9/lock/GLASS.md. */
body.locked #desktop {
  filter: blur(7px) saturate(0.9);
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  body.locked #desktop { filter: blur(7px) saturate(0.9); }
}
#loginback > .lock-core {
  position: relative; z-index: 1;
  background-image:
    linear-gradient(180deg, rgba(255, 255, 255, 0.20) 0, rgba(255, 255, 255, 0) 2px),
    radial-gradient(120% 90% at 12% -10%, rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0) 58%),
    linear-gradient(160deg, rgba(168, 148, 255, 0.10) 0%, rgba(255, 255, 255, 0) 46%);
  /* scoped to this card, NOT --g3-a: that token dresses 27 surfaces across six
     files, and the wallpaper only needs to show through the one card in front
     of it. Thinner fill plus deeper blur is what gives the glass thickness. */
  background-color: rgba(var(--g3-rgb), 0.16);
  backdrop-filter: blur(var(--glass-blur-modal)) saturate(var(--glass-sat-modal)) brightness(1.06);
  -webkit-backdrop-filter: blur(var(--glass-blur-modal)) saturate(var(--glass-sat-modal)) brightness(1.06);
}
@media (prefers-contrast: more), (prefers-reduced-transparency: reduce) {
  #loginback > .lock-core {
    background-color: rgba(var(--g3-rgb), 0.97);
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
}

/* ===========================================================================
   4. FINDING 7: the radii tokens, actually painted

   Measured before, by getComputedStyle on visible boxes: 18 distinct radii
   were painted, including 20px on the update message, 15px on its button,
   and 9px, 4px and 3px on document icon artwork. Plan 4.2 defines the whole
   set. Every stray below is pulled onto a token.
   =========================================================================== */

/* WHY THESE SELECTORS CARRY :root.corner_squ.

   The shell ships an appearance switch, corner_squ, which is on by default
   in this build (measured: documentElement.className is "mica corner_squ").
   Every one of its rules is written as ":root.corner_squ X", specificity
   0,2,0 or better, and it repaints 20px and 15px over the plan's table.
   os2031.css already took the window, the menu and the dock back from that
   switch; the surfaces below were the ones it did not reach.

   Matching the switch's own specificity is the honest way past it. No
   !important is used anywhere in this block. */

/* the shell's own update message was a 20px pill with a 15px button inside
   it. It is a system sheet: 12px, with its control on the button token. */
.msg.update,
:root.corner_squ .msg,
:root.corner_squ .msg.update {
  border-radius: var(--os-r-sheet);
}

.msg.update {
  box-shadow: var(--hair), var(--sh-3), var(--rim-4), var(--glass-inner);
  backdrop-filter: blur(var(--g3-blur)) saturate(var(--g3-sat));
  -webkit-backdrop-filter: blur(var(--g3-blur)) saturate(var(--g3-sat));
  background: var(--g3-bg);
  border: var(--g3-border);
}

.msg.update > .main {
  border-radius: var(--os-r-sheet) 0 0 var(--os-r-sheet);
}

/* the notice button painted 15px through the same switch */
.msg .a.btn.main,
.msg.update .a.btn.main,
:root.corner_squ #notice > .btns > .btn,
:root.corner_squ .a.btn.main {
  border-radius: var(--os-r-btn);
}

/* the start menu app tiles and the about panel pills sat at 20px, which is
   not in the table. A tile is a menu row.

   desktop.css line 628 writes this one with an !important
   (":root.corner_squ list > * { border-radius: 20px !important }"), so the
   token can only land by answering in kind. This is the only !important
   this sheet adds that os2031.css had not already been forced into. */
.sm-app.enable,
.sm-app.enable > *:first-child {
  border-radius: var(--os-r-menu);
}

:root.corner_squ list > *,
:root.corner_squ .sm-app {
  border-radius: var(--os-r-menu) !important;
}

/* the About window's update log rows painted 20px through the same switch */
:root.corner_squ #win-about > .update > div > details {
  border-radius: var(--os-r-cta);
}

/* the last two shell strays: the explorer fold control and the start menu
   focus list both painted the shell's own 7px, which is not in the table.
   Both are menu furniture. */
list.focs,
.fold,
list:not(.new) {
  border-radius: var(--os-r-menu);
}

/* the desktop edit bar is a floating toolbar, which is a menu surface */
#desktop-editbar {
  border-radius: var(--os-r-menu) var(--os-r-menu) 0 0;
}

/* icon artwork carried its own baked corners at 9, 4 and 3 px, which is
   what made four icon families read as four families. The RENDER side of
   finding 4 is ours: every icon image is masked to the one icon token so
   the well is identical no matter which pack drew the art. */
#desktop > div.b.clut > img,
#desktop > div > img {
  border-radius: var(--os-r-icon);
}

#dock-box .dock-btn > img,
#dock-box .dock-btn.pin > img,
#dock-box #taskbar > a img {
  border-radius: var(--os-r-icon);
}

/* the Start mark is a brand mark, not an app tile: it keeps a circle so it
   never competes with the pinned row. authenticity.css pins it at 7px with
   the selector "#dock-box .dock-btn#start-btn .pd-mark", so this one has to
   match that weight to land. */
#dock-box .dock-btn#start-btn .pd-mark { border-radius: 50%; }

/* ===========================================================================
   5. FINDING 7 CONTINUED: the dock nesting maths

   Outer radius should equal inner radius plus the padding between them, or
   the corner of the pill and the corner of the first tile disagree.
   Measured before: outer 16, inner 14, padding 7. 14 + 7 = 21, not 16, so
   the tiles bulged into the corner.

   Plan 4.2 pins the dock at 16 and the icon well at 14, and both are
   tokens, so the free variable is the padding: 16 - 14 = 2 would crush the
   dock. The honest resolution is to keep the plan's two radii and set the
   padding so the maths is true at the corner that is visible: the tile well
   is only painted on hover, and the ART inside it is what the eye reads.
   So the art is inset to 40px inside a 50px tile, giving 5px of glass
   around it, and the pill padding drops to 7px vertical with the tile
   itself carrying the remainder. 9 + 7 = 16. The maths now closes on the
   ART box rather than on an invisible well.
   =========================================================================== */
#dock-box {
  /* 7px vertical keeps the 50px tile inside the 64px pill.
     7px horizontal closes the nesting rule on the art box: the corner art
     sits 7px in from the pill edge, so 16 = 9 + 7 exactly. */
  padding: 7px;
}

#dock-box .dock-btn > img,
#dock-box .dock-btn.pin > img {
  /* the art is the visible box, so the art carries the nesting radius.
     outer 16 = art 9 + padding 7. Verified by getComputedStyle in
     docs/evidence/round6/craft.md rather than asserted here. */
  border-radius: 9px;
}

#dock-box #taskbar > a img { border-radius: 9px; }

/* ===========================================================================
   6. FINDING 8: THE DOCK

   Measured before: zero visible separators (the divider existed in markup
   but painted at width 1px against a 0.18 white line that vanished on
   glass), no hover affordance beyond a scale, no running indicator on a
   pinned app that was not in the strip, and the Software Update pill was a
   42px tall 8px radius saturated block inside a dock whose tiles are 50px
   and 14px, which is exactly the foreign object the review described.

   Decision on the pill: RESTYLE, not evict. It is the OS telling you
   something, which is what a dock badge is for, and evicting it would move
   a funnel surface, which is not this dispatch's call. It becomes a proper
   dock item: same 50px tile, same icon token, the accent moves to a badge
   dot rather than a filled block, and the label is dropped because no other
   dock item has one.
   =========================================================================== */

/* the separator has to be visible on glass, so it is a two tone rule: a
   dark line and a light line, which is how a real bevel reads */
#dock-box .dock-divider {
  width: 2px;
  height: 32px;
  margin: 0 7px;
  border-radius: 1px;
  background: linear-gradient(90deg, rgba(0, 0, 0, 0.34), rgba(255, 255, 255, 0.16));
}

/* a dock tile needs a hover well, not only a scale. The well is the icon
   token so it nests with the art inside it. */
#dock-box .dock-btn,
#dock-box .dock-btn.pin,
#dock-box #taskbar > a {
  border-radius: var(--os-r-icon);
  transition: transform 160ms var(--pm-spring), background-color 140ms var(--pm-ease);
}

#dock-box .dock-btn:hover,
#dock-box .dock-btn.pin:hover,
#dock-box #taskbar > a:hover,
#dock-box .dock-btn:focus-visible {
  background-color: rgba(255, 255, 255, 0.10);
}

#dock-box .dock-btn:active,
#dock-box .dock-btn.pin:active {
  transform: scale(1.04);
  background-color: rgba(255, 255, 255, 0.14);
}

/* the icon art sits on the glass rather than floating above it, which is a
   contact shadow on the one light direction */
#dock-box .dock-btn > img,
#dock-box .dock-btn.pin > img,
#dock-box #taskbar > a img {
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45));
}

/* the running indicator: one Pekan dot, same size for every state, and the
   focused app takes a wider bar. It was a thick blue underline that matched
   nothing; it is now the accent at the size a real dock uses. */
#dock-box #taskbar > a::after,
#dock-box .dock-btn.run::after {
  content: "";
  position: absolute;
  bottom: -1px;
  left: 50%;
  transform: translateX(-50%);
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--pm-lavender);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45);
  transition: width 160ms var(--pm-ease), border-radius 160ms var(--pm-ease);
}

#dock-box #taskbar > a.foc::after,
#dock-box .dock-btn.run.foc::after {
  width: 16px;
  border-radius: 2px;
}

/* the Start button. It was a 12px radius white-tinted block with a label,
   which is a Windows Start button standing in a Mac dock. It keeps its
   label (the OS is a Pekan OS, not a Mac clone, and the plan allows the
   Windows sense of order) but it takes the dock's own geometry: the icon
   token, the same 50px height as its neighbours, and a quieter fill so it
   reads as the first item rather than as a foreign control. */
#dock-box #start-btn,
#dock-box .dock-btn#start-btn {
  height: 50px;
  width: 50px;
  min-width: 50px;
  padding: 0;
  gap: 0;
  justify-content: center;
  border-radius: var(--os-r-icon);
  background: rgba(255, 255, 255, 0.055);
  border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow: var(--rim-1);
}

#dock-box #start-btn:hover {
  transform: none;
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.18);
}

/* the Start mark read as a pair of goggles at 22px because the brand mark
   is a wordmark drawn for a much larger size. It goes up to 24 and takes a
   contact shadow so the two counters separate. Same selector weight as the
   authenticity.css rule that sizes it. */
#dock-box .dock-btn#start-btn .pd-mark {
  width: 24px;
  height: 24px;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5));
}

/* Gemini QA: the word Start next to a mark inside a centred floating dock
   was a Windows launcher standing in a Mac bar. The mark is the launcher;
   the word hid on a phone already. Same tile as its neighbours. */
#dock-box #start-btn .start-label {
  display: none;
}

/* the Software Update pill becomes a dock item. Same tile, same well, the
   accent demoted to a badge. */
#dock-box .dock-key {
  width: 50px;
  height: 50px;
  min-width: 50px;
  padding: 0;
  margin-left: 3px;
  border-radius: var(--os-r-icon);
  background: rgba(255, 255, 255, 0.055);
  border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow: var(--rim-1);
  display: grid;
  place-items: center;
  position: relative;
  color: var(--os-text);
  overflow: visible;
}

#dock-box .dock-key:hover {
  transform: none;
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.18);
  color: var(--os-text);
}

#dock-box .dock-key svg {
  width: 22px;
  height: 22px;
  stroke: var(--os-text);
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45));
}

/* the label is dropped from the tile and becomes the tooltip the rest of
   the dock already uses. It stays in the accessibility tree. */
#dock-box .dock-key > span,
#dock-box .dock-key #os-dock-key {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* the badge: this is the one place the accent is allowed to shout, and it
   is 8px across rather than a 158px block */
#dock-box .dock-key::after {
  content: "";
  position: absolute;
  top: 4px;
  right: 4px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--pm-purple);
  box-shadow: 0 0 0 2px rgba(12, 10, 18, 0.85);
}

/* ===========================================================================
   7. FINDING 5: LABEL TYPOGRAPHY

   Measured before: the two line clamp was already in place and every label
   reported exactly 2 lines, so the review's "one, two and three lines" was
   fixed in an earlier wave. What was NOT fixed:
     the clamp uses -webkit-line-clamp, whose ellipsis is a single U+2026
     glyph, but the label also carried text-overflow: ellipsis on a
     -webkit-box, and the interaction renders a CLIPPED ellipsis at some
     widths, which is the "two dots" the review saw. The fix is to let the
     clamp own the truncation and stop the second mechanism fighting it.
     no scrim under the type beyond a text-shadow, which fails on the
     brightest patch of the aurora,
     no optical tracking, so 11px white on near black bloomed.
   =========================================================================== */
#desktop > div.b.clut > p,
#desktop > div > p {
  /* one truncation mechanism. The clamp draws the ellipsis; text-overflow
     on a -webkit-box is what produced the clipped glyph. */
  text-overflow: clip;
  /* small light type on a dark ground optically bolds and spreads, so it
     is tracked out and its weight is pulled back one step */
  letter-spacing: 0.012em;
  /* 550, not 600. The pixel review read these captions as outlined
     stickers: bold white plus three stacked dark shadows made the shadow
     rival the glyph weight. */
  font-weight: 550;
  /* ONE soft plate that follows the glyphs. Two of the three layers were
     doing the same job at different radii, which is what read as an
     outline rather than as a shadow. */
  /* With the ground held near black by the scrim there is far less bright
     wallpaper to fight, so the plate drops again: one 4px blur at 55
     percent, no offset. An offset shadow is what reads as stamped. */
  text-shadow: 0 0 4px rgba(0, 0, 0, 0.55);
  /* keep the two line box a fixed height so every row in a column aligns
     even when one label is short */
  min-height: calc(2 * 1.2em);
}

/* the expanded label on hover already had a plate; it takes the depth 3
   shadow so it reads as lifted rather than as a flat swatch */
#desktop > div.b.clut:hover > p,
#desktop > div.b.clut:focus-visible > p,
#desktop > div.b.clut.sel > p {
  box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.86), var(--sh-3);
  border-radius: var(--os-r-btn);
  text-shadow: none;
}

/* ===========================================================================
   8. FINDING 4: HOW THE DESKTOP RENDERS ICONS

   Artwork is another agent's file (icon/) and the request for new art is
   written into fleet/requests/craft-icons.md. What is ours is the render:
   cell size, tile size, optical scaling and the well treatment, so that a
   document icon and an app icon at least sit in the same frame even while
   the art itself is being redrawn.

   Measured before: every clut tile rendered its art at 40x40 inside an 84px
   cell, which is correct and consistent. What was inconsistent was that the
   art arrived with its own baked corner radius (9, 4, 3 px measured) and
   its own internal padding, so a folder filled 80 percent of its square and
   a document filled 45. The render side of that is the well: give every
   icon the same well, the same contact shadow and the same optical box, and
   the pack differences stop being four families and become one family with
   varying weight.
   =========================================================================== */
#desktop > div.b.clut > img {
  /* one contact shadow on the one light direction, so a document and an app
     sit on the same desk */
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5)) drop-shadow(0 3px 8px rgba(0, 0, 0, 0.28));
  /* the art box is fixed so a wide pack and a tall pack optically match */
  object-fit: contain;
}

/* the tile well: shown on hover and focus, on the icon token, so the
   hit area is legible and matches the dock */
#desktop.clut-free > div.b.clut:hover,
#desktop.clut-free > div.b.clut:focus-visible,
#desktop.clut-free > div.b.clut.sel {
  border-radius: var(--os-r-icon);
}

#desktop > div.sel,
#desktop.clut-free > div.b.clut.sel {
  background: var(--st-sel);
  outline: 1px solid var(--st-sel-line);
  box-shadow: none;
}

/* ===========================================================================
   9. FINDING 6: the stray glyph at the window's left edge

   Measured: at 1440 with two windows open, a single letter painted at
   x 213, y 707, immediately left of the About window's frame at x 216. It
   is a desktop label at cell x 198 whose two line clamp put one character
   on the second line, and the window edge cut the rest. The label is not
   broken; what is broken is that a desktop object is allowed to paint in
   the 16px gutter the window sits against with no clearance rule.

   The desk keeps its deliberate mess. What it stops doing is placing a cell
   so close to the left edge that a label fragment survives behind a window
   frame. #desktop already clips at overflow hidden; the fix is to give the
   desk an inner gutter so the first column starts on the 8px baseline
   rather than at x 0, and to stop the label painting outside its own cell.
   =========================================================================== */
#desktop.clut-free {
  /* the 8px baseline: a 16px gutter left and right, so no cell can be cut
     by the viewport edge and no label fragment can survive in the gutter */
  padding-left: 8px;
  padding-right: 8px;
  box-sizing: border-box;
}

/* NOTE: an earlier draft of this block set max-width 100% here, which sits
   after the label rule above and silently cancelled it. The measurement
   caught it: the label reported max-width 100% and mask none while the
   stylesheet said 56px. The label's own box is set once, above, and this
   block no longer restates it. */
#desktop > div.b.clut > p {
  overflow: hidden;
}

/* THE STRAY GLYPH AT THE WINDOW'S LEFT EDGE.

   The review reported "a stray R glyph bleeding out at the window's left
   edge, a clipping or z order artifact from a label underneath". It
   reproduces, and it is neither clipping nor z order. Measured at 1440 with
   the About window open at x 216:

     cell x 198, cell width 84
     art  x 219.5, art width 41   -> the art is fully BEHIND the window
     label x 201, label width 78  -> 15px of the label is LEFT of the window

   The label box is 78px wide because it has to hold a filename. The art is
   41px. So there is a 18px band on each side of the cell where the label
   paints and the art does not. When a window edge lands in that band, the
   art disappears behind the window and a sliver of the label survives
   beside it, which reads as a letter floating in space with no icon.

   This is a real defect and it is a TYPE defect, not a stacking one. The
   fix is that a label may not be wider than the thing it labels by more
   than the cell allows, and more importantly that a label fragment on its
   own is worse than no label: the label is given the same visual width
   budget as the tile and centred on the art, so when the art is covered the
   label is covered with it.

   The label keeps its two lines and its full text; only the box narrows. */
/* TWO APPROACHES WERE TRIED AND REJECTED BEFORE THE ONE THAT WORKS, and
   both are recorded because the reasoning matters more than the rule.

   Rejected 1: pin the label box to the 40px art width. It does kill the
   orphan sliver at every window position, measured zero. It also truncates
   every label to about six characters, which trades one defect for a worse
   one. A label has to stay a label.

   Rejected 2: fade only the outer few pixels with a mask. At a fade wide
   enough to hide a fragment it eats the first character of every label on
   the desk; at a fade narrow enough not to, a crisp fragment still survives
   at 4x magnification. Measured: still four orphan slivers, still legible.

   THE FIX, closing the band from both ends at once, because neither end
   closes it alone.

   The label narrows from 76px to 56px. That cuts the band in which a
   fragment can be orphaned from 18px a side to 8px a side, and 56px still
   carries about nine characters a line at 11px DM Sans, which is inside
   what macOS and Windows both show at their own default icon size.

   The remaining 8px is then masked to nothing, with the ramp matched to
   the measured band rather than guessed, so the last half character fades
   out exactly over the strip where the art has already gone.

   Over the centre 40px, which is precisely where the art sits, the label
   is fully opaque and perfectly crisp, so nothing a visitor actually reads
   is touched. The evidence file records the brightest ink surviving left
   of a worst case window edge before and after. */
#desktop > div.b.clut > p {
  max-width: 56px;
  margin-left: auto;
  margin-right: auto;
  /* The ramp is 3px, not 9px. At 9px it visibly dimmed the first and last
     character of every label on the desk, which was a worse defect than the
     one it fixed and is exactly the trap the two rejected approaches fell
     into. At 3px the ramp lands inside the glyph's own antialiasing, so a
     whole character never dims, while a fragment cut by a window edge still
     loses its hard vertical stem and stops reading as a letterform.
     Measured: orphan ink 187 of 255 before, 38 after, against 226 for a
     label the visitor is meant to read. */
  -webkit-mask-image: linear-gradient(90deg,
    transparent 0, #000 3px,
    #000 calc(100% - 3px), transparent 100%);
  mask-image: linear-gradient(90deg,
    transparent 0, #000 3px,
    #000 calc(100% - 3px), transparent 100%);
}

/* hover and focus reveal the whole name, so the mask comes off with the
   clamp it already came off with */
#desktop > div.b.clut:hover > p,
#desktop > div.b.clut:focus-visible > p,
#desktop > div.b.clut.sel > p {
  -webkit-mask-image: none;
  mask-image: none;
}

/* THE TOP ROW AND THE SYSTEM BAR.

   Measured: the system bar is 28px tall and the first row of desktop cells
   starts at y 42, so the tile clears the bar by 14px but its own 40px art
   plus a 6px pad means the ART starts at roughly y 48. That is fine. What
   is NOT fine is that #desktop itself starts at y 28, directly under the
   bar, with overflow hidden, so a cell that the placement engine puts in
   the first 14px is clipped rather than moved. That is the "cluster of half
   clipped label-less icons" the review saw at the top left.

   The desk keeps its deliberate mess. It stops clipping. The desk box is
   pushed down so its own first pixel is already clear of the bar, which
   means a cell can be placed anywhere in the box and still be whole. The
   placement engine in pekan/clutter.js is not touched: it measures the box
   it is given, so giving it a shorter box is the supported way to reach
   this from the style layer. */
#desktop.clut-free {
  /* 14px of air under the 28px bar, so the first row is never cut */
  padding-top: 14px;
}

#desktop.clut-free > div.b.clut {
  /* the tile keeps its own contact shadow so it reads as an object on a
     desk rather than a sticker on a gradient */
  border-radius: var(--os-r-icon);
}

/* ===========================================================================
   10. FINDING 9: ONE ACCENT, ONE NEUTRAL RAMP

   Measured before, by sampling every visible chromatic fill: nine distinct
   saturated colours were painted, including #2983cc dock blue, #660099,
   #008000 and #8e5829 from the shell's task manager legend. Plan 4.1 allows
   exactly two: accent #6E5AE8 and sun #E4C56A used sparingly.

   The task manager legend needs four DISTINGUISHABLE series colours, and
   four accents is what the review objected to. The resolution is a single
   hue family: the accent, and three tints of it plus the sun, which keeps
   the series readable while deleting the strays.
   =========================================================================== */
#win-taskmgr .graph-view-cpu,
#win-taskmgr > .main > .cnt.performance > .content > .select-menu > * > .left > .graph-view-cpu {
  border-color: var(--pm-purple);
}

#win-taskmgr .graph-view-memory,
#win-taskmgr > .main > .cnt.performance > .content > .select-menu > * > .left > .graph-view-memory {
  border-color: var(--pm-lavender);
}

#win-taskmgr .graph-view-disk,
#win-taskmgr > .main > .cnt.performance > .content > .select-menu > * > .left > .graph-view-disk {
  border-color: var(--pm-teal);
}

#win-taskmgr .graph-view-wifi,
#win-taskmgr > .main > .cnt.performance > .content > .select-menu > * > .left > .graph-view-wifi {
  border-color: var(--pm-sun);
}

#win-taskmgr .graph-view-gpu,
#win-taskmgr > .main > .cnt.performance > .content > .select-menu > * > .left > .graph-view-gpu {
  border-color: var(--pm-purple-deep);
}

/* the graph itself and its minor grid come onto the accent family.

   These four colours are written as INLINE style attributes in desktop.html
   (line 2858 border 1px #660099, line 2911 border-left 2px #008000, line
   2976 stroke #8e5829) and in module/apps.js, both of which belong to the
   markup agent. An inline style outranks any stylesheet rule, so the only
   way a style sheet can take them back is an !important, and that is why
   these four carry one. The request to move them into the markup is written
   into fleet/requests/craft.md. */
#win-taskmgr .graph2.minor,
#win-taskmgr .graph.minor,
#win-taskmgr .performance-graph .graph2,
#win-taskmgr .performance-graph .graph {
  border-color: rgba(169, 155, 255, 0.30) !important;
}

/* the read and write speed keys, and any other inline coloured rail inside
   the performance pane */
#win-taskmgr > .main > .cnt.performance [style*="border-left"] {
  border-left-color: var(--pm-lavender) !important;
}

#win-taskmgr .chart[style*="background"] {
  background-color: rgba(110, 90, 232, 0.16) !important;
}

/* THE ELEVATION RAMP INSIDE A GLASS WINDOW.

   An earlier draft of this block painted #win-taskmgr > .main with the
   opaque --el-1. That was wrong and the measurement caught it: an opaque
   child covering 68 percent of the window cancels the window's own
   backdrop-filter for that area, so the panel went back to being the flat
   slab the review complained about. Measured: removing the window's blur
   changed 0.0 percent of the pixels, which is the signature of glass that
   nothing is showing through.

   Elevation inside a translucent window has to be built from TRANSLUCENT
   steps over the glass, not from opaque fills. Each step below is a white
   tint at a fixed alpha, so the depth reads as light collecting on a raised
   surface while the wallpaper still shows through the window as a whole.
   The measured lightness separation between the steps is what the review
   asked for; the transparency is what keeps the glass real. */
#win-taskmgr > .main {
  background: transparent;
}

/* raised: the header row and the side rail. */
#win-taskmgr > .main > .side,
#win-taskmgr > .main > .cnt > .title,
#win-taskmgr > .main > .cnt > .head,
#win-taskmgr > .main > .cnt.performance > .content > .select-menu {
  background: rgba(255, 255, 255, 0.05);
}

/* raised more: a hovered row. */
#win-taskmgr > .main > .cnt.performance > .content > .select-menu > *:hover {
  background: rgba(255, 255, 255, 0.09);
}

/* highest: the selected row. This is the one place the accent appears in
   the table, and it is a tint rather than a fill so the glass survives. */
#win-taskmgr > .main > .cnt.performance > .content > .select-menu > .check {
  background: rgba(110, 90, 232, 0.24);
}

/* ===========================================================================
   11. FINDING 11: TABLE CRAFT

   Measured before: rows painted at 22.0px against 12px type, "Power usage"
   was text-align left while every numeric neighbour was right, and the
   header aggregate values did not share a right edge with their column
   because the header cell had its own padding.
   =========================================================================== */

/* 22px against 12px type is claustrophobic. 28px gives the row a 1.6 ratio,
   which is where a dense system table stops feeling cramped and still fits
   the same count on screen. */
#win-taskmgr > .main > .cnt.processes > table td,
#win-taskmgr > .main > .cnt.processes > table th {
  height: 28px;
  padding: 4px 12px;
  /* tabular figures throughout, so a column of numbers has a spine */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* the last column is a magnitude, so it is right aligned with the rest.
   Both the header and the cell, or the header would float off the edge. */
#win-taskmgr > .main > .cnt.processes > table th:last-child,
#win-taskmgr > .main > .cnt.processes > table td:last-child {
  text-align: right;
}

/* the header aggregate and the data underneath it share one right edge */
#win-taskmgr > .main > .cnt.processes > table th.align-right > .value,
#win-taskmgr > .main > .cnt.processes > table th.align-right > span {
  padding-right: 0;
  margin-right: 0;
}

/* the row banding was loud enough to compete with the data. It drops to a
   step on the neutral ramp, which is elevation rather than stripe. */
#win-taskmgr > .main > .cnt.processes > table tbody > tr:nth-child(even) {
  background: rgba(255, 255, 255, 0.022);
}

#win-taskmgr > .main > .cnt.processes > table tbody > tr:hover {
  background: var(--el-3);
}

/* ===========================================================================
   12. FINDING 10 AND 12: ONE GRAMMAR

   Measured: the three Pekan discs are already plum, amber and teal (the
   review's "macOS red, yellow and green" claim did not reproduce: sampled
   rgb(57,46,118), rgb(113,97,58), rgb(34,78,82) on the About window). Bar
   height is a single 38px everywhere. What DID reproduce is that the
   controls on an UNFOCUSED window are all one grey, so two windows in one
   frame read as two different control systems, which is the same complaint
   arriving by a different route.

   An unfocused window keeps its colours at a reduced saturation rather than
   going grey, which is one grammar in two states instead of two grammars.
   =========================================================================== */
.window:not(.foc) > .titbar .wbtg.red {
  background: rgba(110, 90, 232, 0.55);
}

.window:not(.foc) > .titbar .wbtg:not(.red):not(.max) {
  background: rgba(228, 197, 106, 0.48);
}

.window:not(.foc) > .titbar .wbtg.max {
  background: rgba(62, 156, 156, 0.48);
}

/* the disc gets a contact shadow so it reads as a physical control on the
   one light direction rather than as a printed dot */
.window > .titbar .wbtg {
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.18);
}

/* the sticky note's controls are the same discs at the same size, so a note
   and a window are visibly the same operating system */
.os-note > .nb button {
  border-radius: var(--os-r-menu);
}

/* ===========================================================================
   13. PHONE

   Every geometry above has to survive 390. The dock scrolls there, so the
   tiles and the Start button drop to 44 and the badge scales with them.
   =========================================================================== */
@media (max-width: 700px) {
  #dock-box #start-btn,
  #dock-box .dock-btn#start-btn {
    height: 44px;
    width: 44px;
    min-width: 44px;
    padding: 0;
    justify-content: center;
  }

  /* os2031.css already hides the dock key on a phone. This sheet used to
     put it back as a 44 px tile, which then sat on top of the scrolling
     pins (measured: key at x=328 over notes at x=354 on a 390 canvas).
     Software Update lives in Tools; the Files pin and the Tools tile
     both open that folder. */
  #dock-box .dock-key {
    display: none;
  }

  /* Gemini QA: eight 44 px pins plus Start do not fit a 370 px dock, so
     the last tile clipped the chevron. Terminal and the checklist stay
     reachable from Start. */
  #dock-box .dock-btn.dock-phone-more,
  #dock-box .dock-btn.pin.dock-phone-more {
    display: none;
  }

  #dock-box {
    overflow: hidden;
  }

  #dock-box > .dock.dock-start {
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    overflow-y: hidden;
  }

  #dock-box .dock-divider {
    height: 26px;
    margin: 0 5px;
  }

  /* the desk is a static grid on a phone, so the gutter rule above does not
     apply and would double the padding the grid already sets */
  #desktop.clut-free {
    padding-left: 10px;
    padding-right: 10px;
  }

  /* Gemini QA: toast close was 20 px and Open was 32 px. convert.css
     owns those rules and this sheet loads after it. */
  .pk-toast-x,
  .pk-up-x,
  .msg.update > .a.hide {
    min-width: 44px;
    min-height: 44px;
    width: 44px;
    height: 44px;
    display: grid;
    place-items: center;
  }

  .pk-toast-form button,
  .pk-toast-actions button,
  .pk-toast .primary,
  .pk-up-btn,
  .pk-up-check,
  .msg.update .a.btn.main {
    min-height: 44px;
  }

  #pk-toasts,
  #pk-update-toast {
    bottom: calc(72px + env(safe-area-inset-bottom, 0px));
  }
}

@media (max-width: 620px) {
  /* last-wins: os2031 .os-note is position:fixed. clutter.css already
     restates static, and this sheet loads after both. */
  body #desktop > .os-note.flow,
  body #desktop.clut-free > .os-note.flow {
    position: static !important;
    left: auto !important;
    top: auto !important;
    right: auto !important;
    bottom: auto !important;
    width: auto !important;
    height: auto !important;
    grid-column: 1 / -1;
    /* AUTO, not 1. Requested by the world lane, which owns clutter.css and
       notes.js: a hard grid-row 1 pinned the paper into a short first
       track sized for icons, and the note then overflowed into the first
       icon row. Measured at 375: note y 70 height 187 bottom 257 against
       Tools at y 229. World already mounts the note as the first child and
       sizes the rows min-content, so order -1 is enough to place it. */
    grid-row: auto;
    order: -1;
    z-index: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  #dock-box .dock-btn,
  #dock-box .dock-btn.pin,
  #dock-box #taskbar > a,
  #dock-box #taskbar > a::after,
  #dock-box .dock-btn.run::after {
    transition: none;
  }
}

/* ===========================================================================
   14. ROUND 7: THE GROUND AND THE GLASS

   The owner's words for this round were "darker, richer colour, not overly
   bright, more glass, futuristic, better wallpaper animation". Round 6 was
   measured before any of this was written, and the measurement said the
   picture had the opposite problem to the one it looks like it has.

   MEASURED BEFORE, at 1440 by 900, hearth:

     the wallpaper as painted       mean saturation 0.460, mean value 0.184
     the bare desktop a visitor
       actually sees between the
       icons and the windows        mean saturation 0.308, mean value 0.220
     61 percent of every wallpaper pixel sat inside one 30 degree hue bucket
     depth 2 window plate           lum 0.0100, saturation 0.38
     title bar plate                lum 0.0198
     dock plate                     lum 0.0289
     menu bar plate                 lum 0.0062
     halo plate                     lum 0.0145

   Two readings there matter. The first is that the ground is not short of
   saturation, it is short of saturation WHERE THE VISITOR CAN SEE IT: the
   rich plum well sits under the window stack and the icon field, and what is
   left exposed is the old straight amber horizon band, which measured 15
   points less saturated and 4 points brighter than the picture as a whole.
   That band is the beige haze. It is gone in round 7, replaced by a narrow
   curved lip that rises under the dock and dies at both edges.

   The second is that the five plates above span 0.0062 to 0.0289 in no
   order: the menu bar is darker than the wallpaper, the window is darker
   than the wallpaper, the dock is brighter than everything. That is not a
   depth ramp, it is five unrelated numbers. Section 1 sets the ramp; this
   section makes the glass that sits on it carry colour rather than grey.

   Nothing here invents a design language. Every value is a token that
   os2031.css already declares, restated with a measured number, and this
   sheet is the last one loaded so these are the values actually painted.
   =========================================================================== */
:root {
  /* THE WALLPAPER, read by pekan/wallpaper.js.
     rich  chroma restore about each pixel's own luma. Saturation in HSV is
           scale invariant, so this raises measured saturation and leaves
           value alone, which is the literal reading of "richer, not
           brighter". 1 turns it off.
     sink  the elliptical fall toward the frame, centred a little low so the
           warmth under the dock survives it. Multiplied, so it takes value
           and leaves hue and saturation: darker without being duller.
     filament  the fine anisotropic structure a 20 px backdrop blur needs in
           order to have anything to smear. Without it a blurred near black
           gradient is a flat slab, which is what the plate numbers above
           were describing. */
  --os-wall-rich: 1.26;
  --os-wall-sink: 0.42;
  --os-wall-filament: 1;

  /* THE MOTION, round 8. The owner asked twice for "better wallpaper
     animations, need it to feel futuristic" and got a still both times.

     Measured before this pass, over the eight seconds a visitor might
     actually watch, the median sample point of the default treatment moved
     3 levels out of 255, and the other two treatments moved 0 and 1. The
     composition did eventually travel, over four to five minutes, which is
     the same as not travelling.

     The answer is not a faster wallpaper. A ground carrying 96 icons and a
     lead funnel has to stay a ground. The answer is INDEPENDENCE: five fields
     drifting at rates whose ratios are not simple fractions, so the frame
     never returns to a state a visitor has already seen and no single motion
     is fast enough to follow.

     flow   the current: a slow shear of the whole composition in UV, faded
            out at the bottom of the frame so the hearth stays under the dock
            and the lip stays a straight lip. This is the layer that makes
            five drifting regions read as one volume of air.
     motion a master scalar on every moving term. 0 is the composed still, 1
            is the design. Reduced transparency takes it down rather than off,
            because a flat panel has no blur to hide a moving ground behind.
     fps    the wallpaper's own frame cap, and the reason this pass costs less
            than the still one it replaces. Ambient weather does not need 30
            frames a second: the fastest thing in the frame moves about two
            percent of its own width per frame at 20, which no eye resolves.
            A browser can only divide its own 60, so 30, 20, 15 and 12 are the
            honest values and anything between them becomes the next one down.
     tide-a
     tide-b two caustic sweeps rather than one. One sweep every 24 s was the
            single thing in the old frame a visitor could set a watch by.
            These two share no small factor, so their sum comes back every 37
            minutes. Each is weaker than the single sweep, so the brightest
            pixel the contrast solver has to survive does not rise. */
  --os-wall-flow: 0.044;
  --os-wall-motion: 1;
  --os-wall-fps: 20;
  --os-wall-tide-a: 37s;
  --os-wall-tide-b: 61s;

  /* THE GLASS.
     The depth 2 and depth 3 tints keep their luminance and gain chroma. A
     dark surface with no chroma of its own drags the colour out of whatever
     is behind it, which is why the dock plate measured saturation 0.23 over
     a wallpaper measuring 0.46. Same luma, more colour:

       depth 2   22, 18, 32  luma 19.9, saturation 0.44
                 30, 15, 44  luma 20.3, saturation 0.66
       depth 3   28, 22, 42  luma 24.7, saturation 0.48
                 38, 19, 56  luma 25.7, saturation 0.66

     The backdrop saturation lift rises with them, because the thing being
     lifted is now worth lifting. Blur stays at the plan 4.1 numbers, 20 and
     32: this is a colour change, not a new material. */
  --g2-rgb: 30, 15, 44;
  --g2-sat: var(--glass-sat);
  --g3-rgb: 38, 19, 56;
  --g3-sat: var(--glass-sat-lift);

  /* the opening alpha of each depth, matched to the two bases pekan/glass.js
     solves upward from, so the first paint and the solved paint agree and
     nothing flashes on load. These are not the final numbers: glass.js
     raises whichever depth fails the 4.5 to 1 floor against the wallpaper
     actually on screen, and writes the result back over these. */
  --g2-a: 0.54;
  --g3-a: 0.72;
  --g2-a-idle: 0.46;
}

/* under a reduced transparency preference there is no backdrop to saturate
   and no wallpaper to read through, so the lift is pointless and the tint
   goes back to the quieter neutral: a flat panel at 0.94 wants to look like
   a panel, not like a plum card */
@media (prefers-reduced-transparency: reduce) {
  :root {
    --g2-rgb: 24, 19, 34;
    --g3-rgb: 30, 24, 44;
    --g2-sat: 1;
    --g3-sat: 1;
    /* os2031.css sets these three in its own reduced transparency block, and
       this sheet loads after it, so the flat values have to be restated here
       or the unconditional block above would quietly undo them. */
    --g2-a: 0.94;
    --g2-a-idle: 0.94;
    --g3-a: 0.97;
    /* the ground keeps moving, because reduced transparency is a statement
       about translucency and not about motion, but it moves less. With the
       panels flat there is no blur in front of the wallpaper, so the same
       amplitude that reads as depth behind glass reads as activity beside a
       solid plate. Down, not off. */
    --os-wall-motion: 0.62;
  }
}

/* ===========================================================================
   LIQUID GLASS, 2026-09-05. Shared tokens from pekan/liquid-tokens.css
   are the recipe. This sheet loads last of the linked pekan cascade, so
   these values are the ones a visitor actually sees. Purple wash is
   reduced to a 4 to 6 percent lavender tint. Text is #fff on dark glass.
   Notes stay paper and are not restated here (world owns that cascade).
   =========================================================================== */
:root {
  --r-window: var(--pk-radius-window, 24px);
  --r-card: var(--pk-radius-panel, 16px);
  --r-control: var(--pk-radius-control, 10px);
  --os-ui: var(--pk-font, "Onest", "DM Sans", system-ui, sans-serif);
  --os-body: var(--pk-font, "Onest", "DM Sans", system-ui, sans-serif);
  --os-text: var(--pk-text, #fff);
  --os-text-2: #f2f2f2;
  --pm-purple: var(--pk-accent, #5956E9);
  --pm-purple-deep: var(--pk-accent-deep, #423EF3);
  --pm-lavender: var(--pk-accent-light, #838AFF);
  /* True black is the base. The shell composes its own alpha off these
     triples (pekan/glass.js solves upward from them), so they stay bare
     numbers, and they are now black rather than charcoal. */
  --g2-rgb: 0, 0, 0;
  --g3-rgb: 0, 0, 0;
  --g2-a: 0.46;
  --g3-a: 0.56;
  --g2-a-idle: 0.38;
  --glass-blur: 32px;
  --glass-blur-lift: 36px;
  --glass-blur-modal: 28px;
  --glass-sat: 1.18;
  --glass-sat-lift: 1.22;
  --glass-sat-modal: 1.2;
  --glass-sat-idle: 1.04;
  /* Softer than the shared 25 percent. Combined with the top-lit gradient
     underneath it, the edge reads as a curve rather than as an outline. */
  --glass-border-col: rgba(255, 255, 255, 0.16);
  --glass-border-col-lift: rgba(255, 255, 255, 0.2);
  --glass-border-col-idle: var(--pk-glass-hairline, rgba(255, 255, 255, 0.12));
  /* ONE light stroke per edge, and it is the border.

     A vision pass on the measured after image still read two light lines
     with a dark gap between them along the dock's top edge. Source of each,
     from computed style: the 1px white border at 25 percent, an
     "inset 0 1px 0 white 48 percent" from this token, and a third
     "inset 0 1px 0 white 30 percent" carried inside --pk-glass-shadow.
     Three strokes stacked on a one pixel edge is a bevel, not glass.

     What stays is the border plus the surface's own top-lit gradient. The
     inner highlight is reduced to a whisper along the very bottom, which
     is the light bouncing back up off the desk rather than a second rim. */
  --glass-inner: inset 0 -1px 0 rgba(255, 255, 255, 0.05);
  /* the shared shadow token carries its own inset top highlight, so this
     sheet composes the drop layers itself rather than inheriting it */
  --glass-shadow: 0 28px 80px rgba(0, 0, 0, 0.34), 0 8px 24px rgba(0, 0, 0, 0.18);
  --glass-shadow-focus: 0 36px 96px rgba(0, 0, 0, 0.38), 0 10px 28px rgba(0, 0, 0, 0.2), var(--glass-inner);
  --glass-shadow-lift: 0 40px 110px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.22), var(--glass-inner);
  --glass-shadow-modal: 0 48px 130px rgba(0, 0, 0, 0.46), 0 16px 40px rgba(0, 0, 0, 0.24), var(--glass-inner);
  --os-wall-horizon: 0.05;
  /* 1 is off. Anything above it pushes chroma back into each pixel around
     its own luma, which is the opposite of a near neutral ground. */
  --os-wall-rich: 1;
  --g1-tint-a: rgba(89, 86, 233, 0.06);
  --g1-tint-b: rgba(131, 138, 255, 0.05);
}

.window,
#dock-box,
#start-menu,
#cm,
#dp,
#notice,
.pk-toast,
.clut-dlg,
#os-setup .card {
  color: var(--pk-text, #fff);
  /* Top light, not a diagonal wash: 180deg so every surface in the OS is
     lit from the same direction the shadows already assume. The lavender
     sits at 5 percent, which is the tint the brand asks for. */
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(131, 138, 255, 0.05) 46%, rgba(255, 255, 255, 0.012)),
    var(--pk-glass-surface, rgba(0, 0, 0, 0.62));
  /* A flat, quiet stroke, NOT a border-image gradient. border-image ignores
     border-radius entirely, so a top-lit gradient edge paints square
     corners on a 24px rounded panel. The curvature read comes from the
     surface's own top-lit fill instead, which does clip to the radius. */
  border: 1px solid var(--glass-border-col);
  box-shadow: var(--glass-shadow), var(--glass-inner);
  -webkit-backdrop-filter: var(--pk-glass-blur, blur(32px) saturate(125%));
  backdrop-filter: var(--pk-glass-blur, blur(32px) saturate(125%));
}

.window { border-radius: var(--pk-radius-window, 24px) !important; }
#start-menu,
#loginback > .lock-core,
#os-setup .card { border-radius: var(--pk-radius-window, 24px); }
#cm, #dp, #notice, .pk-toast, .clut-dlg { border-radius: var(--pk-radius-panel, 16px); }

.window > .titbar,
.window.webapp > .titbar,
.window.webapp.foc > .titbar,
.window.chrome > .titbar,
:root.mica .window.webapp > .titbar,
:root.mica .window.webapp.foc > .titbar {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.11), rgba(131, 138, 255, 0.04) 60%, rgba(255, 255, 255, 0.015)) !important;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
  backdrop-filter: blur(18px) saturate(1.15);
  -webkit-backdrop-filter: blur(18px) saturate(1.15);
}

.window > .titbar .wbtg.red { background: #6b3a62; }
.window > .titbar .wbtg:not(.red):not(.max) { background: #c9a24a; }
.window > .titbar .wbtg.max { background: #2f6f6a; }

/* The system bar is the top edge of the whole composition, so it carries
   the strongest top light in the OS and one hairline underneath. The pixel
   review called its depth model unresolved: it had a bottom border AND a
   top inset AND a drop shadow all at similar weights. */
#os-menubar {
  height: 32px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.34));
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.34), 0 12px 30px rgba(0, 0, 0, 0.26);
  -webkit-backdrop-filter: blur(22px) saturate(1.15);
  backdrop-filter: blur(22px) saturate(1.15);
  color: #fff;
}

#os-menubar .mb-item { display: none; }

#loginback {
  background: rgba(8, 8, 12, 0.18);
  backdrop-filter: blur(18px) saturate(1.1);
  -webkit-backdrop-filter: blur(18px) saturate(1.1);
}

#loginback::after {
  background:
    radial-gradient(36% 32% at var(--pk-world-x, 22%) var(--pk-world-y, 20%), rgba(131, 138, 255, var(--pk-world-glow, 0.05)), transparent 68%),
    radial-gradient(40% 36% at 78% 70%, rgba(255, 255, 255, 0.08), transparent 64%);
}

#loginback > .lock-core.pk-spatial-glass,
#loginback > .lock-core {
  background:
    linear-gradient(135deg, rgba(255, 255, 255, 0.1), rgba(131, 138, 255, 0.04)),
    var(--pk-glass-surface, rgba(18, 18, 22, 0.66));
  color: #fff;
  border-radius: var(--pk-radius-window, 24px);
}

.pk-guest-slot,
#os-halo .av.pk-guest,
#startmenu-user.pk-guest {
  display: grid;
  place-items: center;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  /* The slot inherits an 80px/120px type scale from the shell's original
     letter avatar. With an SVG mark inside it that line box is what made
     the slot report scrollWidth 93 against clientWidth 86 and scrollHeight
     70 against clientHeight 46 on a phone: the brand mark was clipped by
     an invisible text line, not by the box. */
  font-size: 0;
  line-height: 0;
}

.pk-guest-cursor,
#startmenu-user > img,
#startmenu-user > svg {
  max-width: 100%;
  max-height: 100%;
}

.pk-guest-cursor {
  width: 72%;
  height: 72%;
  display: block;
}

#start-menu {
  left: 50%;
  width: min(920px, calc(100vw - 48px));
  max-width: calc(100vw - 24px);
  transform: translateX(-50%) translateY(40px);
  bottom: calc(var(--dock-lift, 12px) + var(--dock-tile, 50px) + 28px);
}

#start-menu.show {
  transform: translateX(-50%) translateY(0) !important;
}

#start-menu #os-menubar-phone { display: none; }

#bg-lava[data-world-scene] {
  --pk-scene-glow: radial-gradient(42% 34% at var(--pk-world-x, 50%) var(--pk-world-y, 50%), rgba(131, 138, 255, var(--pk-world-glow, 0.05)), transparent 70%);
}

/* The scrim is the last layer between the animated ground and the desk,
   so it is where the ground is finally held to black. The flat wash is new:
   a vignette alone leaves the CENTRE of the picture at full chroma, and the
   centre is exactly where both vision passes read violet. */
#bg-scrim {
  background:
    linear-gradient(180deg, rgba(0, 0, 0, 0.46), rgba(0, 0, 0, 0.5)),
    radial-gradient(130% 105% at 50% 44%, transparent 40%, rgba(0, 0, 0, 0.42) 100%),
    radial-gradient(ellipse 120% var(--os-wall-horizon-h) at 50% var(--os-wall-horizon-y),
      rgba(255, 255, 255, 0.05) 0%,
      rgba(131, 138, 255, var(--pk-world-glow, 0.05)) 42%,
      transparent 100%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.03 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>") !important;
}

.window.setting .page,
.window.setting .menu,
#win-setting .cnt {
  background: var(--pk-glass-panel, rgba(255, 255, 255, 0.065));
  color: #fff;
}

#win-taskmgr .tm-bar .pk-illustrative {
  flex: 1 1 100%;
  margin: 0 0 6px;
  font-size: 11px;
}

/* RESPONSIVE WINDOW FRAME. Measured at 820x1180: the focused window ran
   to y 1114 with the dock top at 1104, so the frame was 10px under the
   dock and its bottom corners were never visible. The window is clamped
   to the space above the dock at every width where the dock floats. */
.window:not(.max) {
  max-height: calc(100vh - var(--dock-lift, 12px) - var(--dock-tile, 50px) - 30px);
}

@media (max-width: 700px) {
  /* On a phone the window is a full height sheet under the system bar and
     above the dock, so it takes the same clamp from its own top edge. */
  .window {
    max-height: calc(100vh - 32px - var(--dock-lift, 12px) - var(--dock-tile, 50px) - 14px);
  }

  #start-menu {
    left: 8px !important;
    right: 8px !important;
    width: auto !important;
    transform: none;
  }
  #start-menu.show { transform: none !important; }
  #start-menu > #startmenu-l {
    overflow: visible !important;
    min-height: 0;
    height: auto !important;
  }

  /* The last destination has to clear the panel's bottom edge instead of
     being sliced by it. Measured before: the final row's bottom sat 22px
     past the panel at 375. */
  #start-menu {
    scroll-padding-block-end: 24px;
    padding-bottom: 14px;
  }

  #start-menu > #startmenu-r {
    padding-bottom: 22px;
  }
  #start-menu #os-menubar-phone {
    display: flex;
    flex-direction: column;
    margin: 8px 10px 0;
    position: relative;
    top: auto;
    z-index: 3;
  }
  #start-menu > #startmenu-l > list {
    margin-top: 8px;
  }
}

/* FALLBACK. No backdrop-filter means no glass, so the surfaces become
   near opaque black with the same top light, rather than a flat grey. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .window, #dock-box, #start-menu, #cm, #dp, #notice, .pk-toast, .clut-dlg,
  #os-setup .card, #loginback > .lock-core {
    background:
      linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(131, 138, 255, 0.04) 46%, rgba(255, 255, 255, 0.01)),
      rgba(0, 0, 0, 0.94);
  }

  #os-menubar {
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(0, 0, 0, 0.94));
  }
}

@media (prefers-reduced-transparency: reduce) {
  .window, #dock-box, #start-menu, #cm, #dp, #notice, .pk-toast, .clut-dlg,
  #os-setup .card, #loginback > .lock-core, #os-menubar {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    background:
      linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.01)),
      #000000;
  }
}

/* Forced colours throws the whole material away and paints system colours,
   which is correct: a glass system with no glass has to be a plain one. The
   only thing this sheet owes it is that nothing here reintroduces a
   background that the forced palette cannot override. */
@media (forced-colors: active) {
  :root {
    --os-wall-rich: 1;
    --os-wall-sink: 0;
    --os-wall-filament: 0;
    /* forced colours paints system colours over everything, so a moving
       ground underneath is cost with nothing to show for it */
    --os-wall-motion: 0;
  }

  #dock-box,
  #os-menubar,
  #os-halo,
  .window {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* the wallpaper animation is the one thing on the desktop that runs on its
   own, so it is the one thing that has to stop. pekan/wallpaper.js already
   freezes to a single composed frame under the preference; this rule is the
   belt to that brace, because a canvas that somehow kept running would still
   be pinned by the compositor here. */
@media (prefers-reduced-motion: reduce) {
  #bg-lava {
    animation: none !important;
    transition: none !important;
  }
}
