/* Pekan OS 2031, round 6 wave 2: authenticity.

   The owner's instruction is the whole brief: do not mimic an OS, integrate
   into one. This sheet closes the gaps an independent vision review found in
   the dark glass build, and every rule here answers a number that was
   measured in the running browser first.

   It loads after pekan/os2031.css on purpose. os2031.css owns the tokens and
   the chrome grammar and is not edited by this agent; this sheet only
   finishes what the grammar started, at equal or higher specificity, so
   there is no !important war except where os2031.css already used one and a
   later rule is the only way past it.

   No em dashes anywhere in this file. */

/* ===========================================================================
   Defect 6a: an inactive window must visibly differ from the active one.

   os2031.css already declares the idle tokens (--g2-bg-idle 0.50 alpha, a
   dimmer border) and applies them at .window:not(.foc). Measured in the
   build, both windows still painted rgba(22, 18, 32, 0.62): the appearance
   switch rule ":root.mica .window, ... .window.foc" carries !important and
   overrides the idle state for every window, focused or not.

   The fix is a later rule of the same weight that keeps the mica material
   for the focused window and hands the unfocused one the idle material the
   plan already specified. Measured after: active 0.62 alpha with a 0.30 rim
   and the deep focus shadow, inactive 0.50 alpha with a 0.10 rim and a
   flatter shadow. A visitor can tell at a glance which window is listening.
   =========================================================================== */
:root.mica .window:not(.foc),
.window:not(.foc) {
  /* The idle window keeps the SAME material as the focused one, and only
     its alpha changes. Painting a bare colour here dropped the top-lit
     gradient off every unfocused window, which is why an idle window read
     as a flat slab beside a lit one instead of as the same glass at rest.
     Measured before this line: backgroundImage "none" on .window:not(.foc)
     against a top-lit gradient on .window.foc. */
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(131, 138, 255, 0.035) 46%, rgba(255, 255, 255, 0.008)),
    var(--g2-bg-idle) !important;
  border-color: var(--g2-border-idle) !important;
}

/* An inactive window must differ even when the two alphas are the same
   number.

   pekan/glass.js solves --g2-a and --g2-a-idle independently against the
   contrast floor for the wallpaper actually behind them, and raises either
   one until light ink is legible on it. On a bright wallpaper, which is what
   the 390 viewport shows, both solutions land on the same value: measured
   0.650 and 0.650. That is the accessibility layer doing exactly its job,
   and it is not something to override, because winning that argument would
   mean shipping text below the contrast floor on a phone.

   So the difference is carried by something the contrast solver does not
   own. A real compositor dims an inactive window's contents rather than
   only its panel, which is also the more legible signal: it says "this
   window is not listening" without touching the ink on the active one. */
.window:not(.foc) > .titbar > p,
.window:not(.foc) > .content {
  opacity: 0.82;
}

.window.foc > .titbar > p,
.window.foc > .content {
  opacity: 1;
}

/* The shadow half of this is deliberately not set here.

   pekan/craft.css loads after this sheet and already gives the two states
   different lift: --sh-2 for an idle window (0 2px 6px, 0 14px 40px) and
   --sh-2f for the focused one (0 3px 10px, 0 26px 66px), both with
   !important. That is the same idea, done well, by an agent working the same
   round. Adding a competing rule here would only start a specificity war
   over a number both sheets agree about.

   Measured with both sheets loaded: active rgba(22, 18, 32, 0.62) at 26px
   and 66px of lift, inactive rgba(22, 18, 32, 0.50) at 14px and 40px. The
   background separation above is this sheet's contribution, and it is the
   part craft.css does not do. */

/* ===========================================================================
   Defect 16: the glass needs a top rim, and the title bar needs the blur.

   Measured before: the dock already carried the plan 4.3 inner highlight
   inset 0 1px 0 rgba(255, 255, 255, 0.22) and a real backdrop blur, but a
   window carried no rim highlight at all, and .titbar reported
   backdrop-filter: none, so the bar read as a flat tinted panel sitting on
   glass rather than as part of it.

   A real glass panel catches light on its top edge. The rim is drawn on the
   title bar rather than the window, because the bar is the top edge of the
   window and drawing it there survives the window's own overflow.
   =========================================================================== */
