/* ============================================================================
   Vague Presence OS — os/css/system.css
   Owner: design-lead.  Specification: docs/design/DESIGN-SYSTEM.md
   Token source of truth, kept byte-identical: docs/design/tokens.css

   Contains, and contains only:
     1. @font-face
     2. the :root token block
     3. the reset
     4. every Platinum primitive (design system 8.1 - 8.26)

   Layout, positioning, the desktop grid, the layer stack and anything specific
   to one screen belong to os/css/shell.css (app-frontend).

   THE RULE THIS FILE IS REVIEWED AGAINST: no literal colour, size, duration or
   easing appears outside the :root block.  One documented exception exists —
   the sheet-mode media prelude near the bottom — because a media query cannot
   read a custom property.  Its value is declared as --vp-sheet-breakpoint in
   :root and stated nowhere else.

   Reference: Mac OS 8.5 "Platinum".  No Apple marks, no Apple fonts, no Apple
   icon art.  The menu mark is a lemon.
   ============================================================================ */

/* ==========================================================================
   1. TYPEFACE
   ChicagoFLF, public domain — Robin Casady's release, 2014-01-30.  The
   provenance statement ships beside the files as
   os/assets/font/README.ChicagoFLF; sakofchit/system.css, where the binaries
   come from, carries no licence statement at all.
   One src, comma-separated.  font-display: block, never swap — a pixel font
   flashing in as Helvetica breaks the illusion, and the illusion is the
   product.
   ========================================================================== */
@font-face {
  font-family: "ChicagoFLF";
  src: url("../assets/font/ChicagoFLF.woff2?v=53") format("woff2"),
       url("../assets/font/ChicagoFLF.woff?v=53")  format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: block;
}

:root {

  /* ==========================================================================
     1. NEUTRAL RAMP
     Nine steps of the 16-step 0x11 system ramp (#000000, #111111 … #FFFFFF).
     Indices are positions on that full ramp, so the gaps are visible and
     deliberate. Do not fill the gaps. Do not introduce a grey that is not here.
     ========================================================================== */
  --vp-grey-0:    #FFFFFF;   /* [DER] white */
  --vp-grey-1:    #EEEEEE;   /* [DER] */
  --vp-grey-2:    #DDDDDD;   /* [DER] the Platinum face */
  --vp-grey-3:    #CCCCCC;   /* [DER] */
  --vp-grey-5:    #AAAAAA;   /* [DER] */
  --vp-grey-8:    #777777;   /* [DER] */
  --vp-grey-9:    #666666;   /* [A11Y] */
  --vp-grey-10:   #555555;   /* [A11Y] */
  --vp-grey-15:   #000000;   /* [DER] black */

  /* ==========================================================================
     2. ACCENT
     HIG thig-58: under Platinum the accent colour applies to exactly four
     things — scroll bar indicators, progress indicators, slider indicators and
     focus rings. This product has no sliders, and its focus ring departs (see
     section 6). So the accent appears on two elements only.
     Values are legal entries in the Mac 6x6x6 colour cube (00/33/66/99/CC/FF).
     ========================================================================== */
  --vp-accent:        #6666CC;   /* [DER] "lavender", HIG thig-47 */
  --vp-accent-light:  #9999FF;   /* [DER] bevel highlight on an accent surface */
  --vp-accent-dark:   #333399;   /* [DER] bevel shadow, barber-pole stripe, and
                                    the body of an open menu-bar title (D-27) */
  --vp-accent-deep:   #000099;   /* [DER] the bottom row of an open menu-bar
                                    title. Measured #000088 on the Mac OS 8.1
                                    reference; #000099 is the cube-legal
                                    neighbour and the difference is one 0x11
                                    step. Derived from --vp-accent, never
                                    written as a literal outside this block. */

  /* Alert red. HIG thig-42: a movable alert box carries red highlights on its
     title bar; a non-movable alert carries a red border around its placard. */
  --vp-alert-red:     #CC0000;   /* [A11Y] cube-legal; 4.33:1 on the face */

  /* ==========================================================================
     3. ICON PALETTE — icon art only
     Never used for chrome, never used to carry state. Every icon must remain
     identifiable with these values replaced by white, because the black 1px
     outline is what actually carries the shape.
     ========================================================================== */
  --vp-icon-lemon:        #FFCC00;   /* [DER] */
  --vp-icon-lemon-shade:  #CC9900;   /* [DER] */
  --vp-icon-leaf:         #669933;   /* [DER] */

  /* The four ICON ROLES. Icon art paints through these and never through the
     ramp directly, because a selected desktop icon (8.14) darkens by
     re-pointing the roles at lower steps of the same ramp. A role is a name a
     scope can rebind; a ramp step is not — rebinding --vp-grey-0 to
     var(--vp-grey-8) inside a scope that also rebinds --vp-grey-8 is a
     custom-property cycle, and the cycle is why this layer exists rather than
     the art naming greys. No new colour enters the system here: every value
     below is one of the nine. */
  --vp-icon-outline:      var(--vp-ink);       /* the 1px outline, rule 3 */
  --vp-icon-paper:        var(--vp-grey-0);    /* white inside an icon */
  --vp-icon-face:         var(--vp-grey-2);    /* the Platinum face */
  --vp-icon-shade:        var(--vp-grey-5);    /* the one mid grey, rule 4 */
  /* client 2026-09-04: folders are blue. Scoped to folder icons only (system.css
     §9 folder rule); selected pair keeps the darkening step every icon gets. */
  --vp-icon-folder-face:           #9AB2E6;
  --vp-icon-folder-shade:          #6F8BD0;
  --vp-icon-folder-face-selected:  #5E75B0;
  --vp-icon-folder-shade-selected: #455A8E;

  /* client 2026-09-04: app accent palette (apps only — never chrome). Nine swatches, verbatim. */
  --vp-accent-app-green: #1A7A3A;
  --vp-accent-app-purple: #5B1F8C;
  --vp-accent-app-blue: #1B4ED8;
  --vp-accent-app-red: #C13A0C;
  --vp-accent-app-amber: #D18A00;
  --vp-accent-app-lime: #6BA10E;
  --vp-accent-app-magenta: #A11FA6;
  --vp-accent-app-teal: #0A8F86;
  --vp-accent-app-sky: #0BA3E3;
  /* 2x2 pinstripe tiles in each accent, white + accent, same construction as --vp-pattern-pinstripe */
  --vp-pattern-pinstripe-green: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX///8aejpXr70WAAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");
  --vp-pattern-pinstripe-purple: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX///9bH4wcf9O6AAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");
  --vp-pattern-pinstripe-blue: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX///8bTtijQ6eCAAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");
  --vp-pattern-pinstripe-red: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX////BOgzpsL1bAAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");
  --vp-pattern-pinstripe-amber: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX////RigAY5fy4AAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");
  --vp-pattern-pinstripe-lime: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX///9roQ5B5FcQAAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");
  --vp-pattern-pinstripe-magenta: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX///+hH6Z/l+xqAAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");
  --vp-pattern-pinstripe-teal: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX///8Kj4bglfQ5AAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");
  --vp-pattern-pinstripe-sky: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX///8Lo+PlvmB3AAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");

  /* ==========================================================================
     4. SURFACES
     ========================================================================== */
  --vp-surface-chrome:    #DDDDDD;  /* window frame band, title-bar plate, menu
                                       face, dialog face, control face, placards */
  --vp-surface-recessed:  #CCCCCC;  /* pressed placard, back tab, disabled
                                       control face, list-box well */
  --vp-surface-track:     #EEEEEE;  /* scroll bar track, progress track */
  --vp-surface-content:   #FFFFFF;  /* [HIG thig-58] the content region of a
                                       document window stays white */
  --vp-surface-pressed:   #666666;  /* [A11Y] pressed push-button face */
  --vp-surface-selected:  #000000;  /* [HIG HIGuidelines-191] the default
                                       highlight colour is always black */

  /* ==========================================================================
     5. INK
     ========================================================================== */
  --vp-ink:          #000000;
  --vp-ink-dim:      #555555;   /* [A11Y] disabled / deactivated text */
  --vp-ink-inverse:  #FFFFFF;   /* on --vp-surface-selected and -pressed */

  /* ==========================================================================
     6. STRUCTURE
     Every control boundary in this system is one black pixel. That is what
     makes the 3:1 boundary requirement pass everywhere at 15:1 or better, and
     it is HIG-consistent (push buttons, edit-text fields, list boxes, pop-up
     menus, icons and the modal frame are all specified with a black line).
     The greys below are bevel — decorative, and exempt.
     ========================================================================== */
  --vp-transparent:       transparent;  /* the only non-paint value in the
                                           system. Never a colour with alpha. */
  --vp-line:              #000000;
  --vp-line-etch-dark:    #777777;  /* [A11Y] upper line of an etched rule */
  --vp-line-etch-light:   #FFFFFF;  /* lower line of an etched rule */

  --vp-bevel-hi-outer:    #FFFFFF;  /* top + left, outermost pixel */
  --vp-bevel-hi-inner:    #EEEEEE;  /* top + left, second pixel */
  --vp-bevel-lo-outer:    #777777;  /* bottom + right, outermost pixel */
  --vp-bevel-lo-inner:    #AAAAAA;  /* bottom + right, second pixel */

  --vp-pinstripe-light:   #FFFFFF;
  --vp-pinstripe-dark:    #777777;
  --vp-pinstripe-period:  2px;      /* 1px light over 1px dark */

  /* The four Platinum bevels, composed once. "Bevel(2)" in the design system
     is --vp-bevel-2; the pressed and recessed treatment is --vp-bevel-2-in.
     Listed outermost first: an earlier shadow paints over a later one. */
  --vp-bevel-2:
      inset  1px  1px 0 0 #FFFFFF, inset -1px -1px 0 0 #777777,
      inset  2px  2px 0 0 #EEEEEE, inset -2px -2px 0 0 #AAAAAA;
  --vp-bevel-2-in:
      inset  1px  1px 0 0 #777777, inset -1px -1px 0 0 #FFFFFF,
      inset  2px  2px 0 0 #AAAAAA, inset -2px -2px 0 0 #EEEEEE;
  /* The window frame band. Four whole pixels inside the 1px black outer line:
     a raised band with a recessed inner lip.
       left + top,     outside -> in:  #FFFFFF #DDDDDD #DDDDDD #777777
       right + bottom, outside -> in:  #777777 #DDDDDD #DDDDDD #FFFFFF */
  --vp-window-band:
      inset  1px  1px 0 0 #FFFFFF, inset -1px -1px 0 0 #777777,
      inset  3px  3px 0 0 #DDDDDD, inset -3px -3px 0 0 #DDDDDD,
      inset  4px  4px 0 0 #777777, inset -4px -4px 0 0 #FFFFFF;
  --vp-bevel-1:    inset  1px  1px 0 0 #FFFFFF, inset -1px -1px 0 0 #777777;
  --vp-bevel-1-in: inset  1px  1px 0 0 #777777, inset -1px -1px 0 0 #FFFFFF;

  /* The three menu-chrome bevels, measured off the Mac OS 8.1 reference and
     composed here so no primitive spells a colour. See 8.4 and 8.5.

     --vp-bevel-menubar  the bar's own rows: 1px #FFFFFF at the top, 1px shade
                         directly above its 1px black rule. Inset rather than a
                         border so an open title paints over both rows, exactly
                         as Platinum does.
     --vp-bevel-menu     a menu panel's INNER bevel, inside its 1px black
                         frame: 1px #FFFFFF along the top and the left, 1px
                         shade along the right and the bottom. Same geometry as
                         --vp-bevel-1, one ramp step lighter on the shade.
     --vp-bevel-accent   the open menu-bar title: 1px --vp-accent across the
                         top, 1px --vp-accent-deep across the bottom, over an
                         --vp-accent-dark face.

     The shade is --vp-bevel-lo-inner (#AAAAAA); the reference measures
     #999999, which is not a step of the 0x11 ramp. One step, invisible in
     situ — section 3, "the details that do not matter". */
  --vp-bevel-menubar:
      inset 0  1px 0 0 var(--vp-bevel-hi-outer),
      inset 0 -1px 0 0 var(--vp-bevel-lo-inner);
  --vp-bevel-menu:
      inset  1px  1px 0 0 var(--vp-bevel-hi-outer),
      inset -1px -1px 0 0 var(--vp-bevel-lo-inner);
  --vp-bevel-accent:
      inset 0  1px 0 0 var(--vp-accent),
      inset 0 -1px 0 0 var(--vp-accent-deep);

  /* Focus ring: two-tone, so it survives every surface in the system including
     black selections and the desktop pattern. 2px total. */
  --vp-focus-outer:   #FFFFFF;
  --vp-focus-inner:   #000000;
  --vp-focus-width:   1px;   /* per ring; 2px total */
  --vp-focus-offset:  1px;
  --vp-focus-offset-total: 3px;  /* offset + both rings; the outer white ring
                                    sits at this inset, leaving the 1px gap */

  /* ==========================================================================
     7. PATTERN TILES
     8x8, 1-bit, palette PNG. Render with image-rendering: pixelated and
     background-size: 8px 8px. 651 bytes of PNG in total; no extra requests.
     RULE: every pixel value in a desktop pattern must be #777777 or lighter,
     so that black icon labels clear 4.5:1 and the black window frame clears
     3:1 against every pixel the desktop can contain. Do not add a pattern that
     breaks this.
     ========================================================================== */
  --vp-pattern-size: 8px;

  /* AA55AA55AA55AA55 — ink #969696 on paper #A5A5A5. Default desktop. */
  --vp-pattern-gray: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEWlpaWWlpbpLR/sAAAADklEQVR42mNYxRDKgIQBIUQD/TZLIakAAAAASUVORK5CYII=");
  --vp-pattern-sky: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEXG0d+6xtULpJYVAAAADklEQVR42mNYxRDKgIQBIUQD/TZLIakAAAAASUVORK5CYII=");   /* client 2026-09-04: #C6D1DF / #BAC6D5 AA55 checker, subtle dither — the default wallpaper */

  /* 8822882288228822 — ink #969696 on paper #C6C6C6. */
  --vp-pattern-light-gray: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEXGxsaWlpaQTDdoAAAADklEQVR42mPoYFBiQMIAFugCqWF0/nsAAAAASUVORK5CYII=");

  /* 77DD77DD77DD77DD — ink #777777 on paper #969696. */
  --vp-pattern-dark-gray: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEWWlpZ3d3dXlFUiAAAADklEQVR42mMoZ7jLgIQBKPgFUc5kiWcAAAAASUVORK5CYII=");

  /* 8844221188442211 — ink #777777 on paper #A5A5A5. Original composition. */
  --vp-pattern-weave: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEWlpaV3d3fRZbU4AAAAEklEQVR42mPoYHBhUGIQZIDSABMOAf95RiAZAAAAAElFTkSuQmCC");

  /* 45-degree 4-on/4-off — ink #333399 on paper #6666CC. Indeterminate
     progress. Animate by translating background-position 8px, linear. */
  --vp-pattern-barberpole: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEVmZswzM5kKtpPCAAAAGElEQVR42mP4wFDBYMMgx8DP0M5wmOEhAB4QA/1BuFXTAAAAAElFTkSuQmCC");

  /* AA55 — #DDDDDD on #FFFFFF. Scroll bar and progress track stipple.
     May be flattened to --vp-surface-track with no measurable loss. */
  --vp-pattern-track: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX////d3d0cZ2AmAAAADklEQVR42mNYxRDKgIQBIUQD/TZLIakAAAAASUVORK5CYII=");

  /* AA55 — opaque black on transparent. One tile, two jobs: composited over an
     icon it darkens it for the selected state; used as a mask it ghosts a
     `building` app to 50%. */
  --vp-pattern-dither-mask: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEUAAAAAAAClZ7nPAAAAAnRSTlMA/1uRIrUAAAAOSURBVHjaY1jFEMqAhAEhRAP9NkshqQAAAABJRU5ErkJggg==");

  /* 2x2 — 1px #FFFFFF over 1px #777777. The title-bar pinstripe. Shipped as a
     tile rather than a repeating-linear-gradient so the 2px period survives a
     fractional devicePixelRatio with image-rendering: pixelated. */
  --vp-pattern-pinstripe: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX///93d3eqY6YFAAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");

  /* 2x2 — 1px #FFFFFF over 1px #CC0000. The movable-modal title bar. */
  --vp-pattern-pinstripe-alert: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAQMAAABIeJ9nAAAABlBMVEX////MAADNd7xaAAAADElEQVR42mNgYDgAAADEAMHSGxjZAAAAAElFTkSuQmCC");

  /* 4x1 and 1x4 — 2px #000000 alternating with 2px #FFFFFF. The drag outline
     and the rubber band: what an XOR marquee looked like on a 50% dither. */
  --vp-pattern-march-h: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAABlBMVEX///8AAABVwtN+AAAACklEQVR42mM4AAAAwgDB/9Yt3AAAAABJRU5ErkJggg==");
  --vp-pattern-march-v: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAEAQMAAAB1Fsd5AAAABlBMVEX///8AAABVwtN+AAAADklEQVR42mNoYGhgAAIABggBAZ5hOrgAAAAASUVORK5CYII=");

  /* ==========================================================================
     8. TYPE
     One face, one weight, two sizes. Bold is the QuickDraw smear, not a second
     file. There is no italic and no small system font — see the design system
     document, section 4.
     ========================================================================== */
  --vp-font-ui: "ChicagoFLF", "Pixelify Sans", ui-sans-serif, sans-serif;

  --vp-text-size:      12px;   /* [HIG thig-50] the system font */
  --vp-text-line:      16px;   /* [HIG thig-50] 12pt Chicago occupies 16px */
  --vp-text-size-2x:   24px;   /* integer 2x — touch fields, Calculator, boot */
  --vp-text-line-2x:   32px;

  --vp-text-bold-offset: 1px;  /* QuickDraw emboldening: draw again, 1px right */
  --vp-text-chicago-lsb: 2px;  /* [HIG thig-50] a 12pt Chicago glyph carries two
                                  preceding pixels. Subtract this from any
                                  intended optical left inset. */
  --vp-measure-max:    480px;  /* [DER] running text, ~66 characters */

  /* ==========================================================================
     9. SPACE — HIG Chapter 3, Layout Guidelines
     ========================================================================== */
  --vp-space-1:   1px;   /* [HIG] control to a utility-window edge */
  --vp-space-2:   2px;   /* [HIG] small bevel; separator line */
  --vp-space-3:   3px;   /* [HIG] medium bevel; group-box title side inset */
  --vp-space-4:   4px;   /* [HIG] minimum between clickable items; minimum to a
                            window or dialog edge; the window frame band */
  --vp-space-5:   5px;   /* [HIG] control to its label */
  --vp-space-6:   6px;   /* [HIG] preferred between clickable items — the extra
                            2px exists to leave room for a focus ring */
  --vp-space-8:   8px;   /* [HIG] button text to the button's outside line */
  --vp-space-10: 10px;   /* [HIG] stacked buttons; group-box side and bottom */
  --vp-space-12: 12px;   /* [HIG] side-by-side buttons; button to dialog edge;
                            group-box top; horizontal checkbox spacing */
  --vp-space-16: 16px;   /* [HIG] between GROUPS of controls */
  --vp-space-20: 20px;
  --vp-space-24: 24px;   /* [SPEC FI2] above the system-app icon block */

  /* Negatives. Inset offsets and bevel maths need them; spelling -1px inside a
     primitive would be a literal, and calc(var(--vp-space-1) * -1) everywhere
     is unreadable. */
  --vp-space-1-neg:  -1px;
  --vp-space-2-neg:  -2px;
  --vp-space-3-neg:  -3px;
  --vp-space-4-neg:  -4px;
  --vp-space-6-neg:  -6px;
  --vp-space-8-neg:  -8px;

  /* The document text inset. Running text in a white content region takes 8px
     on all four sides, less the Chicago left side bearing on the left so that
     the OPTICAL inset is 8px rather than 10px. One token because five surfaces
     need it — the Note Pad page (8.25), Read Me, the two legal windows and Get
     Info's comments box. Use it whole: padding: var(--vp-doc-text-inset). */
  --vp-doc-text-inset:                /* [DER] 8 8 8 6; see 8.25 */
      var(--vp-space-8) var(--vp-space-8) var(--vp-space-8)
      calc(var(--vp-space-8) - var(--vp-text-chicago-lsb));

  /* ==========================================================================
     10. RADII — four, and no others
     ========================================================================== */
  --vp-radius-0:       0;      /* windows, menus, fields, list boxes, widgets */
  --vp-radius-button:  3px;    /* [DER] push button, tab top corners, dock tab */
  --vp-radius-ring:    6px;    /* [DER] default-button ring = 3 + 3px offset */
  --vp-radius-round:   50%;    /* radio button only */

  /* ==========================================================================
     11. CONTROL METRICS — HIG Chapter 3 unless marked
     ========================================================================== */
  --vp-control-box:          12px;  /* [HIG] checkbox square, radio circle, and
                                       the title-bar widgets [DER] */
  --vp-control-row:          18px;  /* [HIG] whole checkbox/radio hit height */
  --vp-control-label-gap:     5px;  /* [HIG] */
  --vp-button-height:        20px;  /* [HIG] */
  --vp-button-min-width:     58px;  /* [HIG thig-52] OK/Cancel is 20 x 58 */
  --vp-button-text-inset:     8px;  /* [HIG] */
  --vp-button-gap-h:         12px;  /* [HIG] */
  --vp-button-gap-v:         10px;  /* [HIG] */
  --vp-default-ring-gap:      1px;  /* [HIG] white separation */
  --vp-default-ring-width:    3px;  /* [HIG] three black pixels */
  --vp-default-ring-reserve:  4px;  /* gap + width; reserve this around the
                                       button but do not count it in alignment */
  --vp-field-height:         22px;  /* [HIG] edit text */
  --vp-field-height-aligned: 20px;  /* [HIG] when aligned with a pop-up */
  --vp-field-frame:           2px;  /* [HIG] */
  --vp-popup-height:         20px;  /* [HIG] */
  --vp-static-text-height:   16px;  /* [HIG] */
  --vp-progress-height:      12px;  /* [HIG] */
  --vp-groupbox-inset-side:  10px;  /* [HIG] */
  --vp-groupbox-inset-top:   12px;  /* [HIG] */
  --vp-groupbox-inset-bot:   10px;  /* [HIG] */
  --vp-tab-height:           20px;  /* [DER] from the 20px control height */
  --vp-disclosure-gap:        5px;  /* [HIG] triangle to its text */

  /* ==========================================================================
     12. SHELL METRICS
     ========================================================================== */
  --vp-menubar-height:       20px;   /* [BRIEF] */
  --vp-titlebar-height:      19px;   /* [HIG thig-60 / HIGuidelines-112] */
  --vp-window-frame:          4px;   /* [SPEC SH4] drag region, all four sides */
  --vp-window-min-w:        200px;   /* [SPEC SH4] */
  --vp-window-min-h:        120px;   /* [SPEC SH4] */
  --vp-alert-width:         362px;   /* [DER] ONE width for every alert and
                                        every modal panel; derivation in 8.13 */
  --vp-scrollbar:            16px;   /* [BRIEF] */
  --vp-scrollbar-hit:        16px;   /* [R-03] the scroll bar keeps a 16px hit
                                        area on touch. It is a position
                                        indicator there, not the primary control:
                                        a 28px invisible extension would steal
                                        taps from the content beside it. */
  --vp-scroll-thumb-min:     16px;   /* [SPEC FI1] */
  --vp-growbox:              16px;   /* [DER] = scroll bar width */
  --vp-menu-item-height:     16px;   /* [DER] = the 12pt Chicago line box */
  --vp-menu-divider-height:   6px;   /* [DER] 2px space + 2px rule + 2px space */
  --vp-menu-mark-column:     16px;   /* [DER] 4px inset + 12px mark */
  --vp-menu-shortcut-inset:   8px;   /* [DER] */
  --vp-menu-title-inset:      8px;   /* [DER] each side of a menu-bar title */
  --vp-menu-title-min-w:     44px;   /* [R-01] menu-bar title minimum width on
                                        touch; the bar's 20px height never moves */
  --vp-menu-title-hit-ext:   12px;   /* [R-01] invisible downward hit extension,
                                        giving a 32px effective target */
  --vp-dock-tab-height:      19px;   /* [DER] = title bar height */
  --vp-dock-tab-min-label:   64px;   /* [SPEC SH5] */
  --vp-dock-tab-gap:          2px;   /* [DER] */
  --vp-icon-lg:              32px;   /* [HIG HIGuidelines-168] */
  --vp-icon-sm:              16px;   /* [HIG HIGuidelines-168] */
  --vp-icon-boot:            64px;   /* [DER] integer 2x of the large icon */
  --vp-icon-badge:           12px;   /* [DER] padlock, = the control unit */
  --vp-desktop-cell-w:       96px;   /* [SPEC SH2] label truncation width */
  --vp-desktop-cell-h:       68px;   /* [DER] 32 icon + 4 gap + 32 two-line label */
  --vp-desktop-cell-gap:     16px;   /* [SPEC SH2] */
  --vp-desktop-inset:         8px;   /* [SPEC SH2] from the right edge and the
                                        underside of the menu bar */
  --vp-zoom-hysteresis:       7px;   /* [HIG HIGuidelines-122] */
  --vp-dblclick-slop:         2px;   /* [HIG HIGuidelines-205] */

  /* ==========================================================================
     13. TOUCH
     Applies wherever (hover: none) matches, at ANY width — not at a breakpoint.
     The visual size of a Platinum control never scales; only its hit area and
     the row that contains it. A 24px checkbox stops being Platinum.
     ========================================================================== */
  --vp-touch-target:            44px;  /* [SPEC] */
  --vp-touch-titlebar-height:   44px;
  --vp-touch-button-height:     44px;
  --vp-touch-button-min-width:  88px;
  --vp-touch-field-height:      44px;
  --vp-touch-menu-item-height:  44px;
  --vp-touch-row-height:        44px;  /* checkbox / radio / list row */
  --vp-touch-text-size:         24px;  /* form controls only — integer 2x, and
                                          >= 16px so iOS does not zoom on focus */
  --vp-touch-text-line:         32px;
  --vp-touch-window-min-w:     320px;  /* three 44px widgets plus a title */
  --vp-touch-icon-cell:         88px;
  --vp-sheet-breakpoint:      1024px;  /* [SPEC] desktop mode at or above */

  /* ==========================================================================
     14. ELEVATION
     One shadow. Windows deliberately have none — see the design system
     document, section 8, load-bearing detail 4.
     ========================================================================== */
  --vp-shadow-menu: 1px 1px 0 0 #000000;   /* [HIG HIGuidelines-92] menus,
                                              pop-up menus and modal dialogs */

  /* ==========================================================================
     15. MOTION
     Platinum predates easing curves. linear is the only curve in this system.
     Only transform (translate), opacity and background-position may animate.
     ========================================================================== */
  --vp-ease:                 linear;
  --vp-dur-0:                    0ms;
  --vp-dur-screen-flash:        16ms;   /* [SPEC SH6] one animation frame */
  --vp-dur-menu-flash:          60ms;   /* [DER] per phase; 3 flashes = 360ms */
  --vp-dur-key-press:           80ms;   /* [SPEC SA5] */
  --vp-dur-kbd-activate:       133ms;   /* [HIG] eight ticks */
  --vp-dur-minimize:           200ms;   /* [SPEC SH5] */
  --vp-dur-reduced-pulse:      200ms;   /* [SPEC SH6] reduced-motion beep */
  --vp-dur-mode-switch:        300ms;   /* [SPEC SH9] */
  --vp-dur-barberpole:         200ms;   /* [DER] per 8px of travel */
  --vp-dur-touch-longpress:    400ms;   /* [SPEC MO4] */
  --vp-dur-boot-reduced:       600ms;   /* [SPEC SH1] */
  --vp-dur-boot-short:         800ms;   /* [SPEC SH1] */
  --vp-dur-boot-full:         2500ms;   /* [SPEC SH1] within 2.2-2.8s */
  --vp-dur-ratelimit:         5000ms;   /* [SPEC AC4] */
  --vp-dur-sticky-menu:      15000ms;   /* [HIG thig-55] */

  /* Control Panels -> Menus writes this (0-3, default 3). It is a count, not a
     duration, and it is declared here so the primitive always resolves. */
  --vp-menu-flash-count:         3;

  /* User-settable in Control Panels. Defaults are the Medium values. */
  --vp-dur-dblclick-slow:      750ms;   /* docs/API.md 10.2 freezes
                                           DOUBLE_CLICK_MS.slow at 750 (R8) */
  --vp-dur-dblclick:           500ms;   /* [DER] also the sticky-menu latch */
  --vp-dur-dblclick-fast:      300ms;
  --vp-dur-caret-slow:         800ms;
  --vp-dur-caret:              530ms;   /* [DER] classic CaretTime, 32 ticks */
  --vp-dur-caret-fast:         300ms;

  /* ==========================================================================
     16. Z BANDS — docs/BRIEF.md section 6
     Each band is a floor; z-index is derived from position in the ordered
     window array.
     ========================================================================== */
  --vp-z-desktop-icons:     0;
  --vp-z-windows:         100;
  --vp-z-palettes:       9000;
  --vp-z-menus:          9500;
  --vp-z-modals:         9800;
  --vp-z-menubar:        9900;
  --vp-z-drag-outline:   9999;
}