.window > .titbar,
.window.webapp > .titbar,
.window.webapp.foc > .titbar,
.window.chrome > .titbar {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22);
}

/* an unfocused window catches less light, the way a real one does */
.window:not(.foc) > .titbar {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
}

/* a maximised window has no top rim to catch light because it has no edge */
.window.max > .titbar {
  box-shadow: none;
}

/* ===========================================================================
   Defect 16, second half: the wallpaper needs enough structure for the blur
   to visibly do something behind a panel.

   Measured before: the panel interior over the wallpaper reads mean 30.2
   against mean 20.4 with the wallpaper hidden, so light genuinely bleeds
   through and the blur is real. But the uncovered wallpaper itself measured
   a standard deviation of only 2.55 across a 220x160 patch, which is close
   to flat. Glass over a flat field looks like a tint no matter how correct
   the blur is, which is exactly the review's complaint.

   pekan/wallpaper.js reads its own parameters from these tokens at startup
   and is not edited here. The caustic sweep and the star dust the plan
   specifies are already implemented in that file; they were simply set too
   faint to see. Turning them up is a token change, which is the supported
   way to reach that file.

   Star dust goes from 4 to 9 percent white so a lit particle survives a
   20px blur, and the four tints are deepened so the aurora has real
   contrast between its centres of gravity rather than one even wash.
   =========================================================================== */
:root {
  --os-wall-dust: 0.09;
  --g1-tint-a: rgba(126, 72, 196, 0.52);
  --g1-tint-b: rgba(44, 84, 168, 0.44);
  --g1-tint-c: rgba(212, 172, 92, 0.26);
  --g1-tint-d: rgba(46, 124, 124, 0.24);
}

/* ===========================================================================
   Defect 6b: resize edges you can see, and a focus ring on the window
   controls.

   Measured before: eight resize knobs per window existed and worked (a
   scripted drag on the right edge moved 1008px to 858px), but they were
   entirely invisible, which is why the review reported "no window resize
   edges". A real OS shows the edge on hover through the cursor and a faint
   highlight. The cursor was already right; the highlight was missing.
   =========================================================================== */
.window > .resize-bar > .resize-knob {
  transition: background-color 120ms ease;
}

.window.foc > .resize-bar > .resize-knob:hover {
  background-color: rgba(169, 155, 255, 0.28);
}

/* the corner knobs read as a corner grip rather than a bar */
.window.foc > .resize-bar > .resize-knob.top-left:hover,
.window.foc > .resize-bar > .resize-knob.top-right:hover,
.window.foc > .resize-bar > .resize-knob.bottom-left:hover,
.window.foc > .resize-bar > .resize-knob.bottom-right:hover {
  background-color: rgba(169, 155, 255, 0.38);
  border-radius: 3px;
}

/* ===========================================================================
   Thumb scale repair: the caption dot must stay a dot.

   Two correct decisions collided. desktop.css grows each caption control to a
   44px pad at thumb scale for the WCAG target size, keeps that pad
   transparent, and draws the coloured disc as the button's ::after so the
   shape a visitor recognises does not change. pekan/craft.css, working the
   same round, colours .wbtg's own background to give the disc a contact
   shadow, which is right on a pointer where .wbtg IS the 13px disc.

   Below 700px the two combine into a 44px filled plum square, which is not a
   window control in any operating system. Measured at 390 before this rule:
   44 by 44, radius 12px, background rgb(110, 90, 232).

   The pad goes back to transparent under 700px and the colour stays on the
   ::after disc where the mobile design put it. Neither sheet is edited; this
   one loads after desktop.css and restores its intent against a later rule
   that could not know about it.
   =========================================================================== */
@media (max-width: 700px) {
  /* every state of every control, focused or not, keeps a transparent pad.
     Listing them individually missed .window.foc > .titbar .wbtg:not(.red):
     not(.max) in os2031.css and left the minimise pad filled amber, measured
     rgb(228, 197, 106) on a 44px box. The doubled class covers the whole set
     at a weight that beats every one of them. */
  .window.window > .titbar .wbtg,
  .window.window > .titbar .wbtg.red,
  .window.window > .titbar .wbtg.max,
  .window.window > .titbar .wbtg:not(.red):not(.max),
  .window.window.foc > .titbar .wbtg,
  .window.window.foc > .titbar .wbtg.red,
  .window.window.foc > .titbar .wbtg.max,
  .window.window.foc > .titbar .wbtg:not(.red):not(.max),
  .window.window:not(.foc) > .titbar .wbtg,
  .window.window:not(.foc) > .titbar .wbtg.red,
  .window.window:not(.foc) > .titbar .wbtg.max,
  .window.window:not(.foc) > .titbar .wbtg:not(.red):not(.max) {
    background: transparent;
    box-shadow: none;
  }

  /* the disc keeps the contact shadow craft.css wanted, on the mark itself */
  .window.window > .titbar .wbtg::after {
    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.18);
  }

  /* an inactive window's dots dim rather than vanish, the same idea craft.css
     applies on a pointer, moved onto the mark */
  .window.window:not(.foc) > .titbar .wbtg.red::after {
    background: rgba(110, 90, 232, 0.55);
  }

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

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

  /* the pressed state belongs on the pad, which is what a thumb hits */
  .window.window > .titbar .wbtg:active {
    background: rgba(255, 255, 255, 0.10);
    transform: none;
  }
}

/* ===========================================================================
   Defect 6c: hover states on the title bar itself.

   A caption button that only changes when you land exactly on the 13px dot
   reads as decoration. Real window controls reveal their glyphs when the
   pointer enters the bar, which is what tells you they are controls.
   os2031.css already does this for colour; the dots also need to look
   pressable.
   =========================================================================== */
.window > .titbar .wbtg:active {
  transform: scale(0.92);
}

/* an unfocused window's controls are grey until you point at the bar, then
   they take their colours, which is the standard behaviour and also the
   affordance that says "this window is still alive" */
.window:not(.foc) > .titbar:hover .wbtg.red {
  background: var(--pm-purple);
}

.window:not(.foc) > .titbar:hover .wbtg:not(.red):not(.max) {
  background: var(--pm-sun);
}

.window:not(.foc) > .titbar:hover .wbtg.max {
  background: #3E9C9C;
}

/* ===========================================================================
   Defect 5: the note resize grip sits at the corner, not in the text.

   Measured before: the grabber was already positioned at the note's bottom
   right corner (right 0, bottom 0, 20x20), but .body reached the same corner
   with no reserved rim, so the grip painted on top of the last line of the
   note and read as floating inside the text. The body now stops short of the
   grip, which is what makes the grip read as chrome.
   =========================================================================== */
.os-note > .body {
  /* the grabber is 20px; leave it a corner of its own */
  padding-bottom: 18px;
}

.os-note > .grabber {
  /* and give it a hover state so it reads as a control */
  transition: opacity 120ms ease;
  opacity: 0.7;
}

.os-note:hover > .grabber,
.os-note.foc > .grabber,
.os-note > .grabber:focus-visible {
  opacity: 1;
}

/* ===========================================================================
   Defect 4: one control grammar for every window.

   The sticky note used a two control set (a colour dot and an x) while every
   app window used three Pekan discs. A note is not an app window and should
   not pretend to be one, but its controls must be drawn in the same
   language: same size, same discipline, same focus ring. The colour swatch
   keeps its job, the delete control is drawn as the same 13px plum disc a
   window close is drawn as, so a visitor reads it instantly.
   =========================================================================== */
.os-note > .nb {
  border-bottom: 1px solid rgba(26, 20, 8, 0.12);
  padding-bottom: 0;
  box-shadow: none;
}