/* Reduced motion. Every duration collapses except the two the spec keeps: the
   boot dismissal and the outline pulse that replaces the screen flash. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --vp-dur-screen-flash:    0ms;
    --vp-dur-menu-flash:      0ms;
    --vp-dur-key-press:       0ms;
    --vp-dur-kbd-activate:    0ms;
    --vp-dur-minimize:        0ms;
    --vp-dur-mode-switch:     0ms;
    --vp-dur-barberpole:      0ms;
    --vp-dur-boot-full:     600ms;
    --vp-dur-boot-short:    600ms;
  }
}

/* ==========================================================================
   RESET
   Small on purpose. Everything here exists because a browser default fights
   the pixel grid or the illusion.
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html {
  font-family: var(--vp-font-ui);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
  background: var(--vp-surface-chrome);
  /* All five rendering rules are mandatory — design system 4. */
  -webkit-font-smoothing: none;
  font-smooth: never;
  font-synthesis: none;
  font-kerning: none;
  font-variant-ligatures: none;
  text-rendering: optimizeSpeed;
  letter-spacing: 0;
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
  -webkit-tap-highlight-color: var(--vp-transparent);
}

body { margin: 0; }

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ol, ul {
  margin: 0; padding: 0;
}
ol, ul { list-style: none; }

img, svg { display: block; max-inline-size: 100%; }
svg { image-rendering: pixelated; shape-rendering: crispEdges; }

button, input, select, textarea {
  font: inherit; color: inherit; letter-spacing: inherit;
  margin: 0; border-radius: var(--vp-radius-0);
  -webkit-font-smoothing: none; font-smooth: never;
}
button { background: none; border: 0; padding: 0; text-align: start; }
:where(button, [role="button"], summary) { cursor: default; }

/* Focus is drawn by .vp-focus (8.19) on :focus-visible only. Never on a
   pointer click — SPEC SH7. */
:focus { outline: 0; }

/* No transparency of any kind, so a selection is the black highlight. */
::selection { background: var(--vp-surface-selected); color: var(--vp-ink-inverse); }

/* ==========================================================================
   THE SPRITE AND ITS GLYPHS
   os/lib/design/icons.js exports SPRITE as a string; app-frontend inserts it
   once, first thing in <body>. .vp-glyph elements point <use> at it.
   ========================================================================== */
.vp-sprite { position: absolute; inline-size: 0; block-size: 0; overflow: hidden; }
.vp-icon, .vp-glyph { display: block; flex: none; }
.vp-glyph {
  color: var(--vp-ink);
  fill: currentColor;
  /* A glyph is not square — a scroll arrow is 7x4. icons.js writes width and
     height onto every glyph it builds; `auto` lets those attributes win. */
  inline-size: auto;
  block-size: auto;
}
/* Safety net for a glyph written by hand with no attributes, so it can never
   fall back to the SVG default of 300x150. */
.vp-glyph:not([width]) {
  inline-size: var(--vp-control-box);
  block-size: var(--vp-control-box);
}
.vp-icon--lg { inline-size: var(--vp-icon-lg); block-size: var(--vp-icon-lg); }
.vp-icon--sm { inline-size: var(--vp-icon-sm); block-size: var(--vp-icon-sm); }
.vp-icon--badge,
.vp-icon--menu { inline-size: var(--vp-icon-badge); block-size: var(--vp-icon-badge); }
.vp-icon--boot { inline-size: var(--vp-icon-boot); block-size: var(--vp-icon-boot); }

/* Bold is the QuickDraw algorithm: draw the glyph again one pixel right.
   font-synthesis: none above stops the browser also faking one. */
.vp-bold { text-shadow: var(--vp-text-bold-offset) 0 0 currentColor; }

/* Chicago carries two preceding pixels. Subtract them from an optical inset. */
.vp-lsb { margin-inline-start: calc(var(--vp-text-chicago-lsb) * -1); }

/* ==========================================================================
   8.19  FOCUS RING, DRAG OUTLINE, RUBBER BAND, SCREEN FLASH
   Placed first because eight later primitives compose it.
   Two tones, so one of them always contrasts: black against light chrome
   15.46:1, against white content 21:1, against the darkest legal desktop
   pixel 4.69:1; white against a black selection 21:1.
   ========================================================================== */
.vp-focus { position: relative; }

.vp-focus:focus-visible,
.vp-focus--on {                       /* --on is for a ring on a composite
                                         control, e.g. a checkbox AND its label */
  outline: var(--vp-focus-width) solid var(--vp-focus-inner);
  outline-offset: var(--vp-focus-offset);
}
.vp-focus:focus-visible::after,
.vp-focus--on::after {
  content: "";
  position: absolute;
  inset: calc(var(--vp-focus-offset-total) * -1);
  border: var(--vp-focus-width) solid var(--vp-focus-outer);
  border-radius: inherit;
  pointer-events: none;
}

/* Drag outline (SH4) and rubber band (SH2). 1px, alternating 2px black and 2px
   white along its length. The window does not move until release. */
.vp-marchers,
.vp-rubberband {
  position: absolute;
  z-index: var(--vp-z-drag-outline);
  pointer-events: none;
  background-color: var(--vp-transparent);
  background-image: var(--vp-pattern-march-h), var(--vp-pattern-march-h),
                    var(--vp-pattern-march-v), var(--vp-pattern-march-v);
  background-repeat: repeat-x, repeat-x, repeat-y, repeat-y;
  background-position: left top, left bottom, left top, right top;
  background-size: var(--vp-space-4) var(--vp-space-1),
                   var(--vp-space-4) var(--vp-space-1),
                   var(--vp-space-1) var(--vp-space-4),
                   var(--vp-space-1) var(--vp-space-4);
  image-rendering: pixelated;
}

/* Screen flash — the silent system beep. The desktop inverts for exactly one
   animation frame, then returns. No audio, ever. */
.vp-screen-flash {
  position: fixed;
  inset: 0;
  z-index: var(--vp-z-drag-outline);
  pointer-events: none;
  background: var(--vp-grey-0);
  mix-blend-mode: difference;
  animation: vp-flash var(--vp-dur-screen-flash) step-end 1 forwards;
}
@keyframes vp-flash { to { visibility: hidden; } }

/* Its reduced-motion replacement: a 200ms 2px outline pulse on the offending
   element (SH6, SA3). */
.vp-pulse {
  animation: vp-pulse var(--vp-dur-reduced-pulse) step-end 2;
}
@keyframes vp-pulse {
  from { box-shadow: 0 0 0 var(--vp-space-2) var(--vp-line); }
  to   { box-shadow: 0 0 0 var(--vp-space-2) var(--vp-surface-chrome); }
}

/* ==========================================================================
   8.20  THE DESKTOP DITHER
   AA55AA55AA55AA55 in #969696 and #A5A5A5, tiled from the top-left of the area
   below the menu bar. Every pixel in every pattern is #777777 or lighter —
   that floor rule is what lets an icon label sit on the pattern with no plate.
   ========================================================================== */
.vp-desktop {
  background-color: var(--vp-transparent);
  background-image: var(--vp-pattern-sky);
  background-repeat: repeat;
  background-position: left top;
  background-size: var(--vp-pattern-size) var(--vp-pattern-size);
  image-rendering: pixelated;
}
.vp-desktop--grey50    { background-image: var(--vp-pattern-gray); }
.vp-desktop--sky       { background-image: var(--vp-pattern-sky); }
.vp-desktop--light-gray,
.vp-desktop--dots      { background-image: var(--vp-pattern-light-gray); }
.vp-desktop--dark-gray,
.vp-desktop--grid      { background-image: var(--vp-pattern-dark-gray); }
.vp-desktop--weave     { background-image: var(--vp-pattern-weave); }

/* ==========================================================================
   8.1  WINDOW FRAME
   4px, on ALL FOUR SIDES — the single fastest way to read as OS 8 rather than
   as generic old Mac. The whole band is the drag region.
   Left/top,  outside -> in:  #000000 #FFFFFF #DDDDDD #777777
   Right/bottom, outside -> in: #000000 #777777 #DDDDDD #FFFFFF
   Windows cast NO shadow. Adding one is the most common single mistake in web
   recreations of this appearance.
   Markup:
     .vp-window > .vp-window__titlebar + .vp-window__body > .vp-window__content
   ========================================================================== */
.vp-window {
  position: absolute;
  min-inline-size: var(--vp-window-min-w);
  min-block-size:  var(--vp-window-min-h);
  padding: var(--vp-window-frame);
  border: var(--vp-space-1) solid var(--vp-line);
  border-radius: var(--vp-radius-0);
  background: var(--vp-surface-chrome);
  box-shadow: var(--vp-window-band);       /* raised band, recessed inner lip */
  color: var(--vp-ink);
  /* contain: strict includes size containment (ARCHITECTURE section 14), so a
     window element MUST carry an explicit width and height. sys/windows.js
     guarantees one: every window is a geometry record. */
  contain: strict;
  isolation: isolate;
  overflow: hidden;
}
.vp-window__body {
  display: flex;
  flex-direction: column;
  block-size: 100%;
  background: var(--vp-surface-content);
  border: var(--vp-space-1) solid var(--vp-line);
  overflow: hidden;
}
.vp-window__content {
  flex: 1 1 auto;
  min-block-size: 0;
  background: var(--vp-surface-content);
  overflow: hidden;
}

/* Inactive: the face flattens to #DDDDDD with NO bevel and recedes. Three
   independent channels change — pinstripes, widgets, bevel — so any one of
   them identifies the state on its own. */
.vp-window--inactive { box-shadow: none; }

/* Collapsed: the window IS its title bar. The frame band is absent, not
   hidden. The block borders go too, so sys/windows.js's h = TITLEBAR_H is the
   title bar exactly under border-box sizing; the inline black lines stay, and
   the title bar supplies its own highlight row and its own black rule. */
.vp-window--collapsed {
  min-block-size: 0;
  padding: 0;
  border-block: 0;
}
.vp-window--collapsed .vp-window__body { display: none; }

/* Modeless and fixed windows never grow. */
.vp-window--fixed .vp-growbox { display: none; }

/* During a drag or a resize nothing inside a window may take a pointer event —
   the budget depends on it. */
.vp-window--interacting .vp-window__body { pointer-events: none; }

/* ==========================================================================
   8.2  TITLE BAR
   19px: 1px #FFFFFF highlight, a 16px pinstripe field (exactly the 12pt
   Chicago line box), a 1px #777777 shadow row, a 1px #000000 rule.
   The stripes BREAK for a 6px gap either side of the title and either side of
   every widget, leaving a solid #DDDDDD plate. That break is load-bearing.
   ========================================================================== */
.vp-window__titlebar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  block-size: var(--vp-titlebar-height);
  border-block-start: var(--vp-space-1) solid var(--vp-bevel-hi-outer);
  border-block-end:   var(--vp-space-1) solid var(--vp-line);
  box-shadow: inset 0 var(--vp-space-1-neg) 0 0 var(--vp-bevel-lo-outer);
  background-color: var(--vp-surface-chrome);
  background-image: var(--vp-pattern-pinstripe);
  background-repeat: repeat;
  background-position: left top;
  background-size: var(--vp-pinstripe-period) var(--vp-pinstripe-period);
  background-origin: padding-box;
  background-clip: padding-box;
  image-rendering: pixelated;
  overflow: hidden;
  cursor: default;
  user-select: none;
  touch-action: none;
}
.vp-window--inactive .vp-window__titlebar {
  background-image: none;                 /* no pinstripes when inactive */
}

.vp-window__title {
  padding-inline: var(--vp-space-6);      /* the 6px break either side */
  background: var(--vp-surface-chrome);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-inline-size: 100%;
}
.vp-window--inactive .vp-window__title { color: var(--vp-ink-dim); }

/* Widgets — 12x12, 3px from the top of the stripe field.
   Order left to right: close - title - zoom - collapse. */