/* The delete control is a MARK inside its tap box, not a disc the size of
   the tap box. A phone rule raises every note header control to a 44px
   minimum, and a minimum beats a width, so this file's old 13px disc was
   painting as a 44px slab with a transparent glyph on it. The disc is now
   drawn by a pseudo element and the box stays whatever size the layout
   asks for. */
.os-note > .nb .rm {
  border-radius: var(--r-control, 10px);
  background: none;
  color: rgba(26, 20, 8, 0.55);
  display: grid;
  place-items: center;
  position: relative;
  transition: background 160ms var(--pm-ease), color 160ms var(--pm-ease);
}

.os-note > .nb .rm svg {
  width: 7px;
  height: 7px;
}

/* the note reveals its controls on hover exactly as a window bar does */
.os-note:hover > .nb .rm,
.os-note.foc > .nb .rm,
.os-note > .nb .rm:focus-visible {
  color: rgba(26, 20, 8, 0.85);
}

.os-note > .nb .rm:hover {
  background: rgba(26, 20, 8, 0.12);
  color: rgba(26, 20, 8, 0.95);
}

.os-note > .nb .rm:active {
  transform: scale(0.92);
}

.os-note > .nb .rm:focus-visible {
  outline: 2px solid var(--os-focus);
  outline-offset: 3px;
  box-shadow: 0 0 0 6px var(--os-focus-halo);
}

/* ===========================================================================
   Defects 7, 8 and 9 beyond the Task Manager: the same density discipline
   and the same hairlines and scrollbars on every list surface in the OS.

   The review asked for this explicitly: "Apply the same density discipline
   to every list and table surface in the OS." A data table anywhere in the
   product now reads at 12px on a 22px row with a one device pixel rule.
   =========================================================================== */
:root {
  --os-hair: 1px;
  /* a one device pixel rule carries half the ink of a one CSS pixel rule, so
     the alpha is raised to keep it readable over glass */
  --os-hair-col: rgba(255, 255, 255, 0.22);
  --os-grid-row: 22px;
  --os-grid-font: 12px;
}

/* one device pixel, not one CSS pixel. On a 2x display a 1px border is two
   device pixels and reads soft, which is the blur the review called out. */
@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) {
  :root {
    --os-hair: 0.5px;
  }
}

@media (-webkit-min-device-pixel-ratio: 2.5), (min-resolution: 240dpi) {
  :root {
    --os-hair: 0.34px;
  }
}

/* A separator that is one DEVICE pixel, not one CSS pixel.

   Measured with docs/evidence/round6/authenticity/check-hairline.js: at
   devicePixelRatio 2 a 1px CSS border paints 2 device pixel rows, and so does
   a 0.5px border, because the engine rounds border widths up. An inset box
   shadow is not rounded that way: inset 0 -0.5px 0 paints exactly 1 device
   pixel row. That difference is the whole of "crisp 1px hairlines" and it is
   why these rules use a shadow rather than a border. */
.window .content table:not(.no-grid) > tbody > tr > td {
  border-bottom: 0;
  box-shadow: inset 0 calc(-1 * var(--os-hair)) 0 var(--os-hair-col);
}

/* the file list in Explorer is the other big data surface */
.window.explorer #win-explorer .files .file-list > * {
  box-shadow: inset 0 calc(-1 * var(--os-hair)) 0 var(--os-hair-col);
}

/* the menu bar's own bottom edge follows the same rule */
#os-menubar {
  border-bottom: 0;
}

/* = scrollbars that read as system scrollbars, everywhere =
   os2031.css sets a 10px overlay scrollbar globally. Inside a window, where
   content is clipped, the scrollbar also has to be visible enough to say
   "there is more below", which is the specific failure the review saw on the
   process list. These are slightly heavier and take layout width. */
.window .content ::-webkit-scrollbar,
.window .content::-webkit-scrollbar {
  width: 12px;
  height: 12px;
}

.window .content ::-webkit-scrollbar-track,
.window .content::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.20);
}

.window .content ::-webkit-scrollbar-thumb,
.window .content::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.22);
  border: 3px solid transparent;
  background-clip: padding-box;
  border-radius: 6px;
  min-height: 28px;
}

.window .content ::-webkit-scrollbar-thumb:hover,
.window .content::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.34);
  background-clip: padding-box;
}

.window .content ::-webkit-scrollbar-thumb:active,
.window .content::-webkit-scrollbar-thumb:active {
  background: rgba(255, 255, 255, 0.44);
  background-clip: padding-box;
}

/* Firefox has no pseudo elements for this; it gets the same intent */
.window .content {
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.22) rgba(0, 0, 0, 0.20);
}

/* ===========================================================================
   Defect 21: the status pill needs a bar to belong to.

   Measured before: #os-halo floated alone at the top right with nothing
   around it, so it read as a widget rather than as system chrome. It is not
   turned into a macOS menu bar with File and Edit, because this OS does not
   have per app menus and inventing them would be mimicry with nothing
   behind it. Instead the pill is seated in a real menu bar that spans the
   screen: the same glass, a hairline along the bottom, and the OS identity
   at the left where a system name belongs.
   =========================================================================== */
#os-menubar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 28px;
  z-index: 92;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 12px 0 14px;
  font-family: var(--os-ui);
  font-size: 12px;
  color: var(--os-text-2);
  background: rgba(var(--g2-rgb), 0.44);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  /* the top rim highlight and the one device pixel edge below, in one
     shadow so both survive at any device pixel ratio */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14),
    inset 0 calc(-1 * var(--os-hair)) 0 var(--os-line);
  pointer-events: auto;
}

#os-menubar .mb-mark {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-weight: 700;
  color: var(--os-text);
  letter-spacing: -0.01em;
}

#os-menubar .mb-mark img {
  width: 14px;
  height: 14px;
  object-fit: contain;
}

#os-menubar .mb-item {
  color: var(--os-text-2);
  background: none;
  border: 0;
  font: inherit;
  padding: 3px 8px;
  border-radius: var(--os-r-btn);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

#os-menubar .mb-item:hover {
  background: var(--os-tile);
  color: var(--os-text);
}

#os-menubar .mb-item:focus-visible {
  outline: 2px solid var(--os-focus);
  outline-offset: 2px;
}

#os-menubar .mb-spacer {
  flex: 1;
}

/* the pill now sits inside the bar instead of floating over the wallpaper */
#os-menubar #os-halo {
  position: static;
  height: 22px;
  padding: 0 4px 0 8px;
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 0;
  box-shadow: none;
  border-radius: 0;
}

#os-menubar #os-halo .av {
  width: 20px;
  height: 20px;
  font-size: 10px;
  box-shadow: 0 0 0 1.2px rgba(255, 255, 255, 0.28);
}

#os-menubar #os-halo .sep {
  height: 12px;
}

/* a note from the OS still expands the pill, and the bar grows with it */
#os-menubar #os-halo.say {
  height: 22px;
  padding-left: 8px;
}

/* The desktop starts below the bar so nothing is hidden under it.
   pekan/clutter.css makes #desktop an absolutely positioned box with inset 0
   and no padding, so clearance is taken from the top inset rather than from
   padding, which that sheet zeroes. Both forms are covered. */
#desktop {
  padding-top: 28px;
}

#desktop.clut-free {
  top: 28px;
  height: calc(100% - 78px);
}

/* defect 22: the clock reads as a clock, with the date beside it and a
   meridiem after it. The date sits in the lighter secondary ink so the time
   stays the thing you read first. */
#os-halo .when-d {
  color: var(--os-text-2);
  font-family: var(--os-ui);
  font-size: 11.5px;
  white-space: nowrap;
  /* the gap is real space rather than two trailing spaces in a text node, so
     the date and the time never read as one string */
  margin-right: 8px;
}

#os-halo .when-mer {
  font-family: var(--os-mono);
  font-size: 11px;
  color: var(--os-text-2);
  letter-spacing: 0.02em;
  white-space: nowrap;
}