.vp-window__widget {
  position: absolute;
  inset-block-start: var(--vp-space-3);
  inline-size: var(--vp-control-box);
  block-size: var(--vp-control-box);
  border: var(--vp-space-1) solid var(--vp-line);
  border-radius: var(--vp-radius-0);
  background: var(--vp-surface-chrome);
  /* the 6px plate that breaks the stripes, clipped by the bar's overflow */
  box-shadow: var(--vp-bevel-2), 0 0 0 var(--vp-space-6) var(--vp-surface-chrome);
}
.vp-window__widget--close    { inset-inline-start: var(--vp-space-4); }
.vp-window__widget--collapse { inset-inline-end:   var(--vp-space-4); }
.vp-window__widget--zoom {
  /* 4 + 12 + 4 — the collapse box's inset, its width, and the HIG minimum
     between clickable items. Zoom sits immediately left of collapse. */
  inset-inline-end: calc(var(--vp-space-4) + var(--vp-control-box) + var(--vp-space-4));
}
.vp-window__widget::before {
  content: "";
  position: absolute;
  inset: 0;
}
.vp-window__widget--zoom::before {
  /* a 6x6 outlined square in the upper-left of the interior */
  inset: 0 auto auto 0;
  inline-size: var(--vp-space-6);
  block-size: var(--vp-space-6);
  border: var(--vp-space-1) solid var(--vp-line);
}
.vp-window__widget--collapse::before {
  /* a 1px horizontal bar across the interior */
  inset: 50% 0 auto 0;
  block-size: var(--vp-space-1);
  background: var(--vp-line);
}
.vp-window__widget:active,
.vp-window__widget[aria-pressed="true"] {
  background: var(--vp-surface-recessed);
  box-shadow: var(--vp-bevel-2-in), 0 0 0 var(--vp-space-6) var(--vp-surface-chrome);
}
/* Absent on an inactive window — not dimmed, ABSENT. */
.vp-window--inactive .vp-window__widget { display: none; }

/* ==========================================================================
   8.3  RESIZE GRIP (GROW BOX)
   16x16, equal to the scroll bar width, where the two scroll bars meet.
   Resize anchors the top-left; the drag outline's bottom-right follows the
   pointer and the window jumps once on release. Never live-resize.
   ========================================================================== */
.vp-growbox {
  position: relative;
  inline-size: var(--vp-growbox);
  block-size: var(--vp-growbox);
  flex: none;
  background: var(--vp-surface-chrome);
  border-block-start: var(--vp-space-1) solid var(--vp-line);
  border-inline-start: var(--vp-space-1) solid var(--vp-line);
  cursor: default;
  touch-action: none;
}
.vp-growbox:active { box-shadow: var(--vp-bevel-2-in); }
/* Absent when the window is inactive. */
.vp-window--inactive .vp-growbox { display: none; }

/* ==========================================================================
   8.4  MENU BAR
   20px, pinned, full width, z 9900. It belongs to activeAppId, never to the
   focused window, and its height never changes at any viewport width or
   browser zoom. Flat — the menu bar is NOT pinstriped.
   ========================================================================== */
.vp-menubar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--vp-z-menubar);
  display: flex;
  align-items: stretch;
  block-size: var(--vp-menubar-height);
  padding-inline: var(--vp-space-8);
  border-block-end: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-surface-chrome);
  /* 1px #FFFFFF top row, 1px shade row above the black rule. Both are inset
     shadows, not borders, so a title button (a child, painted above an inset
     shadow) covers them when its menu is open -- the reference's open title
     runs the full 19px from the top of the bar down to the rule. */
  box-shadow: var(--vp-bevel-menubar);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  user-select: none;
}
.vp-menubar__spacer { flex: 1 1 auto; }

.vp-menubar__title,
.vp-menubar__clock,
.vp-menubar__app {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--vp-space-4);
  padding-inline: var(--vp-menu-title-inset);
  /* Transparent, not #DDDDDD: the bar's white top row and shade row must run
     unbroken through every title that is not open. */
  background: var(--vp-transparent);
  color: var(--vp-ink);
  white-space: nowrap;
}
.vp-menubar__clock { cursor: default; }

/* Open: the Platinum beveled accent highlight, full height from the top of the
   bar to its black rule -- 1px --vp-accent, an --vp-accent-dark body, 1px
   --vp-accent-deep. White text on the body measures 10.12:1 (D-27). */
.vp-menubar__title[aria-expanded="true"],
.vp-menubar__app[aria-expanded="true"],
.vp-menubar__overflow[aria-expanded="true"] {
  background: var(--vp-accent-dark);
  box-shadow: var(--vp-bevel-accent);
  color: var(--vp-ink-inverse);
}
/* The mark inverts with its title: a lemon outlined in --vp-ink would lose its
   silhouette on the accent. Scoped to the icon, so only the 1px outline the art
   draws with var(--vp-ink) flips -- nothing else in the button reads that
   token. */
.vp-menubar__title[aria-expanded="true"] .vp-icon,
.vp-menubar__app[aria-expanded="true"] .vp-icon,
.vp-menubar__overflow[aria-expanded="true"] .vp-glyph {
  --vp-ink: var(--vp-ink-inverse);
  color: var(--vp-ink-inverse);
}
/* Every item unavailable: dim the title — the menu still pulls down. */
.vp-menubar__title--dim { color: var(--vp-ink-dim); }

/* ==========================================================================
   8.5  MENU AND MENU ITEM
   Panel: 1px black border, #DDDDDD face, a 1px hard black shadow. Square
   corners, opening flush under its title with the left edges aligned.
   ========================================================================== */
.vp-menu {
  position: absolute;
  z-index: var(--vp-z-menus);
  padding: 0;
  border: var(--vp-space-1) solid var(--vp-line);
  border-radius: var(--vp-radius-0);
  background: var(--vp-surface-chrome);
  /* Inner bevel first, then the hard shadow: 1px #FFFFFF top and left, 1px
     shade right and bottom, inside the black frame, and the frame's own 1px
     hard shadow one pixel down and right. A menu opened from the bar sits at
     the bar's own black rule, and the bar (z 9900) paints over the panel
     (z 9500), so the visible top row is the white highlight -- which is exactly
     what the reference shows below its rule. */
  box-shadow: var(--vp-bevel-menu), var(--vp-shadow-menu);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  user-select: none;
}

.vp-menu__item {
  display: flex;
  align-items: center;
  block-size: var(--vp-menu-item-height);
  padding-inline-end: var(--vp-menu-shortcut-inset);
  color: var(--vp-ink);
  white-space: nowrap;
}
.vp-menu__mark {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--vp-menu-mark-column);
  block-size: var(--vp-menu-item-height);
}
/* M-1. The 16px icon rail, between the mark column and the label. Present only
   on a menu that carries at least one iconId — ui/menu.js appends the span and
   sets .vp-menu--icons — and then reserved on EVERY command row of that menu,
   icon or not, so the labels still start at one x. The row is 16px and the
   icon is 16px, which is why the icon fits with no vertical fudging: it is the
   same 12pt Chicago line box the whole bar is built on. */
.vp-menu__icon {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--vp-icon-sm);
  block-size: var(--vp-menu-item-height);
  margin-inline-end: var(--vp-space-4);
}
.vp-menu-sheet .vp-menu__icon { block-size: var(--vp-touch-menu-item-height); }
.vp-menu__label   { flex: 1 1 auto; }
.vp-menu__shortcut{
  flex: none;
  margin-inline-start: var(--vp-space-16);   /* the HIG group gap */
  text-align: end;
}

/* Highlighted: FULL-WIDTH inversion. The HIG's highlight colour is black. */
.vp-menu__item[aria-selected="true"],
.vp-menu__item.vp-menu__item--hot {
  background: var(--vp-surface-selected);
  color: var(--vp-ink-inverse);
}
/* ...and the icon inverts with the row. Only the OUTLINE has to move: it is
   #000000 on #000000 otherwise, and rule 3 says the outline is what carries
   the shape, so losing it loses the icon. The same reason the lemon mark
   inverts on an open menu-bar title (D-27). White outline on black is 21:1. */
.vp-menu__item[aria-selected="true"] .vp-menu__icon,
.vp-menu__item.vp-menu__item--hot   .vp-menu__icon {
  --vp-icon-outline: var(--vp-ink-inverse);
}
/* A disabled row's icon dims with its label, and drops the icon palette — a
   saturated lemon on a dimmed row reads as enabled. Outline #555555 on #DDDDDD
   is 5.49:1, the same ratio the label carries. */
.vp-menu__item[aria-disabled="true"] .vp-menu__icon {
  --vp-icon-outline:     var(--vp-ink-dim);
  --vp-icon-lemon:       var(--vp-grey-2);
  --vp-icon-lemon-shade: var(--vp-grey-5);
  --vp-icon-leaf:        var(--vp-grey-5);
}
/* Disabled: dimmed AND unhoverable AND skipped by keyboard traversal, so the
   state survives for anyone who cannot resolve 5.49:1 against 15.46:1. */
.vp-menu__item[aria-disabled="true"] {
  color: var(--vp-ink-dim);
  pointer-events: none;
}
.vp-menu__item[aria-disabled="true"] .vp-glyph { color: var(--vp-ink-dim); }

/* Flashing: inverts 60ms per phase, N times (0-3), then the menu closes. */
.vp-menu__item--flash {
  animation: vp-menu-flash calc(var(--vp-dur-menu-flash) * 2) step-end
             var(--vp-menu-flash-count);
}
@keyframes vp-menu-flash {
  0%   { background: var(--vp-surface-selected); color: var(--vp-ink-inverse); }
  50%  { background: var(--vp-surface-chrome);   color: var(--vp-ink); }
}

/* Etched divider — 6px: 2px space, 1px #777777 over 1px #FFFFFF, 2px space.
   Never gets a hover or a focus state. */
.vp-menu__divider {
  block-size: var(--vp-menu-divider-height);
  border: 0;
  margin: 0;
  padding: 0;
  background: var(--vp-surface-chrome);
  box-shadow:
      inset 0 var(--vp-space-2) 0 0 var(--vp-surface-chrome),
      inset 0 var(--vp-space-3) 0 0 var(--vp-line-etch-dark),
      inset 0 var(--vp-space-4) 0 0 var(--vp-line-etch-light);
  pointer-events: none;
}

/* ==========================================================================
   8.6  PUSH BUTTON
   20px tall, 58px minimum, 8px text inset each side excluding the black
   border, 3px radius.
   There is ONE button. No primary/secondary/tertiary, no ghost, no link, no
   icon-only, no destructive-red. There is a push button and there is a push
   button carrying the default ring.
   ========================================================================== */
.vp-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  block-size: var(--vp-button-height);
  min-inline-size: var(--vp-button-min-width);
  padding-inline: var(--vp-button-text-inset);
  border: var(--vp-space-1) solid var(--vp-line);
  border-radius: var(--vp-radius-button);
  background: var(--vp-surface-chrome);
  box-shadow: var(--vp-bevel-2);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
  white-space: nowrap;
  user-select: none;
}
.vp-button:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--vp-surface-pressed);
  box-shadow: var(--vp-bevel-2-in);
  color: var(--vp-ink-inverse);
}
.vp-button:disabled,
.vp-button[aria-disabled="true"],
/* A button in a background window renders disabled. */
.vp-window--inactive .vp-button {
  background: var(--vp-surface-recessed);
  box-shadow: none;
  border-color: var(--vp-ink-dim);
  color: var(--vp-ink-dim);
  pointer-events: none;
}

/* Default-button ring: 1px #FFFFFF separation, then a 3px #000000 ring at the
   6px concentric radius. Reserve 4px of clear space around the button but do
   NOT count the ring in alignment or in the 12px button-to-edge measurement —
   the ring is an attribute and does not change the button's size. */
.vp-button--default { position: relative; }
.vp-button--default::before {
  content: "";
  position: absolute;
  inset: calc((var(--vp-default-ring-gap) + var(--vp-default-ring-width)) * -1);
  border: var(--vp-default-ring-width) solid var(--vp-line);
  border-radius: var(--vp-radius-ring);
  pointer-events: none;
}

.vp-buttons {
  display: flex;
  align-items: center;
  gap: var(--vp-button-gap-h);            /* 12px side by side */
}
.vp-buttons--stacked {
  flex-direction: column;
  align-items: stretch;
  gap: var(--vp-button-gap-v);            /* 10px vertically stacked */
}

/* ==========================================================================
   8.7  TEXT INPUT (EDIT TEXT FIELD)
   22px. Outside -> in: 1px recessed bevel, 1px #000000, 18px white interior
   holding the 16px text box, 1px #000000, 1px bevel. The bevel sits OUTSIDE
   the black border and is excluded when measuring the field.
   Errors are never colour-only: the message is text, adjacent to its field.
   ========================================================================== */
.vp-field {
  display: block;
  inline-size: 100%;
  block-size: var(--vp-field-height);
  padding-inline: var(--vp-space-2);
  border: var(--vp-space-1) solid var(--vp-line);
  border-radius: var(--vp-radius-0);
  background: var(--vp-surface-content);
  box-shadow: var(--vp-bevel-1-in);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
  caret-color: var(--vp-ink);
}
.vp-field--aligned { block-size: var(--vp-field-height-aligned); }
.vp-field::placeholder { color: var(--vp-ink-dim); }
.vp-field:disabled,
.vp-field[aria-disabled="true"] {
  background: var(--vp-surface-chrome);
  border-color: var(--vp-ink-dim);
  color: var(--vp-ink-dim);
  box-shadow: none;
}
.vp-field--multiline {
  block-size: auto;
  padding-block: var(--vp-space-2);
  resize: none;
}
.vp-fields > * + * { margin-block-start: var(--vp-space-6); }   /* stacked: 6px */

/* --- Inline error (M-10) --------------------------------------------------
   An error message that is only a sentence is helper text; the round-2 critic
   read ours as exactly that. The system already owns a mark for "this stopped"
   — the Stop octagon (8.13, section 9 #17) — so the error row carries it at 12
   rather than inventing a badge, a banner or a red field. It is the ONE size
   the octagon is redrawn at outside 32.

   Markup, on the field's own row, immediately under the field it belongs to:

     <p class="vp-field-error" id="password-error">
       <svg class="vp-icon vp-icon--menu vp-field-error__mark" ...>
         <use href="#vp-i-alert-stop-12"/></svg>
       <span>Email or password did not match.</span>
     </p>

   with aria-describedby and aria-invalid="true" on the field. .vp-form-error is
   the same row for an error that belongs to the form rather than to one field
   (a 500, a dropped connection) and sits above the button row.

   The message text stays --vp-ink, not red: #CC0000 on the Platinum face is
   4.33:1 and would not clear AA as text. The red is in the mark, where it is a
   non-text indicator at 4.33:1 against the 3:1 bar, and the mark's own 1px
   black outline measures 15.46:1. Colour is therefore never the only channel —
   silhouette, position and the copy all carry it too. */