@media (max-width: 700px) {
  /* on a phone the bar keeps the pill and drops the menu items, which is
     what a phone status bar is */
  #os-menubar {
    height: 24px;
    gap: 8px;
    padding: 0 8px;
  }

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

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

  #desktop {
    padding-top: 24px;
  }

  #desktop.clut-free {
    top: 24px;
    height: calc(100% - 74px);
  }

  /* a phone bar has no room for a weekday, so the time and the battery keep
     the space and the date stands down */
  #os-halo .when-d {
    display: none;
  }
}

@media (max-width: 620px) {
  /* clutter.css owns the home-screen grid. The 24 px padding above is for
     the 621-700 band, where the desk is still free-positioned under a
     24 px bar. Below 620 that padding parks a flow note on top of the
     first icon row. */
  #desktop,
  #desktop.clut-free {
    top: auto;
    /* same pad clutter.css sets: bar plus toast. This sheet loads later. */
    padding: calc(64px + env(safe-area-inset-top, 0px)) 12px calc(168px + env(safe-area-inset-bottom, 0px));
    height: calc(100% - 72px);
  }
}

/* ===========================================================================
   Defect 23: the Start control carries OS meaning.

   The mark is ours and stays, but at 25x22 next to the word Start it read as
   a pair of spectacles rather than a system button. It is given the ring a
   system button gets, so its role is legible before its shape is.
   =========================================================================== */
#dock-box .dock-btn#start-btn {
  gap: 8px;
}

#dock-box .dock-btn#start-btn .pd-mark {
  width: 22px;
  height: 22px;
  padding: 3px;
  border-radius: 7px;
  background: rgba(255, 255, 255, 0.10);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
  transition: background-color 140ms ease, box-shadow 140ms ease;
}

#dock-box .dock-btn#start-btn:hover .pd-mark,
#dock-box .dock-btn#start-btn:focus-visible .pd-mark {
  background: rgba(169, 155, 255, 0.26);
  box-shadow: inset 0 0 0 1px rgba(169, 155, 255, 0.45);
}

#dock-box .dock-btn#start-btn[aria-expanded="true"] .pd-mark {
  background: rgba(169, 155, 255, 0.34);
}

/* ===========================================================================
   Defect 24: the running indicator tells the truth.

   Measured before: two windows were open and no dock pin was lit, because
   neither Notepad nor the Task Manager is pinned, so pekan/dock.js had
   nothing to light. The dock now also carries a tile for a running app that
   has no pin, and both the pin dot and the tile dot are drawn here in one
   grammar so "running" looks the same wherever it appears.
   =========================================================================== */
#dock-box .dock-btn.run::after,
#dock-box #taskbar > a::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 3px;
  transform: translateX(-50%);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--pm-lavender);
  opacity: 0.75;
  transition: width 160ms var(--pm-spring), opacity 160ms ease;
}

/* the focused app's dot stretches into a bar, so "running" and "the one you
   are looking at" are two different readings rather than one */
#dock-box .dock-btn.run.foc::after,
#dock-box #taskbar > a.foc::after {
  width: 14px;
  border-radius: 3px;
  opacity: 1;
}

/* a minimised window is running but not on screen: hollow dot */
#dock-box #taskbar > a.min::after {
  background: none;
  box-shadow: inset 0 0 0 1.5px var(--pm-lavender);
  opacity: 0.8;
}

#dock-box .dock-btn,
#dock-box #taskbar > a {
  position: relative;
}

/* ===========================================================================
   Defect 18 and 19: the desktop icon grid and one truncation rule.

   pekan/clutter.js owns where the 66 objects sit and is not edited here.
   What this sheet owns is how they are drawn: every label follows one rule,
   two lines then an ellipsis, so the three appearances the review saw become
   one. Measured before: the rule was already uniform in CSS, but a label of
   exactly one short line and a label of two long lines look like different
   rules unless the label box is a fixed height. It is now.
   =========================================================================== */