.vp-field-error,
.vp-form-error {
  display: flex;
  align-items: flex-start;
  gap: var(--vp-space-4);
  margin-block-start: var(--vp-space-2);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
}
.vp-form-error { margin-block-start: var(--vp-space-6); }
/* The 12px mark sits on the first line's optical centre: the Chicago line box
   is 16 and the mark is 12, so 2px down centres it on the cap height. */
.vp-field-error__mark,
.vp-form-error__mark { margin-block-start: var(--vp-space-2); }

/* ==========================================================================
   8.8  CHECKBOX     8.9  RADIO BUTTON
   The square is 12x12 and the circle is 12x12. THE BOX NEVER SCALES — a 24px
   checkbox stops being Platinum. Only the row grows, and only on touch.
   ========================================================================== */
.vp-check,
.vp-radio {
  display: flex;
  align-items: center;
  gap: var(--vp-control-label-gap);        /* 5px between the box and its label */
  block-size: var(--vp-control-row);
  color: var(--vp-ink);
  user-select: none;
}
.vp-check__box,
.vp-radio__box {
  position: relative;
  flex: none;
  display: block;
  inline-size: var(--vp-control-box);
  block-size: var(--vp-control-box);
  border: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-surface-content);
  box-shadow: var(--vp-bevel-1-in);
  appearance: none;
}
.vp-check__box { border-radius: var(--vp-radius-0); }
.vp-radio__box { border-radius: var(--vp-radius-round); }

.vp-check__box .vp-glyph { position: absolute; inset: 0; visibility: hidden; }
.vp-check__box[aria-checked="true"]  .vp-glyph,
.vp-check input:checked + .vp-check__box .vp-glyph { visibility: visible; }

/* Mixed: a centred 8x2 dash on the checkbox, a 6x2 dash on the radio. */
.vp-check__box[aria-checked="mixed"]::after,
.vp-radio__box[aria-checked="mixed"]::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  translate: -50% -50%;
  block-size: var(--vp-space-2);
  background: var(--vp-ink);
}
.vp-check__box[aria-checked="mixed"]::after { inline-size: var(--vp-space-8); }
.vp-radio__box[aria-checked="mixed"]::after { inline-size: var(--vp-space-6); }
.vp-check__box[aria-checked="mixed"] .vp-glyph { visibility: hidden; }

/* On: a 4px black dot, centred. */
.vp-radio__box[aria-checked="true"]::after,
.vp-radio input:checked + .vp-radio__box::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  translate: -50% -50%;
  inline-size: var(--vp-space-4);
  block-size: var(--vp-space-4);
  border-radius: var(--vp-radius-round);
  background: var(--vp-ink);
}

.vp-check:active .vp-check__box,
.vp-radio:active .vp-radio__box { background: var(--vp-surface-recessed); }

.vp-check[aria-disabled="true"],
.vp-radio[aria-disabled="true"] { color: var(--vp-ink-dim); pointer-events: none; }
.vp-check[aria-disabled="true"] .vp-check__box,
.vp-radio[aria-disabled="true"] .vp-radio__box {
  background: var(--vp-surface-chrome);
  border-color: var(--vp-ink-dim);
  box-shadow: none;
}
.vp-check[aria-disabled="true"] .vp-glyph { color: var(--vp-ink-dim); }
.vp-check[aria-disabled="true"] .vp-check__box::after,
.vp-radio[aria-disabled="true"] .vp-radio__box::after { background: var(--vp-ink-dim); }

.vp-checks > * + *      { margin-block-start: var(--vp-space-6); }   /* 6px min */
.vp-checks--row         { display: flex; gap: var(--vp-space-12); }  /* 12px min */
.vp-checks--row > * + * { margin-block-start: 0; }

/* ==========================================================================
   8.10  POP-UP MENU
   20px. Never a native <select> styled to look like one — a native popup
   renders in the OS's own chrome and breaks the illusion at the one moment
   the user is looking straight at it.
   ========================================================================== */
.vp-popup {
  display: inline-flex;
  align-items: center;
  gap: var(--vp-space-4);
  block-size: var(--vp-popup-height);
  padding-inline-start: var(--vp-button-text-inset);
  padding-inline-end: var(--vp-space-4);
  border: var(--vp-space-1) solid var(--vp-line);
  border-radius: var(--vp-radius-0);
  background: var(--vp-surface-chrome);
  box-shadow: var(--vp-bevel-2);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
  white-space: nowrap;
  user-select: none;
}
.vp-popup__value { flex: 1 1 auto; text-align: start; }
.vp-popup__arrow {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--vp-control-box);
  block-size: var(--vp-control-box);
}
.vp-popup:active,
.vp-popup[aria-expanded="true"] {
  background: var(--vp-surface-recessed);
  box-shadow: var(--vp-bevel-2-in);
}
.vp-popup:disabled,
.vp-popup[aria-disabled="true"] {
  background: var(--vp-surface-recessed);
  border-color: var(--vp-ink-dim);
  color: var(--vp-ink-dim);
  box-shadow: none;
  pointer-events: none;
}
.vp-popup[aria-disabled="true"] .vp-glyph { color: var(--vp-ink-dim); }
/* 4px between an edit field and its associated pop-up, and between
   interrelated pop-ups. The Toolbox never provided this and neither does the
   browser. */
.vp-popup + .vp-popup,
.vp-field + .vp-popup { margin-inline-start: var(--vp-space-4); }

/* ==========================================================================
   8.11  TABS
   Used once: the Sign In / Create Account pair.
   The front/back distinction is STRUCTURAL, not tonal — #DDDDDD against
   #CCCCCC measures 1.18:1 and would fail on its own. The front tab is 2px
   taller and has NO bottom border.
   ========================================================================== */
.vp-tabs {
  display: flex;
  align-items: flex-end;
  gap: 0;
}
.vp-tab {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  block-size: calc(var(--vp-tab-height) - var(--vp-space-2));
  min-inline-size: var(--vp-button-min-width);
  padding-inline: var(--vp-button-text-inset);
  border: var(--vp-space-1) solid var(--vp-line);
  border-start-start-radius: var(--vp-radius-button);
  border-start-end-radius: var(--vp-radius-button);
  background: var(--vp-surface-recessed);
  box-shadow: var(--vp-bevel-2);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
  white-space: nowrap;
}
.vp-tab[aria-selected="true"] {
  block-size: var(--vp-tab-height);        /* 2px proud */
  border-block-end: 0;                     /* open — it joins the pane */
  background: var(--vp-surface-chrome);
}
.vp-tab:active:not([aria-selected="true"]) { box-shadow: var(--vp-bevel-2-in); }
.vp-tab[aria-disabled="true"] { color: var(--vp-ink-dim); pointer-events: none; }

.vp-tabpane {
  border: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-surface-chrome);
  box-shadow: var(--vp-bevel-2);
  padding: var(--vp-space-12);
  margin-block-start: var(--vp-space-1-neg);   /* tucks under the front tab */
}

/* ==========================================================================
   8.12  SCROLL BAR
   16px. Arrows at opposite ends. Proportional thumb — fixed-size thumbs are
   Mac OS 8.0 and earlier, and getting this wrong is the common tell.

   THE FIVE STATES, and the two rules that are routinely conflated:
     1  active, content scrolls  everything
     2  active, CONTENT FITS     rectangles outlined only, no track fill, no
                                 thumb, arrows HOLLOW
     3  WINDOW INACTIVE          only the outline of the scroll bar as a whole,
                                 nothing inside it at all
     4  arrow pressed            that box inverted, face #CCCCCC
     5  track pressed            track darkens to #CCCCCC for the press

   Markup: each arrow holds both glyphs; the state shows the right one.
     .vp-scrollbar > .vp-scrollbar__arrow(x2) + .vp-scrollbar__track > __thumb
   ========================================================================== */
.vp-scrollbar {
  display: flex;
  flex: none;
  background: var(--vp-surface-chrome);
  border: var(--vp-space-1) solid var(--vp-line);
  user-select: none;
  touch-action: none;
}
.vp-scrollbar--v {
  flex-direction: column;
  inline-size: var(--vp-scrollbar);
  border-block-start: 0;
  border-inline-end: 0;
}
.vp-scrollbar--h {
  flex-direction: row;
  block-size: var(--vp-scrollbar);
  border-inline-start: 0;
  border-block-end: 0;
}

.vp-scrollbar__arrow {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--vp-scrollbar);
  block-size: var(--vp-scrollbar);
  background: var(--vp-surface-chrome);
  box-shadow: var(--vp-bevel-2);
}
.vp-scrollbar__arrow .vp-glyph--hollow { display: none; }
.vp-scrollbar__arrow:active {
  background: var(--vp-surface-recessed);
  box-shadow: var(--vp-bevel-2-in);
}

.vp-scrollbar__track {
  position: relative;
  flex: 1 1 auto;
  min-inline-size: 0;
  min-block-size: 0;
  background-color: var(--vp-surface-track);
  background-image: var(--vp-pattern-track);
  background-repeat: repeat;
  background-size: var(--vp-pattern-size) var(--vp-pattern-size);
  image-rendering: pixelated;
}
.vp-scrollbar__track:active { background-image: none; background-color: var(--vp-surface-recessed); }

/* The thumb is the accent. HIG thig-26: the indicator takes the accent colour.
   Proportional to content length, never below 16px. */
.vp-scrollbar__thumb {
  position: absolute;
  inset-inline: 0;
  min-block-size: var(--vp-scroll-thumb-min);
  border: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-accent);
  box-shadow: inset var(--vp-space-1) var(--vp-space-1) 0 0 var(--vp-accent-light),
              inset var(--vp-space-1-neg) var(--vp-space-1-neg) 0 0 var(--vp-accent-dark);
}
.vp-scrollbar--h .vp-scrollbar__thumb {
  inset-inline: auto;
  inset-block: 0;
  min-inline-size: var(--vp-scroll-thumb-min);
  min-block-size: 0;
}
/* Grip: three 1px rows #FFFFFF / #333399 / #FFFFFF, 6px wide, centred, drawn
   only when the thumb is at least 24px long. */
.vp-scrollbar__thumb--gripped::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  translate: -50% -50%;
  inline-size: var(--vp-space-6);
  block-size: var(--vp-space-1);
  background: var(--vp-accent-dark);
  box-shadow: 0 var(--vp-space-1-neg) 0 0 var(--vp-grey-0),
              0 var(--vp-space-1)     0 0 var(--vp-grey-0);
}

/* State 2 — content fits. Outlined rectangles only; the arrows go hollow. */
.vp-scrollbar--fits .vp-scrollbar__track {
  background-image: none;
  background-color: var(--vp-surface-chrome);
}
.vp-scrollbar--fits .vp-scrollbar__thumb { display: none; }
.vp-scrollbar--fits .vp-scrollbar__arrow {
  background: var(--vp-surface-chrome);
  box-shadow: none;
  border: var(--vp-space-1) solid var(--vp-line);
}
.vp-scrollbar--fits .vp-scrollbar__arrow .vp-glyph--solid  { display: none; }
.vp-scrollbar--fits .vp-scrollbar__arrow .vp-glyph--hollow { display: block; }

/* State 3 — the whole window is inactive. Only the outer outline survives.
   This is NOT state 2: nothing at all is drawn inside. */
.vp-window--inactive .vp-scrollbar { background: var(--vp-surface-chrome); }
.vp-window--inactive .vp-scrollbar > * { visibility: hidden; }

/* ==========================================================================
   8.13  DIALOG AND ALERT
   Non-movable alert: 1px black, a 2px black inner line (the HIG modal double
   outline), a 2px red placard border, then the face.
   NO BACKDROP SCRIM. Classic Mac modals did not dim what was behind them, and
   adding one reads as a modern web dialog. Modality is carried by the focus
   trap, the double frame, the red border and the flash on an outside click.
   ========================================================================== */
.vp-alert {
  position: fixed;
  z-index: var(--vp-z-modals);
  /* ONE width for every alert and every modal panel in the OS. 362 = a 352px
     content region + 10px of frame; the 352 is 12 + 32 + 16 + 280 + 12.
     Derivation in the design system, 8.13. Height is whatever fits. */
  inline-size: var(--vp-alert-width);
  /* The 12px dialog inset is measured INSIDE the 4px of frame the box-shadow
     below draws, so the interior column is 362 - 2 - 32 = 328: the 32px icon,
     the 16px group gap and the 280px text column. */
  padding: calc(var(--vp-space-12) + var(--vp-space-4));
  border: var(--vp-space-1) solid var(--vp-line);
  border-radius: var(--vp-radius-0);
  background: var(--vp-surface-chrome);
  /* outside -> in: the 1px border, a 2px black inner line, a 2px red placard
     border, then the face. First shadow listed paints on top. */
  box-shadow: inset 0 0 0 var(--vp-space-2) var(--vp-line),
              inset 0 0 0 var(--vp-space-4) var(--vp-alert-red),
              var(--vp-shadow-menu);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
}
.vp-alert__inner {
  display: flex;
  gap: var(--vp-space-16);                 /* the HIG group gap */
}
/* An alert or panel with no severity icon keeps the SAME outer width and gives
   its whole 328px interior to content. The width is a constant of the OS, not
   a function of what is in the dialog. */