.b.clut .clut-label,
.b.clut > p {
  /* a fixed two line box: one rule, one silhouette, whatever the name */
  height: 26px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-word;
}

/* ===========================================================================
   Defect 20, the part this agent owns: how the desktop RENDERS its objects.

   New artwork belongs to the icon agent and is requested in
   fleet/requests/icons.md. What is fixed here is the render: a folder, an
   archive, an image and an application are given different silhouettes at a
   glance through the well behind the art, which is a rendering decision and
   not new artwork.
   =========================================================================== */
.b.clut .clut-art,
.b.clut > img {
  transition: transform 140ms var(--pm-spring);
}

/* a folder sits flat on the desk, no well */
.b.clut[data-kind="folder"] > img {
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.45));
}

/* an image file is shown as a print: a light mount behind the art */
.b.clut[data-kind="image"] > img {
  background: rgba(255, 255, 255, 0.10);
  padding: 3px;
  border-radius: 3px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.42), inset 0 0 0 1px rgba(255, 255, 255, 0.16);
}

/* an archive is a stack: a second edge peeking out behind it */
.b.clut[data-kind="archive"] {
  position: relative;
}

.b.clut[data-kind="archive"] > img {
  border-radius: 4px;
  box-shadow: 3px 3px 0 -1px rgba(255, 255, 255, 0.14), 5px 5px 0 -2px rgba(255, 255, 255, 0.08);
}

/* an application gets the rounded well an app icon has everywhere */
.b.clut[data-kind="app"] > img {
  border-radius: 9px;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.46);
}

/* a document keeps a paper edge */
.b.clut[data-kind="doc"] > img {
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.40);
}

/* a shortcut carries the arrow badge every OS puts on a link, drawn rather
   than imported so no vendor artwork is involved */
.b.clut[data-shortcut="1"] > img {
  position: relative;
}

.b.clut[data-shortcut="1"]::before {
  content: "";
  position: absolute;
  left: 50%;
  margin-left: 4px;
  top: 34px;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  background: rgba(18, 15, 26, 0.92);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.20);
  z-index: 2;
}

.b.clut[data-shortcut="1"]::after {
  content: "";
  position: absolute;
  left: 50%;
  margin-left: 7.5px;
  top: 38.5px;
  width: 6px;
  height: 6px;
  border-top: 1.5px solid var(--os-text);
  border-right: 1.5px solid var(--os-text);
  transform: rotate(-45deg);
  z-index: 3;
}

/* ===========================================================================
   Defect 25: Software Update appears once.

   The object is homed in Tools (pekan/funnels.js) so the desk never paints
   it as a tile. The dock key is the system channel on desktop widths. On a
   phone the dock key stands down (craft.css) and Tools is the door, with
   the Files pin opening the same folder. This hide is the belt: if a
   funnel ever features the object, it still must not become a second desk
   prop. Explorer files are not .b.clut, so the homed copy stays reachable.
   =========================================================================== */
.b.clut[data-clut="update"] {
  display: none;
}

/* Sound is a utility, not a brand control. convert.css paints #os-sound.on
   purple; this sheet loads later and returns the glyph to the bar ink.
   On and muted are told apart by the speaker drawing itself. */
#os-sound,
#os-sound.on {
  color: var(--os-text-2, #c4c0d0);
  background: transparent;
}

#os-sound.on {
  color: var(--os-text, #f3f0fa);
}

#os-sound:hover,
#os-sound.on:hover {
  color: var(--os-text, #f3f0fa);
  background: rgba(255, 255, 255, 0.10);
}

/* Menu titles, not website nav. A system bar names the OS and two
   always-available tools. Hover is a quiet wash, not a pill. */
#os-menubar .mb-item {
  padding: 1px 7px;
  border-radius: 4px;
  font-weight: 600;
  color: var(--os-text);
}

#os-menubar .mb-item:hover {
  background: rgba(255, 255, 255, 0.08);
  color: var(--os-text);
}