.vp-alert__icon:empty { display: none; }
.vp-alert__icon { flex: none; }
.vp-alert__body { flex: 1 1 auto; min-inline-size: 0; }
.vp-alert__title { font-size: var(--vp-text-size); line-height: var(--vp-text-line); }
.vp-alert__text  { margin-block-start: var(--vp-space-6); }
.vp-alert__buttons {
  display: flex;
  justify-content: flex-end;
  gap: var(--vp-button-gap-h);
  margin-block-start: var(--vp-space-16);
  padding-inline-end: var(--vp-default-ring-reserve);   /* room for the ring */
}

/* Movable modal — sign-in and the account panels. A standard 19px title bar,
   draggable, NO CLOSE BOX because it is modal, and its pinstripe rows are red
   over white instead of #777777 over white.

   ITS FRAME IS NOT THE ALERT'S FRAME. The 1px black outer line wraps the WHOLE
   modal, title bar included. The 2px black inner line and the 2px red placard
   border wrap the CONTENT REGION ONLY, starting below the title bar's own 1px
   black rule (8.2 draws that rule). Wrapping the title bar in them instead
   would push four more pixels into a 19px band whose every row is spoken for.
   No bevel: a modal layout excludes the bevel (design system 6). */
.vp-modal {
  position: absolute;
  z-index: var(--vp-z-modals);
  inline-size: var(--vp-alert-width);      /* the same one modal width */
  border: var(--vp-space-1) solid var(--vp-line);
  border-radius: var(--vp-radius-0);
  background: var(--vp-surface-chrome);
  box-shadow: var(--vp-shadow-menu);
}
.vp-modal > .vp-window__titlebar {
  background-image: var(--vp-pattern-pinstripe-alert);
}
.vp-modal .vp-window__widget { display: none; }
/* The content region: 2px black, then 2px red, then the 12px dialog inset,
   leaving the same 328px column the alert has. */
.vp-modal__body {
  padding: calc(var(--vp-space-12) + var(--vp-space-4));
  background: var(--vp-surface-chrome);
  box-shadow: inset 0 0 0 var(--vp-space-2) var(--vp-line),
              inset 0 0 0 var(--vp-space-4) var(--vp-alert-red);
}

/* ==========================================================================
   8.14  DESKTOP ICON
   96x68. The unselected label needs NO PLATE because of the pattern floor
   rule: every pixel a desktop pattern may contain is #777777 or lighter, so
   black label ink measures at worst 4.69:1.
   ========================================================================== */
.vp-desktop-icon {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  inline-size: var(--vp-desktop-cell-w);
  min-block-size: var(--vp-desktop-cell-h);
  color: var(--vp-ink);
  user-select: none;
}
.vp-desktop-icon__art {
  position: relative;
  inline-size: var(--vp-icon-lg);
  block-size: var(--vp-icon-lg);
}
.vp-desktop-icon__label {
  margin-block-start: var(--vp-space-4);
  max-inline-size: var(--vp-desktop-cell-w);
  padding-inline: var(--vp-space-1);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
/* Selected: the ART ITSELF IS DRAWN DARKER, and the label takes a black plate
   with white ink.

   M-9. This was a 50% dither mask laid over the icon, and a checkerboard over
   32px of art is not a darkened icon — it is noise with the icon underneath.
   The round-2 critic could not read the Control Panels sliders through it.
   Platinum darkens the drawing; it does not stipple it.

   Method: re-point the four icon roles at lower steps of the SAME nine-step
   ramp, on the art's own subtree. No filter (section 13 forbids it), no second
   sprite, no new colour. Roles rather than ramp names because
   `--vp-grey-0: var(--vp-grey-8)` in a scope that also rebinds --vp-grey-8 is
   a custom-property cycle; the role layer is what makes the rebinding legal.

   Each step is the nearest of the nine to 50% toward black, and three of the
   four are exact:
     paper   #FFFFFF -> #777777   (50% is #808080; #777777 is one step under)
     face    #DDDDDD -> #666666   (50% is #6E6E6E)
     shade   #AAAAAA -> #555555   exact
     outline #000000 -> #000000   black is already black, and rule 3 says the
                                  outline is what carries the shape
   The interior ratios survive the move, which is the whole point: white-on-face
   was 1.36:1 unselected and is 1.28:1 selected, so detail that was legible
   stays legible. The lemon darkens one step to its own shade; no icon that can
   carry a selection uses the icon palette. */
.vp-desktop-icon[aria-selected="true"] .vp-desktop-icon__art,
.vp-icon-cell[aria-selected="true"]    .vp-icon-cell__art {
  --vp-icon-outline: var(--vp-ink);
  --vp-icon-paper:   var(--vp-grey-8);
  --vp-icon-face:    var(--vp-grey-9);
  --vp-icon-shade:   var(--vp-grey-10);
  --vp-icon-lemon:   var(--vp-icon-lemon-shade);
}

/* Folder icons are blue (client, 2026-09-04). The sprite's folder symbol paints
   with the paper/face/shade roles like every icon, so the colour is a scoped
   re-point of two roles on folder <svg>s only — no second sprite, no hand edit.
   The selected pair darkens the same way the grey icons darken. */
svg.vp-icon[data-icon="folder"] {
  --vp-icon-face:  var(--vp-icon-folder-face);
  --vp-icon-shade: var(--vp-icon-folder-shade);
}
.vp-desktop-icon[aria-selected="true"] svg.vp-icon[data-icon="folder"],
.vp-icon-cell[aria-selected="true"]    svg.vp-icon[data-icon="folder"] {
  --vp-icon-face:  var(--vp-icon-folder-face-selected);
  --vp-icon-shade: var(--vp-icon-folder-shade-selected);
}
/* The plate hugs the label, not the 96px cell — an inherited box width made
   the selection a band across the whole column. */
.vp-desktop-icon[aria-selected="true"] .vp-desktop-icon__label {
  inline-size: fit-content;
  margin-inline: auto;
  background: var(--vp-surface-selected);
  color: var(--vp-ink-inverse);
}
/* `building`: ghosted through the dither at 50%. NEVER by reducing opacity —
   the dither is what keeps the pixels hard, and the surviving outline pixels
   still measure 21:1. */
.vp-desktop-icon--building .vp-desktop-icon__art > * {
  mask-image: var(--vp-pattern-dither-mask);
  mask-size: var(--vp-pattern-size) var(--vp-pattern-size);
  mask-repeat: repeat;
  -webkit-mask-image: var(--vp-pattern-dither-mask);
  -webkit-mask-size: var(--vp-pattern-size) var(--vp-pattern-size);
  -webkit-mask-repeat: repeat;
}
/* Padlock badge, lower-right of the icon, in both views, signed in or out. */
.vp-badge-lock {
  position: absolute;
  inset-block-end: 0;
  inset-inline-end: 0;
  inline-size: var(--vp-icon-badge);
  block-size: var(--vp-icon-badge);
}

/* ==========================================================================
   8.15  DOCK TAB STRIP
   Modelled on Mac OS 8 pop-up windows. Not rendered at all when nothing is
   minimized, and reserving no vertical space.
   Never magnify, bounce, add gloss, or animate on hover: a screenshot at rest
   and mid-hover must be identical apart from the pressed state.
   ========================================================================== */
.vp-dock {
  position: fixed;
  inset: auto 0 0 0;
  z-index: var(--vp-z-palettes);
  display: flex;
  align-items: flex-end;
  gap: var(--vp-dock-tab-gap);
  padding-inline: var(--vp-space-8);
  padding-block-end: env(safe-area-inset-bottom);
  pointer-events: none;
}
.vp-dock > * { pointer-events: auto; }
.vp-dock:empty { display: none; }

.vp-dock-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--vp-space-4);
  block-size: var(--vp-dock-tab-height);
  max-inline-size: var(--vp-desktop-cell-w);
  padding-inline-start: var(--vp-space-4);
  padding-inline-end: var(--vp-space-8);
  border: var(--vp-space-1) solid var(--vp-line);
  border-block-end: 0;                     /* flush with the viewport */
  border-start-start-radius: var(--vp-radius-button);
  border-start-end-radius: var(--vp-radius-button);
  background: var(--vp-surface-chrome);    /* flat — the window is minimized */
  box-shadow: var(--vp-bevel-2);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
  white-space: nowrap;
}
.vp-dock-tab__label {
  min-inline-size: var(--vp-dock-tab-min-label);
  overflow: hidden;
  text-overflow: ellipsis;
}
.vp-dock-tab:active {
  background: var(--vp-surface-recessed);
  box-shadow: var(--vp-bevel-2-in);
}

/* ==========================================================================
   8.16  PROGRESS INDICATOR
   The barber pole is the ONLY loading indicator in this system. There are no
   spinners and no skeletons.
   ========================================================================== */
.vp-progress {
  position: relative;
  block-size: var(--vp-progress-height);
  border: var(--vp-space-1) solid var(--vp-line);
  background-color: var(--vp-surface-track);
  background-image: var(--vp-pattern-track);
  background-size: var(--vp-pattern-size) var(--vp-pattern-size);
  box-shadow: var(--vp-bevel-1-in);
  image-rendering: pixelated;
  overflow: hidden;
}
.vp-progress__fill {
  block-size: 100%;
  background: var(--vp-accent);
  box-shadow: inset var(--vp-space-1) var(--vp-space-1) 0 0 var(--vp-accent-light),
              inset var(--vp-space-1-neg) var(--vp-space-1-neg) 0 0 var(--vp-accent-dark);
}
.vp-progress--indeterminate .vp-progress__fill {
  inline-size: 100%;
  background-color: var(--vp-accent);
  background-image: var(--vp-pattern-barberpole);
  background-repeat: repeat;
  background-size: var(--vp-pattern-size) var(--vp-pattern-size);
  box-shadow: none;
  animation: vp-barberpole var(--vp-dur-barberpole) var(--vp-ease) infinite;
}
@keyframes vp-barberpole {
  from { background-position: 0 0; }
  to   { background-position: var(--vp-pattern-size) 0; }
}

/* The About window's memory bar is a different object: one segment per
   application, sized by MEASURED transferred bytes. No fabricated figure. */
.vp-memorybar {
  display: flex;
  block-size: var(--vp-progress-height);
  border: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-surface-track);
}
.vp-memorybar__seg {
  background: var(--vp-accent);
  border-inline-end: var(--vp-space-1) solid var(--vp-line);
}
.vp-memorybar__seg:last-child { border-inline-end: 0; }

/* ==========================================================================
   8.17  DISCLOSURE TRIANGLE
   9x9 solid black. Collapsed points right, expanded points down, pressed
   fills #555555. Operated by click and by Return or Space when focused.
   ========================================================================== */
.vp-disclosure {
  display: inline-flex;
  align-items: center;
  gap: var(--vp-disclosure-gap);           /* 5px to its text */
  color: var(--vp-ink);
  user-select: none;
}
.vp-disclosure .vp-glyph--expanded { display: none; }
.vp-disclosure[aria-expanded="true"] .vp-glyph--collapsed { display: none; }
.vp-disclosure[aria-expanded="true"] .vp-glyph--expanded  { display: block; }
.vp-disclosure:active .vp-glyph { color: var(--vp-ink-dim); }

/* ==========================================================================
   8.18  LIST VIEW, COLUMN HEADER, SORT INDICATOR, STATUS PLACARD
   The word is the differentiator. There is no colour coding: `live`, `beta`
   and `building` are distinguished by the text a Platinum placard contains.
   ========================================================================== */
.vp-list {
  background: var(--vp-surface-content);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
  user-select: none;
}
.vp-list__row {
  display: flex;
  align-items: center;
  gap: var(--vp-space-4);
  block-size: var(--vp-menu-item-height);
  padding-inline: var(--vp-space-4);
}
.vp-list__row[aria-selected="true"] {
  background: var(--vp-surface-selected);
  color: var(--vp-ink-inverse);
}
.vp-list__row--building { color: var(--vp-ink-dim); }
.vp-list__row--building .vp-icon {
  mask-image: var(--vp-pattern-dither-mask);
  mask-size: var(--vp-pattern-size) var(--vp-pattern-size);
  mask-repeat: repeat;
  -webkit-mask-image: var(--vp-pattern-dither-mask);
  -webkit-mask-size: var(--vp-pattern-size) var(--vp-pattern-size);
  -webkit-mask-repeat: repeat;
}

.vp-list__header {
  display: flex;
  align-items: center;
  block-size: var(--vp-menu-item-height);
  background: var(--vp-surface-chrome);
  border-block-end: var(--vp-space-1) solid var(--vp-line);
  box-shadow: var(--vp-bevel-1);
}
.vp-list__col {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--vp-space-4);
  block-size: 100%;
  padding-inline: var(--vp-button-text-inset);
  color: var(--vp-ink);
  white-space: nowrap;
}
.vp-list__col:active { background: var(--vp-surface-recessed); box-shadow: var(--vp-bevel-1-in); }
/* Sort indicator: present or absent, pointing down for ascending and up for
   descending. Never a colour change. */
.vp-list__col .vp-glyph { visibility: hidden; }
.vp-list__col[aria-sort] .vp-glyph { visibility: visible; }
.vp-list__col[aria-sort="ascending"]  .vp-glyph--desc { display: none; }
.vp-list__col[aria-sort="descending"] .vp-glyph--asc  { display: none; }

.vp-placard {
  display: inline-flex;
  align-items: center;
  block-size: var(--vp-static-text-height);
  padding-inline: var(--vp-space-4);
  border: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-surface-chrome);
  box-shadow: var(--vp-bevel-1);
  color: var(--vp-ink);
  white-space: nowrap;
}
.vp-placard--pressed { background: var(--vp-surface-recessed); box-shadow: var(--vp-bevel-1-in); }

.vp-statusline {
  display: flex;
  align-items: center;
  flex: none;
  block-size: var(--vp-static-text-height);
  padding-inline: var(--vp-button-text-inset);
  border-block-start: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-surface-chrome);
  color: var(--vp-ink);
}

/* ==========================================================================
   8.21  SHEET, AND THE SHEET TITLE BAR
   The switch is layout mode, not touch. Structure only; the rules that turn it
   on live at the bottom of this file.
   ========================================================================== */
.vp-sheet {
  position: fixed;
  inset: var(--vp-menubar-height) 0 0 0;
  z-index: var(--vp-z-windows);
  display: flex;
  flex-direction: column;
  block-size: auto;
  background: var(--vp-surface-content);
  padding-block-end: env(safe-area-inset-bottom);
  padding-inline-start: env(safe-area-inset-left);
  padding-inline-end: env(safe-area-inset-right);
}
.vp-sheet__titlebar {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  block-size: var(--vp-touch-titlebar-height);
  border-block-end: var(--vp-space-1) solid var(--vp-line);
  box-shadow: inset 0 var(--vp-space-1-neg) 0 0 var(--vp-bevel-lo-outer);
  background-color: var(--vp-surface-chrome);
  background-image: var(--vp-pattern-pinstripe);   /* the period stays 2px */
  background-repeat: repeat;
  background-size: var(--vp-pinstripe-period) var(--vp-pinstripe-period);
  background-clip: padding-box;
  image-rendering: pixelated;
  /* Clips the break plate below, exactly as .vp-window__titlebar clips the
     widgets'. The clip is the PADDING box, so the bar's 1px black rule is
     outside it and nothing a child paints can cover the rule. */
  overflow: hidden;
}
.vp-sheet__titlebar .vp-window__title { background: var(--vp-surface-chrome); }

/* B-7. Done is the only way out of a sheet, so it is a control, not a caption.
   It takes the title-bar control construction — 1px black outline, Bevel(2),
   Platinum face, square corners like the three window widgets — and it breaks
   the pinstripes the way detail 2 says every title-bar element does: a solid
   plate of chrome, here --vp-space-8 rather than the widgets' 6, because this
   one is 88px wide and a 6px break reads as a rim rather than a clear zone.
   Radius 0, not --vp-radius-button: this is a title-bar control and the ring
   below is a box-shadow spread, which a 3px radius would round into 3px of
   pinstripe at each end of the plate. */
.vp-sheet__done {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: var(--vp-space-8);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  block-size: var(--vp-touch-button-height);
  min-inline-size: var(--vp-touch-button-min-width);
  padding-inline: var(--vp-space-16);
  border: var(--vp-space-1) solid var(--vp-line);
  border-radius: var(--vp-radius-0);
  background: var(--vp-surface-chrome);
  box-shadow: var(--vp-bevel-2), 0 0 0 var(--vp-space-8) var(--vp-surface-chrome);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
  white-space: nowrap;
  user-select: none;
}
.vp-sheet__done:active {
  background: var(--vp-surface-pressed);
  box-shadow: var(--vp-bevel-2-in), 0 0 0 var(--vp-space-8) var(--vp-surface-chrome);
  color: var(--vp-ink-inverse);
}
/* The bar clips its children, so this one control's ring is drawn INSIDE it:
   same two tones, same 1px each, same order outward-in (white then black). */
.vp-sheet__done:focus-visible         { outline-offset: calc(var(--vp-space-3) * -1); }
.vp-sheet__done:focus-visible::after  { inset: var(--vp-space-2); }
.vp-sheet__content { flex: 1 1 auto; min-block-size: 0; overflow: auto; }

.vp-menu-sheet {
  position: fixed;
  inset: var(--vp-menubar-height) 0 auto 0;
  z-index: var(--vp-z-menus);
  border-block-end: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-surface-chrome);
  box-shadow: none;                        /* a sheet is not a floating panel */
}
.vp-menu-sheet .vp-menu__item     { block-size: var(--vp-touch-menu-item-height); }
.vp-menu-sheet .vp-menu__divider  { block-size: var(--vp-button-text-inset); }

/* Overflow: menu titles that do not fit collapse, in order, into a single
   three-bar mark in a 12x12 box. */
.vp-menubar__overflow {
  display: none;
  align-items: center;
  padding-inline: var(--vp-menu-title-inset);
}
.vp-menubar--overflowing .vp-menubar__overflow { display: flex; }

/* ==========================================================================
   8.22  KEYPAD BUTTON  (Calculator, Puzzle)
   ========================================================================== */
.vp-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  block-size: var(--vp-button-height);
  min-inline-size: var(--vp-text-size-2x);
  padding-inline: var(--vp-space-4);
  border: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-surface-chrome);
  box-shadow: var(--vp-bevel-2);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
}
.vp-key:active,
.vp-key--down {
  background: var(--vp-surface-pressed);
  box-shadow: var(--vp-bevel-2-in);
  color: var(--vp-ink-inverse);
}
/* The track sizes live here, not as an inline style on the element, because
   the (hover: none) block below has to be able to change them: on touch a
   .vp-key becomes 44x44, and 44px keys in 32px columns overflowed their
   tracks and overlapped each other — the keypad rendered as a jumble with
   clipped labels. An inline style is not something a media query can reach. */
.vp-keypad {
  display: grid;
  gap: var(--vp-space-4);
  grid-template-columns: repeat(4, var(--vp-key-size, 32px));
  grid-template-rows: repeat(5, var(--vp-key-row, var(--vp-button-height)));
  justify-content: center;
}

.vp-display {
  block-size: var(--vp-text-line-2x);
  padding-inline: var(--vp-space-4);
  border: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-surface-content);
  box-shadow: var(--vp-bevel-1-in);
  font-size: var(--vp-text-size-2x);
  line-height: var(--vp-text-line-2x);
  color: var(--vp-ink);
  text-align: end;
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  white-space: nowrap;
}

.vp-tile {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--vp-icon-lg);
  block-size: var(--vp-icon-lg);
  border: var(--vp-space-1) solid var(--vp-line);
  background: var(--vp-surface-chrome);
  box-shadow: var(--vp-bevel-2);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
  transition: translate var(--vp-dur-minimize) var(--vp-ease);
}
.vp-tile--gap {
  background: var(--vp-surface-recessed);
  box-shadow: var(--vp-bevel-2-in);
  border-color: var(--vp-line);
}

/* ==========================================================================
   8.23  BOOT SCREEN
   The string "Macintosh" appears nowhere — not in the DOM, not in an asset
   filename, not in a CSS content property, not in the title. There is no
   Apple mark of any kind.
   ========================================================================== */
.vp-boot {
  position: fixed;
  inset: 0;
  z-index: var(--vp-z-menubar);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--vp-space-16);
  background: var(--vp-surface-chrome);
  color: var(--vp-ink);
}
.vp-boot__wordmark {
  font-size: var(--vp-text-size-2x);
  line-height: var(--vp-text-line-2x);
}
.vp-boot--leaving { animation: vp-boot-out var(--vp-dur-boot-short) var(--vp-ease) forwards; }
@keyframes vp-boot-out { to { opacity: 0; visibility: hidden; } }

/* ==========================================================================
   8.24  GROUP BOX
   2px etched — 1px #FFFFFF next to 1px dark grey. The one place the HIG
   states bevel construction outright. Measure from INSIDE those two lines.
   It is a rule, not a panel: never give it a different background fill.
   ========================================================================== */
.vp-group {
  padding-block-start: var(--vp-groupbox-inset-top);
  padding-block-end: var(--vp-groupbox-inset-bot);
  padding-inline: var(--vp-groupbox-inset-side);
  border: var(--vp-space-1) solid var(--vp-line-etch-dark);
  box-shadow: inset var(--vp-space-1) var(--vp-space-1) 0 0 var(--vp-line-etch-light),
              inset var(--vp-space-1-neg) var(--vp-space-1-neg) 0 0 var(--vp-line-etch-light);
  color: var(--vp-ink);
}
.vp-group--secondary { box-shadow: none; }
.vp-group > legend,
.vp-group__title {
  padding-inline: var(--vp-space-3);
  background: var(--vp-surface-chrome);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  text-shadow: var(--vp-text-bold-offset) 0 0 currentColor;   /* emphasised */
}
.vp-group + .vp-group          { margin-block-start: var(--vp-groupbox-inset-top); }
.vp-group .vp-group            { margin: var(--vp-groupbox-inset-side); }
.vp-group-row                  { display: flex; gap: var(--vp-groupbox-inset-side); }

/* ==========================================================================
   8.25  NOTE PAD PAGE AND DOG-EAR
   Click the dog-ear to turn forward; shift-click it, or click the smaller
   top-left fold, to turn back. Page 8 forward wraps to page 1.
   ========================================================================== */
.vp-page {
  position: relative;
  padding: var(--vp-doc-text-inset);       /* 8 all round, optically (8.25) */
  background: var(--vp-surface-content);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
}
.vp-page__number {
  text-align: center;
  color: var(--vp-ink-dim);
}
.vp-dogear,
.vp-backfold {
  position: absolute;
  inset-inline-start: 0;
  inline-size: var(--vp-icon-sm);
  block-size: var(--vp-icon-sm);
}
.vp-dogear   { inset-block-end: 0; }
.vp-backfold {
  inset-block-start: 0;
  inline-size: var(--vp-groupbox-inset-side);
  block-size: var(--vp-groupbox-inset-side);
}
/* M-8. The fold is two triangles meeting along the crease: the uncovered
   corner in --vp-icon-shade (drawn into the art, because it is never anything
   else) and the lifted flap in currentColor, so the pressed state can take the
   flap to #CCCCCC the way 8.25 asks without a second drawing. At rest the flap
   is the Platinum face — the page's own under-side. */
.vp-dogear   .vp-glyph,
.vp-backfold .vp-glyph        { color: var(--vp-surface-chrome); }
.vp-dogear:active   .vp-glyph,
.vp-backfold:active .vp-glyph { color: var(--vp-surface-recessed); }

/* ==========================================================================
   8.26  FINDER ICON VIEW CELL
   The desktop icon reused inside a Finder window, with two differences: the
   ground is white, and the icon size follows Control Panels -> Views. The
   16px icon is the redrawn small version, never a scaled 32.
   ========================================================================== */
.vp-icon-cell {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  inline-size: var(--vp-desktop-cell-w);
  min-block-size: var(--vp-desktop-cell-h);
  background: var(--vp-transparent);
  color: var(--vp-ink);
  user-select: none;
}
.vp-icon-cell__art {
  position: relative;
  inline-size: var(--vp-icon-lg);
  block-size: var(--vp-icon-lg);
}
.vp-icon-cell--small,
.vp-icon-cell--small .vp-icon-cell__art { min-block-size: 0; }
.vp-icon-cell--small .vp-icon-cell__art {
  inline-size: var(--vp-icon-sm);
  block-size: var(--vp-icon-sm);
}
.vp-icon-cell__label {
  margin-block-start: var(--vp-space-4);
  max-inline-size: var(--vp-desktop-cell-w);
  padding-inline: var(--vp-space-1);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.vp-icon-cell--small .vp-icon-cell__label { -webkit-line-clamp: 1; }
/* Selection darkens the art (8.14, and the note on it above), never dithers
   over it. The role remap lives with the desktop icon so the two states cannot
   drift apart. */
.vp-icon-cell[aria-selected="true"] .vp-icon-cell__label {
  inline-size: fit-content;
  margin-inline: auto;
  background: var(--vp-surface-selected);
  color: var(--vp-ink-inverse);
}
.vp-icon-cell--building .vp-icon-cell__art > * {
  mask-image: var(--vp-pattern-dither-mask);
  mask-size: var(--vp-pattern-size) var(--vp-pattern-size);
  mask-repeat: repeat;
  -webkit-mask-image: var(--vp-pattern-dither-mask);
  -webkit-mask-size: var(--vp-pattern-size) var(--vp-pattern-size);
  -webkit-mask-repeat: repeat;
}

/* ==========================================================================
   RUNNING TEXT
   Read Me, the legal windows and Get Info comments wrap at 480px — about 66
   characters at Chicago's average advance.
   ========================================================================== */

/* The document content region. White, with the Note Pad page's inset (8.25):
   8px on all four sides, less the Chicago left side bearing on the left so the
   OPTICAL inset is 8px rather than 10px. Read Me, both legal windows and Get
   Info's comments box are the Note Pad page with different contents, so they
   take its inset rather than each composing one. */
.vp-doc {
  padding: var(--vp-doc-text-inset);
  background: var(--vp-surface-content);
  color: var(--vp-ink);
}

.vp-prose {
  max-inline-size: var(--vp-measure-max);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink);
}
.vp-prose > * + *   { margin-block-start: var(--vp-text-line); }
.vp-prose a         { color: var(--vp-ink); text-decoration: underline; }
.vp-prose--secondary{ color: var(--vp-ink-dim); }

/* ==========================================================================
   HIT AREA
   .vp-hit is an empty span a control may contain. At rest it is exactly the
   control. Wherever (hover: none) matches it becomes a 44x44 box centred on
   the control — WITHOUT changing what is drawn.
   The governing rule: the visual size of a Platinum control never scales.
   Only its hit area and the row containing it.
   ========================================================================== */
.vp-hit { position: absolute; inset: 0; }

/* ==========================================================================
   TOUCH — wherever (hover: none) matches, at ANY width.
   This is NOT the layout switch. A touch laptop at 1440px gets windows AND
   big targets; a mouse on a 900px window gets sheets and small targets.
   ========================================================================== */
@media (hover: none) {
  .vp-hit {
    inline-size: var(--vp-touch-target);
    block-size:  var(--vp-touch-target);
    inset: 50% auto auto 50%;
    translate: -50% -50%;
  }

  /* R-01. The bar's 20px height does not move — SPEC SH9. The title gets a
     44px minimum width and a 12px invisible downward extension, for a 32px
     effective target. */
  .vp-menubar__title,
  .vp-menubar__app {
    min-inline-size: var(--vp-menu-title-min-w);
    justify-content: center;
  }
  .vp-menubar__title .vp-hit {
    inset: 0 0 auto 0;
    inline-size: auto;
    block-size: calc(var(--vp-menubar-height) + var(--vp-menu-title-hit-ext));
    translate: none;
  }

  /* R-02. Three 44px title-bar hit areas plus a title need 320px. */
  .vp-window { min-inline-size: var(--vp-touch-window-min-w); }
  .vp-window__titlebar { block-size: var(--vp-touch-titlebar-height); }

  .vp-button, .vp-sheet__done {
    block-size: var(--vp-touch-button-height);
    min-inline-size: var(--vp-touch-button-min-width);
    padding-inline: var(--vp-space-16);
  }
  .vp-field, .vp-field--aligned, .vp-popup {
    block-size: var(--vp-touch-field-height);
    font-size: var(--vp-touch-text-size);      /* 24px: an integer 2x, and >= 16
                                                  so iOS does not zoom on focus */
    line-height: var(--vp-touch-text-line);
  }
  .vp-field--multiline { block-size: auto; }
  .vp-display { font-size: var(--vp-touch-text-size); }

  /* The 12px box is unchanged. Only the row grows. */
  .vp-check, .vp-radio, .vp-list__row, .vp-menu__item, .vp-tab {
    block-size: var(--vp-touch-row-height);
  }
  .vp-key, .vp-tile {
    min-inline-size: var(--vp-touch-target);
    block-size: var(--vp-touch-target);
  }
  /* ...and the tracks they sit in grow to match, or they overlap. */
  .vp-keypad {
    --vp-key-size: var(--vp-touch-target);
    --vp-key-row:  var(--vp-touch-target);
  }

  /* R-03. The scroll bar stays 16px with a 16px hit area. On touch it is a
     position INDICATOR; scrolling happens by direct content drag. A 28px
     invisible extension would sit over the content and steal taps from it. */
  .vp-scrollbar--v { inline-size: var(--vp-scrollbar-hit); }
  .vp-scrollbar--h { block-size:  var(--vp-scrollbar-hit); }

  /* Drawn at their own size, hit at 44. A .vp-hit centres itself on its
     nearest positioned ancestor, so a control laid out statically needs one
     here. R15: .vp-dogear and .vp-backfold do NOT — 8.25 already gives them
     `position: absolute` against the page wrapper, so they are containing
     blocks as they stand. Adding `position: relative` took that away and
     dropped both into the wrapper's flex row, side by side at its
     cross-start; their two 44x44 hit boxes then overlapped by 31x41px and a
     tap on the dog-ear's own glyph landed on the back-fold, turning the page
     BACKWARD. They keep note-pad.md 2's corners under touch exactly as they
     have them under a pointer: dog-ear lower-left, back-fold upper-left,
     the whole page between the two hit boxes. */
  .vp-disclosure, .vp-window__widget { position: relative; }

  /* Window drag is a 400ms long press, then a drag — SPEC MO4. */
  .vp-window__titlebar { touch-action: none; }
}

/* Hover styles are gated on (hover: hover) and never on width — SPEC MO4.
   There is no hover-only affordance anywhere in this system; these are
   reinforcement of something already visible at rest. */
@media (hover: hover) {
  .vp-menu__item:not([aria-disabled="true"]):hover {
    background: var(--vp-surface-selected);
    color: var(--vp-ink-inverse);
  }
  .vp-list__row:not([aria-selected="true"]):hover { background: var(--vp-surface-track); }
}

/* ==========================================================================
   SHEET MODE — the layout switch.
   1024px is the ONE literal in this file outside :root. A media prelude cannot
   read a custom property; the value is declared as --vp-sheet-breakpoint and
   appears nowhere else. env.js's layoutMode() is defined as the same
   comparison, so the two cannot disagree.
   Below it, the frame, the widgets, the grow box, the dock and the rubber band
   are ABSENT FROM THE DOM, not present and disabled (SPEC MO1) — these rules
   are the belt to app-frontend's braces.
   ========================================================================== */
@media (width < 1024px) {
  .vp-window {
    position: fixed;
    inset: var(--vp-menubar-height) 0 0 0;
    min-inline-size: 0;
    padding: 0;
    border: 0;
    box-shadow: none;
    background: var(--vp-surface-content);
  }
  .vp-window__titlebar { block-size: var(--vp-touch-titlebar-height); }
  .vp-window__widget,
  .vp-growbox,
  .vp-dock,
  .vp-rubberband,
  .vp-scrollbar { display: none; }          /* sheets scroll natively */

  .vp-window__content { overflow: auto; -webkit-overflow-scrolling: touch; }

  .vp-menu {
    inset-inline: 0;
    inset-block-start: var(--vp-menubar-height);
    border-inline: 0;
    box-shadow: none;
  }
  .vp-menu__item    { block-size: var(--vp-touch-menu-item-height); }
  .vp-menu__divider { block-size: var(--vp-button-text-inset); }

  .vp-modal, .vp-alert {
    position: fixed;
    inset: var(--vp-menubar-height) 0 0 0;
    inline-size: auto;            /* --vp-alert-width would over-constrain */
    border: 0;
    box-shadow: none;
  }
  .vp-desktop-icon { inline-size: var(--vp-touch-icon-cell); }
}

/* ==========================================================================
   REDUCED MOTION
   Every duration collapses in the token block. What remains here is the two
   things the spec keeps working rather than shortens: the barber pole stops
   moving and its state is carried by the status line text ("Reading..."), and
   the screen flash is replaced by the outline pulse.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .vp-progress--indeterminate .vp-progress__fill { animation: none; }
  .vp-tile { transition: none; }
  .vp-menu__item--flash { animation: none; }
  .vp-screen-flash { display: none; }
}

/* Control Panels -> Motion overrides the media query (SPEC SH9). */
[data-vp-motion="never"] *,
[data-vp-motion="never"] *::before,
[data-vp-motion="never"] *::after {
  animation-duration: var(--vp-dur-0) !important;
  animation-iteration-count: 1 !important;
  transition-duration: var(--vp-dur-0) !important;
}

/* ---- .vp-visually-hidden -------------------------------------------------
   Added by the orchestrator (docs/requests/app-frontend.md APPS-11). Referenced
   by ui/controls.js for the native <input> behind every Platinum checkbox and
   radio; it was never defined, so the native control painted over the glyph.
   The standard pattern: keeps the input focusable and announced, removes it
   from layout and paint. Not a token-bearing rule — no colour, size or motion.
   The 1px box and its -1px margin are the pattern's own construction, not a
   design value, but they are still written as tokens so the file's one rule
   holds without an exception. */
.vp-visually-hidden {
  position: absolute !important;
  inline-size: var(--vp-space-1); block-size: var(--vp-space-1);
  padding: 0; margin: var(--vp-space-1-neg); border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap;
}

/* App accents (client, 2026-09-04): apps are the only saturated colour. Every
   icon role is tinted — several app shapes draw with outline and paper only, so
   a face-only accent was invisible (QA 2026-09-04). The accent is the face, paper
   is a light tint, the outline IS the accent (several app shapes are outline-only line art — a dark mix read as near-black), and shade is a dark mix on desktop and Finder cells (selected icons
   still darken to grey like every other icon), and the active window's title-bar
   pinstripe tile — the same mechanism as the movable modal's red stripes. */
.vp-desktop-icon:not([aria-selected="true"]) [data-accent="green"] svg.vp-icon,
.vp-icon-cell:not([aria-selected="true"]) [data-accent="green"] svg.vp-icon { --vp-icon-face: var(--vp-accent-app-green); --vp-icon-paper: color-mix(in srgb, var(--vp-accent-app-green) 22%, white); --vp-icon-outline: var(--vp-accent-app-green); --vp-icon-shade: color-mix(in srgb, var(--vp-accent-app-green) 70%, black); }
.vp-window--active[data-accent="green"] { --vp-pattern-pinstripe: var(--vp-pattern-pinstripe-green); }
.vp-desktop-icon:not([aria-selected="true"]) [data-accent="purple"] svg.vp-icon,
.vp-icon-cell:not([aria-selected="true"]) [data-accent="purple"] svg.vp-icon { --vp-icon-face: var(--vp-accent-app-purple); --vp-icon-paper: color-mix(in srgb, var(--vp-accent-app-purple) 22%, white); --vp-icon-outline: var(--vp-accent-app-purple); --vp-icon-shade: color-mix(in srgb, var(--vp-accent-app-purple) 70%, black); }
.vp-window--active[data-accent="purple"] { --vp-pattern-pinstripe: var(--vp-pattern-pinstripe-purple); }
.vp-desktop-icon:not([aria-selected="true"]) [data-accent="blue"] svg.vp-icon,
.vp-icon-cell:not([aria-selected="true"]) [data-accent="blue"] svg.vp-icon { --vp-icon-face: var(--vp-accent-app-blue); --vp-icon-paper: color-mix(in srgb, var(--vp-accent-app-blue) 22%, white); --vp-icon-outline: var(--vp-accent-app-blue); --vp-icon-shade: color-mix(in srgb, var(--vp-accent-app-blue) 70%, black); }
.vp-window--active[data-accent="blue"] { --vp-pattern-pinstripe: var(--vp-pattern-pinstripe-blue); }
.vp-desktop-icon:not([aria-selected="true"]) [data-accent="red"] svg.vp-icon,
.vp-icon-cell:not([aria-selected="true"]) [data-accent="red"] svg.vp-icon { --vp-icon-face: var(--vp-accent-app-red); --vp-icon-paper: color-mix(in srgb, var(--vp-accent-app-red) 22%, white); --vp-icon-outline: var(--vp-accent-app-red); --vp-icon-shade: color-mix(in srgb, var(--vp-accent-app-red) 70%, black); }
.vp-window--active[data-accent="red"] { --vp-pattern-pinstripe: var(--vp-pattern-pinstripe-red); }
.vp-desktop-icon:not([aria-selected="true"]) [data-accent="amber"] svg.vp-icon,
.vp-icon-cell:not([aria-selected="true"]) [data-accent="amber"] svg.vp-icon { --vp-icon-face: var(--vp-accent-app-amber); --vp-icon-paper: color-mix(in srgb, var(--vp-accent-app-amber) 22%, white); --vp-icon-outline: var(--vp-accent-app-amber); --vp-icon-shade: color-mix(in srgb, var(--vp-accent-app-amber) 70%, black); }
.vp-window--active[data-accent="amber"] { --vp-pattern-pinstripe: var(--vp-pattern-pinstripe-amber); }
.vp-desktop-icon:not([aria-selected="true"]) [data-accent="lime"] svg.vp-icon,
.vp-icon-cell:not([aria-selected="true"]) [data-accent="lime"] svg.vp-icon { --vp-icon-face: var(--vp-accent-app-lime); --vp-icon-paper: color-mix(in srgb, var(--vp-accent-app-lime) 22%, white); --vp-icon-outline: var(--vp-accent-app-lime); --vp-icon-shade: color-mix(in srgb, var(--vp-accent-app-lime) 70%, black); }
.vp-window--active[data-accent="lime"] { --vp-pattern-pinstripe: var(--vp-pattern-pinstripe-lime); }
.vp-desktop-icon:not([aria-selected="true"]) [data-accent="magenta"] svg.vp-icon,
.vp-icon-cell:not([aria-selected="true"]) [data-accent="magenta"] svg.vp-icon { --vp-icon-face: var(--vp-accent-app-magenta); --vp-icon-paper: color-mix(in srgb, var(--vp-accent-app-magenta) 22%, white); --vp-icon-outline: var(--vp-accent-app-magenta); --vp-icon-shade: color-mix(in srgb, var(--vp-accent-app-magenta) 70%, black); }
.vp-window--active[data-accent="magenta"] { --vp-pattern-pinstripe: var(--vp-pattern-pinstripe-magenta); }
.vp-desktop-icon:not([aria-selected="true"]) [data-accent="teal"] svg.vp-icon,
.vp-icon-cell:not([aria-selected="true"]) [data-accent="teal"] svg.vp-icon { --vp-icon-face: var(--vp-accent-app-teal); --vp-icon-paper: color-mix(in srgb, var(--vp-accent-app-teal) 22%, white); --vp-icon-outline: var(--vp-accent-app-teal); --vp-icon-shade: color-mix(in srgb, var(--vp-accent-app-teal) 70%, black); }
.vp-window--active[data-accent="teal"] { --vp-pattern-pinstripe: var(--vp-pattern-pinstripe-teal); }
.vp-desktop-icon:not([aria-selected="true"]) [data-accent="sky"] svg.vp-icon,
.vp-icon-cell:not([aria-selected="true"]) [data-accent="sky"] svg.vp-icon { --vp-icon-face: var(--vp-accent-app-sky); --vp-icon-paper: color-mix(in srgb, var(--vp-accent-app-sky) 22%, white); --vp-icon-outline: var(--vp-accent-app-sky); --vp-icon-shade: color-mix(in srgb, var(--vp-accent-app-sky) 70%, black); }
.vp-window--active[data-accent="sky"] { --vp-pattern-pinstripe: var(--vp-pattern-pinstripe-sky); }

/* Boot progress bar under "Welcome" (client, 2026-09-04): the §8 progress
   primitive, sized to the wordmark, filled over the boot's own duration by
   ui/boot-screen.js; instant under reduced motion. */
.vp-boot__progress { inline-size: 200px; margin-block-start: var(--vp-space-16); }
.vp-boot__progress .vp-progress__fill { inline-size: 0; transition: inline-size var(--vp-boot-progress-ms, 0ms) linear; }

/* Boot art (client, 2026-09-04): a raster illustration replaces the lemon-computer
   symbol on the startup screen. Drawn at its own integer size, never smoothed. */
.vp-boot__icon--art { inline-size: auto; block-size: auto; image-rendering: pixelated; }

/* In-development badge (client, 2026-09-04): under an app's name in the Finder,
   so an unfinished app is unmistakable. Existing tokens only — the system has
   one type size, so the badge reads at 12px on a dim plate. */
.vp-badge-indev {
  display: block;
  align-self: center;
  margin-block-start: var(--vp-space-2);
  padding: 0 var(--vp-space-4);
  font-size: var(--vp-text-size);
  line-height: var(--vp-text-line);
  color: var(--vp-ink-inverse);
  background: var(--vp-ink-dim);
  border-radius: var(--vp-radius-button);
}
