vintage-frames 0.13.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +16 -0
  2. package/custom-elements.json +184 -20
  3. package/dist/components/vf-checkbox.d.ts +6 -5
  4. package/dist/components/vf-checkbox.js +41 -37
  5. package/dist/components/vf-container.d.ts +14 -14
  6. package/dist/components/vf-container.js +58 -28
  7. package/dist/components/vf-desktop.d.ts +114 -12
  8. package/dist/components/vf-desktop.js +119 -58
  9. package/dist/components/vf-fieldset.js +30 -22
  10. package/dist/components/vf-icon-field.d.ts +1 -1
  11. package/dist/components/vf-icon.js +111 -104
  12. package/dist/components/vf-list.js +30 -29
  13. package/dist/components/vf-menu-bar.d.ts +5 -0
  14. package/dist/components/vf-menu-bar.js +67 -43
  15. package/dist/components/vf-menu.js +24 -22
  16. package/dist/components/vf-number-field.js +32 -30
  17. package/dist/components/vf-progress-bar.js +28 -29
  18. package/dist/components/vf-radio.js +3 -4
  19. package/dist/components/vf-scroll-area.js +27 -26
  20. package/dist/components/vf-select.js +108 -90
  21. package/dist/components/vf-separator.d.ts +5 -5
  22. package/dist/components/vf-separator.js +36 -10
  23. package/dist/components/vf-swatch.js +47 -45
  24. package/dist/components/vf-text-area.js +37 -35
  25. package/dist/components/vf-text-field.js +20 -18
  26. package/dist/components/vf-window.d.ts +13 -0
  27. package/dist/components/vf-window.js +101 -72
  28. package/dist/index.d.ts +12 -1
  29. package/dist/index.js +61 -59
  30. package/dist/pattern-fill.d.ts +11 -8
  31. package/dist/pattern-fill.js +2 -4
  32. package/dist/position.d.ts +25 -7
  33. package/dist/position.js +6 -3
  34. package/dist/shell/alert.d.ts +32 -0
  35. package/dist/shell/alert.js +44 -0
  36. package/dist/shell/catalog.d.ts +168 -0
  37. package/dist/shell/catalog.js +278 -0
  38. package/dist/shell/clock.d.ts +16 -0
  39. package/dist/shell/clock.js +36 -0
  40. package/dist/shell/filing.d.ts +39 -0
  41. package/dist/shell/filing.js +68 -0
  42. package/dist/shell/finder.d.ts +116 -0
  43. package/dist/shell/finder.js +564 -0
  44. package/dist/shell/geometry.d.ts +196 -0
  45. package/dist/shell/geometry.js +241 -0
  46. package/dist/shell/index.d.ts +29 -0
  47. package/dist/shell/index.js +11 -0
  48. package/dist/shell/shell.d.ts +150 -0
  49. package/dist/shell/shell.js +213 -0
  50. package/dist/shell/state.d.ts +88 -0
  51. package/dist/shell/state.js +103 -0
  52. package/dist/shell/storage.d.ts +14 -0
  53. package/dist/shell/storage.js +41 -0
  54. package/dist/shell/windows.d.ts +215 -0
  55. package/dist/shell/windows.js +343 -0
  56. package/dist/styles/base.d.ts +3 -1
  57. package/dist/styles/recipes/field.d.ts +10 -6
  58. package/dist/styles/recipes/field.js +8 -7
  59. package/dist/styles/recipes/focus.d.ts +7 -3
  60. package/dist/styles/recipes/rule.d.ts +11 -8
  61. package/dist/styles/recipes/rule.js +31 -13
  62. package/dist/styles/recipes/scroll-rail.d.ts +7 -6
  63. package/dist/styles/recipes/scroll-rail.js +18 -18
  64. package/dist/styles/recipes/shadow.d.ts +10 -6
  65. package/dist/styles/recipes/shadow.js +4 -2
  66. package/dist/styles/recipes/stroke.d.ts +85 -0
  67. package/dist/styles/recipes/stroke.js +53 -0
  68. package/dist/styles/recipes/surface.d.ts +8 -4
  69. package/dist/styles/recipes/surface.js +23 -17
  70. package/dist/styles/recipes/title-bar.d.ts +7 -0
  71. package/dist/styles/recipes/title-bar.js +25 -22
  72. package/dist/styles/recipes/toggle.js +3 -3
  73. package/dist/window-chrome.d.ts +43 -0
  74. package/dist/window-chrome.js +13 -0
  75. package/dist/zoom.d.ts +9 -9
  76. package/docs/SPEC.md +34 -32
  77. package/editor/vscode.html-custom-data.json +12 -7
  78. package/editor/web-types.json +50 -14
  79. package/package.json +10 -2
@@ -152,7 +152,7 @@
152
152
  },
153
153
  {
154
154
  "name": "vf-checkbox",
155
- "description": "The classic System 7 checkbox: a 13×13 white square with a 1px black\nborder whose checked state is the corner-to-corner ✕ glyph — the pixel-exact\ncross traced from the Classic Macintosh UI Kit sprite. The border \"thickens\"\nwhile pressed, exactly like the original control.\n\nForm-associated: submits `value` under `name` when checked (like a native\ncheckbox) and restores its initial checked state on form reset. Toggles on\nclick and Space.\n---\n\n\n### **Events:**\n - **vf-change** - When toggled by user interaction. `detail: { checked: boolean }`.\n- **input** - Native event, dispatched from the host per user toggle (with `change`, the pair a native checkbox fires). A programmatic `checked` set fires nothing, as on a native checkbox.\n- **change** - Native event, dispatched from the host per user toggle so form delegation and framework bindings hear it.\n\n### **Slots:**\n - _default_ - The label, rendered to the right of the box with a 6px gap. Left empty, the label and its gap collapse: the control is the bare 13×13 box.\n\n### **CSS Parts:**\n - **box** - The 13×13 checkbox square.\n- **label** - The label wrapper around the slot.",
155
+ "description": "The classic System 7 checkbox: a 12×12 white square with a 1px black\nborder whose checked state is the corner-to-corner ✕ glyph — the pixel-exact\ncross traced from the Classic Macintosh UI Kit sprite, filling the 10×10\ninterior. The border \"thickens\" while pressed, exactly like the original\ncontrol.\n\nForm-associated: submits `value` under `name` when checked (like a native\ncheckbox) and restores its initial checked state on form reset. Toggles on\nclick and Space.\n---\n\n\n### **Events:**\n - **vf-change** - When toggled by user interaction. `detail: { checked: boolean }`.\n- **input** - Native event, dispatched from the host per user toggle (with `change`, the pair a native checkbox fires). A programmatic `checked` set fires nothing, as on a native checkbox.\n- **change** - Native event, dispatched from the host per user toggle so form delegation and framework bindings hear it.\n\n### **Slots:**\n - _default_ - The label, rendered to the right of the box with a 6px gap. Left empty, the label and its gap collapse: the control is the bare 12×12 box.\n\n### **CSS Parts:**\n - **box** - The 12×12 checkbox square.\n- **label** - The label wrapper around the slot.",
156
156
  "attributes": [
157
157
  {
158
158
  "name": "checked",
@@ -204,7 +204,7 @@
204
204
  },
205
205
  {
206
206
  "name": "vf-container",
207
- "description": "`<vf-container>` — a box that is nothing but its declared size.\n\nThe kit's positioned-placement story (src/position.ts) ends with one line of\nCSS it can't write for you: children placed with `top`/`left` need a\npositioned ancestor, and while every kit container is one — a window body, a\nstack, a fieldset — a region of *your own* needs `position: relative` in a\nstylesheet. This component is that region as an element: declare `width` and\n`height` in whole system px, slot anything into it, place children against\nits origin. A DITL's enclosing rectangle, with nothing drawn in it.\n\n```html\n<vf-container width=\"200\" height=\"120\">\n <vf-icon label=\"System\" width=\"64\" top=\"8\" left=\"12\">…</vf-icon>\n <vf-icon label=\"Finder\" width=\"64\" top=\"8\" left=\"104\">…</vf-icon>\n</vf-container>\n```\n\nThe rectangle is the whole API — `width`/`height` here, plus the `top`/`left`\npair nearly every component takes (VfPositioned), so a container is\nitself placeable: inside a window, a desktop, or another container, at whole\nsystem px that keep its box on the device-pixel grid by construction.\n\n**It is not a `vf-stack`.** The stack is a flexbox with opinions — it\ndistributes children along an axis, compiles `fill-width`/`fill-height` into\nflex, defaults a cross-axis alignment. This box has no layout opinion at\nall: in-flow children get normal flow, placed children get a coordinate\nsystem, and that is the whole API. Reach for it when the stack's opinions\nare the thing in the way — a field of placed icons, a fixed stage for\nabsolutely-positioned art, a consumer's own composition that brings its\nlayout with it.\n\n**The declared size is the layout.** `width`/`height` land on the host as a\nlive `calc(var(--vf-scale, 1) * Npx)` (VfSized), so the box scales\nwith the display and sits on the device-pixel grid by construction. Content\nthat outgrows the box overflows it rather than growing it — the number is\nthe layout, and content that doesn't fit is a number to raise. Leave a\ndimension off and that axis shrink-wraps: `fit-content`, not the parent's\nwidth, because a layout box that silently claimed a size nobody declared\nwould be inventing one (the `vf-stack` rule, held here too).\n\n**It paints nothing and means nothing** — unless `pattern` or `rule` say\nwhat to paint. No role, keyboard behavior or selection; what it holds\ndecides what it is.\n\n**`rule` draws the 1px rule on the edges it names** — `rule=\"bottom\"` is\nthe menu bar's anatomy (the box's rows over one row of ink), `rule=\"top\"`\na status strip's, all four a framed box. The rule is the box's own border\n(vfRule), inside the declared size, so a 24px `rule=\"bottom\"`\nstrip is 23 rows of box over the line; content, `fill-width` children and\nplaced children begin inside it, as a rectangle's interior begins inside\nFrameRect's line.\n\n**`pattern` fills the box with a 1-bit pattern**: one of the 38 standard\nMacPaint patterns by name (`pattern=\"bricks\"`, `pattern=\"gray-50\"` —\ndocs/PATTERNS.md has the table), or sixteen hex digits stating a custom\n8×8 pattern row by row, the way a PAT resource did. It is painted as the\nbox's own background — black ink on a `--vf-white` ground, anchored at\nthe box's top-left corner, under the content — by the same repeating tile\nas the desktop dither, so it is 1-bit at every density and zoom and a box\nof any size, declared or not, costs nothing more (src/pattern-fill.ts).\nUnder forced colors the pattern goes flat Canvas.\n\n**It holds its box on the device-pixel grid** — with a `GridSnapController`.\nA container's box is itself the consumer's coordinate system, including for\nnon-`vf` content that cannot correct itself, so the box is the thing to\nhold on the grid. The shadow box below owns the `position: relative` anchor\nand the `vf-snap` class together, so the correction\nmoves the whole coordinate system — everything placed against it rides\nalong instead of being re-corrected child by child. (`vf-stack` shipped\nwithout a controller on the theory that slotted `vf-*` children correct\ntheir own origins; this component is where that theory's gap — consumer\ncontent — became visible, and the stack has since adopted the same\narrangement.)\n\nLike the stack it is **typographically transparent**: `vfBase`'s chrome\ndress is returned to `inherit` on the host, so wrapping content in a sized\nbox changes nothing about how that content reads.\n\n`fill-width` / `fill-height` work here the way they do everywhere: read\nabout the host (be as big as *its* parent allows), and compiled for slotted\nchildren — `width: 100%` in normal flow, so a child filling the cross of a\ndeclared box needs no stylesheet. A height fill needs a declared `height`\nto resolve against; with none it is inert, not an error.\n---\n\n\n### **Slots:**\n - _default_ - The content. In flow by default; `top`/`left` on a kit child places it against this box's origin. `fill-width` / `fill-height` on a child fills it to the declared box.",
207
+ "description": "`<vf-container>` — a box that is nothing but its declared size.\n\nThe kit's positioned-placement story (src/position.ts) ends with one line of\nCSS it can't write for you: children placed with `top`/`left` need a\npositioned ancestor, and while every kit container is one — a window body, a\nstack, a fieldset — a region of *your own* needs `position: relative` in a\nstylesheet. This component is that region as an element: declare `width` and\n`height` in whole system px, slot anything into it, place children against\nits origin. A DITL's enclosing rectangle, with nothing drawn in it.\n\n```html\n<vf-container width=\"200\" height=\"120\">\n <vf-icon label=\"System\" width=\"64\" top=\"8\" left=\"12\">…</vf-icon>\n <vf-icon label=\"Finder\" width=\"64\" top=\"8\" left=\"104\">…</vf-icon>\n</vf-container>\n```\n\nThe rectangle is the whole API — `width`/`height` here, plus the `top`/`left`\npair nearly every component takes (VfPositioned), so a container is\nitself placeable: inside a window, a desktop, or another container, at whole\nsystem px that keep its box on the device-pixel grid by construction.\n\n**It is not a `vf-stack`.** The stack is a flexbox with opinions — it\ndistributes children along an axis, compiles `fill-width`/`fill-height` into\nflex, defaults a cross-axis alignment. This box has no layout opinion at\nall: in-flow children get normal flow, placed children get a coordinate\nsystem, and that is the whole API. Reach for it when the stack's opinions\nare the thing in the way — a field of placed icons, a fixed stage for\nabsolutely-positioned art, a consumer's own composition that brings its\nlayout with it.\n\n**The declared size is the layout.** `width`/`height` land on the host as a\nlive `calc(var(--vf-scale, 1) * Npx)` (VfSized), so the box scales\nwith the display and sits on the device-pixel grid by construction. Content\nthat outgrows the box overflows it rather than growing it — the number is\nthe layout, and content that doesn't fit is a number to raise. Leave a\ndimension off and that axis shrink-wraps: `fit-content`, not the parent's\nwidth, because a layout box that silently claimed a size nobody declared\nwould be inventing one (the `vf-stack` rule, held here too).\n\n**It paints nothing and means nothing** — unless `pattern` or `rule` say\nwhat to paint. No role, keyboard behavior or selection; what it holds\ndecides what it is. A page that gives it a role and a `tabindex` — a\npattern chooser's cells as radios — gets the kit's keyboard focus mark\nrather than the browser's ring: the dashed rule below the box.\n\n**`rule` draws the 1px rule on the edges it names** — `rule=\"bottom\"` is\nthe menu bar's anatomy (the box's rows over one row of ink), `rule=\"top\"`\na status strip's, all four a framed box. The rule is drawn inside the\ndeclared size (vfRule), so a 24px `rule=\"bottom\"` strip is 23 rows\nof box over the line; content, `fill-width` children and placed children\nbegin inside it, as a rectangle's interior begins inside FrameRect's line.\n\n**`pattern` fills the box with a 1-bit pattern**: one of the 38 standard\nMacPaint patterns by name (`pattern=\"bricks\"`, `pattern=\"gray-50\"` —\ndocs/PATTERNS.md has the table), or sixteen hex digits stating a custom\n8×8 pattern row by row, the way a PAT resource did. It is painted as the\nbox's own background — black ink on a `--vf-white` ground, anchored at\nthe box's top-left corner, under the content — by the same repeating tile\nas the desktop dither, so it is 1-bit at every density and zoom and a box\nof any size, declared or not, costs nothing more (src/pattern-fill.ts).\nUnder forced colors the pattern goes flat Canvas.\n\n**It holds its box on the device-pixel grid** — with a `GridSnapController`.\nA container's box is itself the consumer's coordinate system, including for\nnon-`vf` content that cannot correct itself, so the box is the thing to\nhold on the grid. The correction lands on the shadow box below, and the\ncoordinate system sits inside it, so the correction moves the whole\ncoordinate system — everything placed against it rides along instead of\nbeing re-corrected child by child. (`vf-stack` shipped\nwithout a controller on the theory that slotted `vf-*` children correct\ntheir own origins; this component is where that theory's gap — consumer\ncontent — became visible, and the stack has since adopted the same\narrangement.)\n\nLike the stack it is **typographically transparent**: `vfBase`'s chrome\ndress is returned to `inherit` on the host, so wrapping content in a sized\nbox changes nothing about how that content reads.\n\n`fill-width` / `fill-height` work here the way they do everywhere: read\nabout the host (be as big as *its* parent allows), and compiled for slotted\nchildren — `width: 100%` in normal flow, so a child filling the cross of a\ndeclared box needs no stylesheet. A height fill needs a declared `height`\nto resolve against; with none it is inert, not an error.\n---\n\n\n### **Slots:**\n - _default_ - The content. In flow by default; `top`/`left` on a kit child places it against this box's origin. `fill-width` / `fill-height` on a child fills it to the declared box.",
208
208
  "attributes": [
209
209
  {
210
210
  "name": "pattern",
@@ -213,7 +213,7 @@
213
213
  },
214
214
  {
215
215
  "name": "rule",
216
- "description": "The 1px rule on the box's edges: edge names separated by spaces —\n`\"bottom\"`, `\"top bottom\"`, up to all four in any order. Drawn as the\nbox's own border inside the declared size, in `--vf-black`, scaled with\nthe display like every kit frame's border; content and placed children\nbegin inside it.\nUnset, no rule; a value naming anything but an edge draws none and\nwarns once.",
216
+ "description": "The 1px rule on the box's edges: edge names separated by spaces —\n`\"bottom\"`, `\"top bottom\"`, up to all four in any order. Drawn inside\nthe declared size, in `--vf-black`, scaled with the display like every\nkit frame; content and placed children begin inside it.\nUnset, no rule; a value naming anything but an edge draws none and\nwarns once.",
217
217
  "values": []
218
218
  },
219
219
  {
@@ -251,7 +251,7 @@
251
251
  },
252
252
  {
253
253
  "name": "vf-desktop",
254
- "description": "`<vf-desktop>` — the full-bleed classic desktop container.\n\nRenders the desktop pattern — the classic 50% dither by default, or any of\nthe standard patterns by name (`pattern`, System 7's General Controls\nsetting) — and manages the stacking order and `active` state of slotted\n`vf-window` children: a `pointerdown` or\n`focusin` (keyboard focus) anywhere inside a window brings it to the front\nand makes it the single active window. The windows' light-DOM order is kept\nin step with the stacking order (bottom-most first, synced in a task once\nany pointer gesture has ended), so tabbing walks the stack the way the eye\ndoes and Shift+Tab is its exact mirror.\n\nUtility windows (`vf-window[variant=\"utility\"]`) stack in a floating tier\nabove every document-tier window, restack only among themselves, and stand\noutside the single-active invariant entirely — clicking a palette neither\ndeactivates the active document window nor greys the palette, exactly as\nSystem 7's floating windoids behaved while their application was frontmost.\nA slotted `vf-menu-bar` (or a free-standing `vf-menu`) sits on a tier\nabove both, so its dropped menus cover palettes and document windows\nalike; only the screen-corner mask is in front of it.\n\n**Deactivation.** On a real System 7 machine clicking the desktop clicked\nthe *Finder* — the frontmost application's windows lost their stripes.\nclearActive is that gesture's handler: it clears `active` from\nthe whole document tier, and **zero active windows is a legal state**,\nheld until a press or keyboard focus re-enters a document window (or a\nnew one is slotted, which activates it — opening a window brings its\napplication forward). The desktop never takes this decision itself: its\nfurniture is slotted light DOM (an icon layer, say), so only the page\nknows which of its children — or which presses on the bare dither — mean\n\"the Finder\", and it routes those through `clearActive()`. Left alone,\nthe classic always-one-active behavior is unchanged. activeWindow\nreads the current holder, and every change of holder — including to and\nfrom none — fires `vf-activate`.\n\nThe desktop is a raster with an explicit size, always: **`width` and\n`height`**, in system px, the way a WIND resource declared a window's —\nthe host box renders at the declared screen plus `2 × bezel` per axis, a\nwhole number of system pixels by construction (default 512×342, the\ncompact Mac's screen). Pure CSS sizing is not supported; the page sets\nthe numbers — directly, or via VfDesktop.fitWithin on\n`resize`/`onScaleChange` for a viewport-filling desktop — and positions\nthe sized box with its own stylesheet, keeping any sub-system-pixel\nslack on its side. `bezel` (system px) draws the black screen surround —\nthe CRT's unlit margin — around the screen, rounding its four corners\nwith the classic corner mask.\n\n**`pattern`** names the desktop pattern — `gray-50` (the dither) by\ndefault, any of the 38 standard patterns (docs/PATTERNS.md), or sixteen\nhex digits stating a custom 8×8 pattern, as on `vf-container`. It is\npainted as the screen's own background: black ink on an opaque white\npaper, a repeating tile drawn at the display's resolution, 1-bit at every\ndensity and zoom (src/pattern-fill.ts).\n\n**The drag surface.** The Finder dragged an icon as a dotted outline drawn\non the *screen*, clipped at its edge and phase-locked to its raster, so\nthe screen hosts the layer that outline draws on: a full-bleed child of\nthe screen, `pointer-events: none` (never a hit for the page's\n`elementsFromPoint`), whose children paint one tier above the menu bar\nand under the corner mask — the layer itself is deliberately no stacking\ncontext, since a blend inside one would composite against nothing. An\nicon reaches it without an import, the menu-handshake idiom: on a drag's\nfirst step it dispatches `vf-drag-surface-request` (bubbles, non-composed,\n`detail.surface` null), and the nearest desktop on its light-DOM path\nfills the detail with the layer. A window asks the same way and draws\nthere with the same pen: its zoom rects when it opens from a rect\n(`vf-window.show({ from })`), its outline under an `outline-drag`. Not the\ntop layer: stable Safari cannot\nblend an element there against the page (src/cursor.ts), and a second\nkit entry in the top layer would need a re-promotion handshake.\n\nCustom properties:\n- `--vf-desktop-pattern` — a consumer's own tile art in place of the\n pattern (the kit's default is a 1-bit 50% checker, opaque\n black-on-white on a 30-system-px tile). Set, it wins over `pattern` and\n renders as a placed tile grid at that same 30-px geometry\n (src/tile-grid.ts); a token swapped at runtime without touching the\n component wants a `requestUpdate()`.\n- `--vf-desktop` — base color painted *under* the pattern (default\n `#808080`). The pattern's paper is opaque, so this only becomes visible\n when `--vf-desktop-pattern` is overridden with a tile that has\n transparent cells (or with `none`).\n---\n\n\n### **Events:**\n - **vf-activate** - The active document-tier window changed. Detail `{ window: HTMLElement | null }` — the new holder, or `null` when the document tier deactivated (a {@link clearActive} call, or the active window leaving the DOM with none behind it). Fired once per change of holder, never for a re-assertion of the same one.\n\n### **Slots:**\n - _default_ - Default slot: menu bar, windows, anything.\n\n### **CSS Properties:**\n - **--vf-desktop** - base color under the desktop pattern — occluded by the pattern's opaque paper, so it only shows through a custom `--vf-desktop-pattern` _(default: #808080)_\n- **--vf-desktop-pattern** - a consumer's own desktop tile, in place of `pattern` — the kit's default is the 50% checker drawn as opaque black-on-white rects on a 30-system-px tile. Override the whole tile; consumer art renders as a placed tile grid at that same geometry (raster art magnifies nearest-neighbor, the `vf-img` idiom) _(default: undefined)_\n\n### **CSS Parts:**\n - **desktop** - The patterned screen surface — the whole-system-px raster (inset by `bezel` when one is set).",
254
+ "description": "`<vf-desktop>` — the full-bleed classic desktop container.\n\nRenders the desktop pattern — the classic 50% dither by default, or any of\nthe standard patterns by name (`pattern`, System 7's General Controls\nsetting) — and manages the stacking order and `active` state of slotted\n`vf-window` children: a `pointerdown` or\n`focusin` (keyboard focus) anywhere inside a window brings it to the front\nand makes it the single active window. The windows' light-DOM order is kept\nin step with the stacking order (bottom-most first, synced in a task once\nany pointer gesture has ended), so tabbing walks the stack the way the eye\ndoes and Shift+Tab is its exact mirror.\n\nUtility windows (`vf-window[variant=\"utility\"]`) stack in a floating tier\nabove every document-tier window, restack only among themselves, and stand\noutside the single-active invariant entirely — clicking a palette neither\ndeactivates the active document window nor greys the palette, exactly as\nSystem 7's floating windoids behaved while their application was frontmost.\nA slotted `vf-menu-bar` (or a free-standing `vf-menu`) sits on a tier\nabove both, so its dropped menus cover palettes and document windows\nalike; only the screen-corner mask is in front of it.\n\n**Deactivation.** On a real System 7 machine clicking the desktop clicked\nthe *Finder* — the frontmost application's windows lost their stripes.\nclearActive is that gesture's handler: it clears `active` from\nthe whole document tier, and **zero active windows is a legal state**,\nheld until a press or keyboard focus re-enters a document window (or a\nnew one is slotted, which activates it — opening a window brings its\napplication forward). The desktop never takes this decision itself: its\nfurniture is slotted light DOM (an icon layer, say), so only the page\nknows which of its children — or which presses on the bare dither — mean\n\"the Finder\", and it routes those through `clearActive()`. Left alone,\nthe classic always-one-active behavior is unchanged. activeWindow\nreads the current holder, and every change of holder — including to and\nfrom none — fires `vf-activate`.\n\n**Hidden windows.** A window with `hidden` — closed by a page that hides\nits windows rather than removing them, through `vf-window.hide()` or the\nattribute itself — never holds the active state. One slotted hidden waits\nto be shown; `bringToFront()` on one gives it its place in the stack and\nactivates nothing; the holder hiding hands the state to the topmost shown\ndocument window, or to none. A window shown into a tier where none is\nactive, unless the tier was deliberately deactivated, takes it.\nstackingOrder lists the windows as they stand, bottom-most first.\n\n**The work area.** A slotted `vf-menu-bar` along the top takes its band\noff the screen: workArea is what is left, and the gestures on the\nscreen stay in it — a window dragged up stops with its title bar under the\nbar, where it can still be grabbed, and an icon dropped, nudged or walked\non the desktop lands below the bar. `window-top` deepens the area for\nwindows alone (windowArea), for a page with a strip of its own\nunder the bar. A gesture asks for the box it is clamped into with\n`vf-placement-bounds-request` (bubbles, non-composed), the drag surface's\nhandshake, and the desktop answers for the hosts placed on its screen.\n\nThe desktop is a raster with an explicit size, always: **`width` and\n`height`**, in system px, the way a WIND resource declared a window's —\nthe host box renders at the declared screen plus `2 × bezel` per axis, a\nwhole number of system pixels by construction (default 512×342, the\ncompact Mac's screen). Pure CSS sizing is not supported; the page sets\nthe numbers — directly, or via VfDesktop.fitWithin on\n`resize`/`onScaleChange` for a viewport-filling desktop — and positions\nthe sized box with its own stylesheet, keeping any sub-system-pixel\nslack on its side. `bezel` (system px) draws the black screen surround —\nthe CRT's unlit margin — around the screen, rounding its four corners\nwith the classic corner mask.\n\n**`pattern`** names the desktop pattern — `gray-50` (the dither) by\ndefault, any of the 38 standard patterns (docs/PATTERNS.md), or sixteen\nhex digits stating a custom 8×8 pattern, as on `vf-container`. It is\npainted as the screen's own background: black ink on an opaque white\npaper, a repeating tile drawn at the display's resolution, 1-bit at every\ndensity and zoom (src/pattern-fill.ts).\n\n**The drag surface.** The Finder dragged an icon as a dotted outline drawn\non the *screen*, clipped at its edge and phase-locked to its raster, so\nthe screen hosts the layer that outline draws on: a full-bleed child of\nthe screen, `pointer-events: none` (never a hit for the page's\n`elementsFromPoint`), whose children paint one tier above the menu bar\nand under the corner mask — the layer itself is deliberately no stacking\ncontext, since a blend inside one would composite against nothing. An\nicon reaches it without an import, the menu-handshake idiom: on a drag's\nfirst step it dispatches `vf-drag-surface-request` (bubbles, non-composed,\n`detail.surface` null), and the nearest desktop on its light-DOM path\nfills the detail with the layer. A window asks the same way and draws\nthere with the same pen: its zoom rects when it opens from a rect\n(`vf-window.show({ from })`), its outline under an `outline-drag`. Not the\ntop layer: stable Safari cannot\nblend an element there against the page (src/cursor.ts), and a second\nkit entry in the top layer would need a re-promotion handshake.\n\nCustom properties:\n- `--vf-desktop-pattern` — a consumer's own tile art in place of the\n pattern (the kit's default is a 1-bit 50% checker, opaque\n black-on-white on a 30-system-px tile). Set, it wins over `pattern` and\n renders as a placed tile grid at that same 30-px geometry\n (src/tile-grid.ts); a token swapped at runtime without touching the\n component wants a `requestUpdate()`.\n- `--vf-desktop` — base color painted *under* the pattern (default\n `#808080`). The pattern's paper is opaque, so this only becomes visible\n when `--vf-desktop-pattern` is overridden with a tile that has\n transparent cells (or with `none`).\n---\n\n\n### **Events:**\n - **vf-activate** - The active document-tier window changed. Detail `{ window: HTMLElement | null }` — the new holder, or `null` when the document tier deactivated (a {@link clearActive} call, or the active window leaving the DOM or hiding with no shown window behind it). Fired once per change of holder, never for a re-assertion of the same one.\n\n### **Slots:**\n - _default_ - Default slot: menu bar, windows, anything.\n\n### **CSS Properties:**\n - **--vf-desktop** - base color under the desktop pattern — occluded by the pattern's opaque paper, so it only shows through a custom `--vf-desktop-pattern` _(default: #808080)_\n- **--vf-desktop-pattern** - a consumer's own desktop tile, in place of `pattern` — the kit's default is the 50% checker drawn as opaque black-on-white rects on a 30-system-px tile. Override the whole tile; consumer art renders as a placed tile grid at that same geometry (raster art magnifies nearest-neighbor, the `vf-img` idiom) _(default: undefined)_\n\n### **CSS Parts:**\n - **desktop** - The patterned screen surface — the whole-system-px raster (inset by `bezel` when one is set).",
255
255
  "attributes": [
256
256
  {
257
257
  "name": "width",
@@ -273,6 +273,11 @@
273
273
  "description": "The desktop pattern — System 7's General Controls setting. A library\npattern by name (`gray-50`, the classic dither, by default; `gray-75`,\n`bricks`, … — docs/PATTERNS.md) or sixteen hex digits stating a custom\n8×8 pattern, as on `vf-container`. Painted black on opaque white over\nthe whole screen, 1-bit at every density and zoom. A\n`--vf-desktop-pattern` token override still wins and renders the\nconsumer's tile as a placed grid; an unrecognized value warns once and\nkeeps the dither.",
274
274
  "values": []
275
275
  },
276
+ {
277
+ "name": "window-top",
278
+ "description": "The least `top` a window may take, in system px from the screen's top —\nfor a page that keeps a strip of its own under the menu bar, over the\nwindows. A window dragged on this desktop stops there, and\nwindowArea starts there; icons still stop at the menu bar. Below\nthe bar's bottom it changes nothing. Unset, windows stop at the bar.",
279
+ "values": []
280
+ },
276
281
  {
277
282
  "name": "top",
278
283
  "description": "Offset from the top of the positioning parent, in whole system px.\nSetting this (or `left`) absolutely positions the element within its\nparent; the coordinate left unset is 0. Remove both to return the\nelement to normal flow.",
@@ -449,7 +454,7 @@
449
454
  },
450
455
  {
451
456
  "name": "vf-icon-field",
452
- "description": "`<vf-icon-field>` — the container a field of `vf-icon`s sits in: a desktop's\nicons, a folder window's contents.\n\nEvery other set in the kit has its container — `vf-list` owns\n`vf-list-item`, `vf-radio-group` owns `vf-radio`, `vf-menu` owns\n`vf-menu-item`, `vf-select` owns `vf-option` — and `vf-icon` was the one\nitem whose container the consumer wrote by hand: a bare\n`<div role=\"listbox\" aria-multiselectable=\"true\">`, because an `option` is\nonly valid inside a `listbox` that owns it, and every kit container is a\npositioning anchor by design, so nothing in the kit was neutral enough to\nstand in. A consumer who forgot the role got icons that silently degraded\nto pictures. This is that container, as kit furniture:\n\n```html\n<vf-desktop width=\"512\" height=\"342\">\n <vf-icon-field label=\"Desktop\" fill-width fill-height>\n <vf-icon label=\"Macintosh HD\" width=\"64\" selectable movable editable left=\"16\" top=\"24\">…</vf-icon>\n <vf-icon label=\"Trash\" width=\"64\" selectable movable editable left=\"16\" top=\"280\">…</vf-icon>\n </vf-icon-field>\n <vf-window heading=\"Documents\" width=\"320\" height=\"201\" scrollbars=\"both\" top=\"40\" left=\"120\">\n <vf-icon-field label=\"Documents\">\n <vf-icon label=\"Read Me\" width=\"64\" selectable movable editable left=\"16\" top=\"16\">…</vf-icon>\n </vf-icon-field>\n </vf-window>\n</vf-desktop>\n```\n\n### Semantics through internals\n\n`role=\"listbox\"` and `aria-multiselectable=\"true\"` always — the Finder was\nalways multi-select, so there is no attribute for it — and `label` as the\naccessible name, the way `vf-scroll-area` takes one. Internals values are\ndefaults (SPEC §2): a consumer's own `role`/`aria-*` on the tag still wins.\nA `selectable` icon inside becomes a real `option` carrying `aria-selected`;\n`vf-icon` matches this tag directly, since a role written through internals\nnever lands as an attribute for `closest()` to find.\n\n### Layout-neutral, exactly what the div was\n\nAn in-flow block with no size, no inset and no position of its own,\npainting nothing — the `vf-stack` posture. A field whose icons are all\nplaced is a zero-height block, so the icons keep anchoring to the desktop's\nraster or the window's plane, stored coordinates mean what they meant, and\na press on the bare dither still reaches the desktop. It takes `top`/`left`\nand `width`/`height` like the other declared-box containers, so a page that\nwants the field to be a box places and sizes it, at which point it becomes\nthe anchor — the placement working, as documented for everything.\n`fill-width`/`fill-height` are the other way to give it a box, read about\nthe host the way `vf-stack` and `vf-container` read them: a filled field\nstays in flow and static, so its icons keep their anchor, and it has a\nsurface to press — which is what the rubber band needs.\n\n### The rubber band\n\nA press on the field's own background — not on an icon — dragged across\nthe field draws the Finder's dotted selection rectangle from the press to\nthe pointer, and the selection follows it live by the Finder's one rule:\n**an icon is selected exactly when it was selected at the press XOR the\nrectangle touches it.** The press fixes that anchor: a plain press has\nalready cleared everything (the way any press outside an icon does), so\nthe rectangle simply selects what it touches and releases what it leaves;\nwith Shift or ⌘ held the selection survives the press and the rectangle\n*toggles* against it — an icon already selected deselects while the\nrectangle covers it and comes back when it leaves, one that was not\nselects. Each change reports `vf-select` as a press would. \"Touches\"\nmeans the icon's art cell or its name plate (VfIcon.touches), not\nthe empty cell beside them, so a rectangle through the gap between two\nicons selects neither. The release keeps the result; Escape or a\n`pointercancel` cancels, the rectangle vanishes and the selection goes\nback to the anchor. A press that never leaves its system pixel draws\nnothing.\n\nThe rectangle is drawn with the drag outline's pen (* paintSelectionRect: the dotted one-pixel outline, `filter: invert(1)`\nunder `mix-blend-mode: difference`) at the field's own level, which is\nwhere the Finder drew its marquee — on the desktop under the windows, in a\nwindow body over that window's content and under any window above it —\npositioned against the viewport from the field's own shadow, since a\nlayout-neutral field has no box of its own to anchor to. It reaches no\nfurther than the field, inside every clip above the field (a window body,\na scroll viewport, the raster's edge), so it never paints outside the\nregion the icons are visible in. Its dots take the pen's phase on the\n*screen* — the desktop's, found by the `vf-drag-surface-request`\nhandshake the drag outline uses (penPhase) — so over the desktop\ndither the rectangle reads as a black line wherever the field sits; with\nno desktop, the field's own box is the reference.\n\nOnly a field with a box can be pressed: fill it, or place and size it. An\nunplaced, unfilled field of placed icons is zero-height and draws no band.\n`touch-action` is left alone, so on a touch screen a drag on the\nbackground pans a scrolling window as it always did; the band is a mouse\nand pen gesture.\n\n### The walk\n\nThe Finder's Clean Up moved a container's icons one at a time, each\nicon's dotted outline travelling to its cell and the icon landing when\nthe outline arrived. dragIcons is that walk: `{ icon, left, top }`\nmoves in the page's order — which icon goes first is a statement about\nthe page's lattice, and the kit ships none — each through the icon's own\n`dragTo`, with a beat (`WALK_BEAT_MS`, src/motion.ts) after every landing\nthat showed. It resolves when the last icon has landed. One walk per\nfield: a second call finishes the first. A press anywhere, or Escape,\nfinishes it too — every icon still to go lands at its target at once, the\nFinder never made you wait — and so does the field leaving the DOM; an\nicon gone from the DOM by its turn is skipped. Under\n`prefers-reduced-motion` every icon lands at once, no outline, no beat.\n\n### `size` is the view's\n\n`large` or `small`, written onto every icon in the field when set and\nwhenever it changes, so View → by Small Icon is one attribute instead of a\nloop over every icon. Unset, each icon keeps its own.\n\n### The desktop uses it, and renders none\n\nA desktop's icons sit in a field slotted into `vf-desktop` beside the\nwindows, written by the page; a folder window's icons sit in one slotted\ninto the window body. `vf-desktop` builds no field of its own: its furniture\nis slotted light DOM and the page decides what it is, a desktop with no\nicons should carry no empty listbox, and a field inside the desktop's\nshadow is one `closest()` could not reach.\n---\n\n\n### **Slots:**\n - _default_ - The icons.",
457
+ "description": "`<vf-icon-field>` — the container a field of `vf-icon`s sits in: a desktop's\nicons, a folder window's contents.\n\nEvery other set in the kit has its container — `vf-list` owns\n`vf-list-item`, `vf-radio-group` owns `vf-radio`, `vf-menu` owns\n`vf-menu-item`, `vf-select` owns `vf-option` — and `vf-icon` was the one\nitem whose container the consumer wrote by hand: a bare\n`<div role=\"listbox\" aria-multiselectable=\"true\">`, because an `option` is\nonly valid inside a `listbox` that owns it, and every kit container is a\npositioning anchor by design, so nothing in the kit was neutral enough to\nstand in. A consumer who forgot the role got icons that silently degraded\nto pictures. This is that container, as kit furniture:\n\n```html\n<vf-desktop width=\"512\" height=\"342\">\n <vf-icon-field label=\"Desktop\" fill-width fill-height>\n <vf-icon label=\"Macintosh HD\" width=\"64\" selectable movable editable left=\"16\" top=\"24\">…</vf-icon>\n <vf-icon label=\"Trash\" width=\"64\" selectable movable editable left=\"16\" top=\"280\">…</vf-icon>\n </vf-icon-field>\n <vf-window heading=\"Documents\" width=\"320\" height=\"201\" scrollbars=\"both\" top=\"40\" left=\"120\">\n <vf-icon-field label=\"Documents\">\n <vf-icon label=\"Read Me\" width=\"64\" selectable movable editable left=\"16\" top=\"16\">…</vf-icon>\n </vf-icon-field>\n </vf-window>\n</vf-desktop>\n```\n\n### Semantics through internals\n\n`role=\"listbox\"` and `aria-multiselectable=\"true\"` always — the Finder was\nalways multi-select, so there is no attribute for it — and `label` as the\naccessible name, the way `vf-scroll-area` takes one. Internals values are\ndefaults (SPEC §2): a consumer's own `role`/`aria-*` on the tag still wins.\nA `selectable` icon inside becomes a real `option` carrying `aria-selected`;\n`vf-icon` matches this tag directly, since a role written through internals\nnever lands as an attribute for `closest()` to find.\n\n### Layout-neutral, exactly what the div was\n\nAn in-flow block with no size, no inset and no position of its own,\npainting nothing — the `vf-stack` posture. A field whose icons are all\nplaced is a zero-height block, so the icons keep anchoring to the desktop's\nraster or the window's plane, stored coordinates mean what they meant, and\na press on the bare dither still reaches the desktop. It takes `top`/`left`\nand `width`/`height` like the other declared-box containers, so a page that\nwants the field to be a box places and sizes it, at which point it becomes\nthe anchor — the placement working, as documented for everything.\n`fill-width`/`fill-height` are the other way to give it a box, read about\nthe host the way `vf-stack` and `vf-container` read them: a filled field\nstays in flow and static, so its icons keep their anchor, and it has a\nsurface to press — which is what the rubber band needs.\n\n### The rubber band\n\nA press on the field's own background — not on an icon — dragged across\nthe field draws the Finder's dotted selection rectangle from the press to\nthe pointer, and the selection follows it live by the Finder's one rule:\n**an icon is selected exactly when it was selected at the press XOR the\nrectangle touches it.** The press fixes that anchor: a plain press has\nalready cleared everything (a press on a field's background does), so\nthe rectangle simply selects what it touches and releases what it leaves;\nwith Shift or ⌘ held the selection survives the press and the rectangle\n*toggles* against it — an icon already selected deselects while the\nrectangle covers it and comes back when it leaves, one that was not\nselects. Each change reports `vf-select` as a press would. \"Touches\"\nmeans the icon's art cell or its name plate (VfIcon.touches), not\nthe empty cell beside them, so a rectangle through the gap between two\nicons selects neither. The release keeps the result; Escape or a\n`pointercancel` cancels, the rectangle vanishes and the selection goes\nback to the anchor. A press that never leaves its system pixel draws\nnothing.\n\nThe rectangle is drawn with the drag outline's pen (* paintSelectionRect: the dotted one-pixel outline, `filter: invert(1)`\nunder `mix-blend-mode: difference`) at the field's own level, which is\nwhere the Finder drew its marquee — on the desktop under the windows, in a\nwindow body over that window's content and under any window above it —\npositioned against the viewport from the field's own shadow, since a\nlayout-neutral field has no box of its own to anchor to. It reaches no\nfurther than the field, inside every clip above the field (a window body,\na scroll viewport, the raster's edge), so it never paints outside the\nregion the icons are visible in. Its dots take the pen's phase on the\n*screen* — the desktop's, found by the `vf-drag-surface-request`\nhandshake the drag outline uses (penPhase) — so over the desktop\ndither the rectangle reads as a black line wherever the field sits; with\nno desktop, the field's own box is the reference.\n\nOnly a field with a box can be pressed: fill it, or place and size it. An\nunplaced, unfilled field of placed icons is zero-height and draws no band.\n`touch-action` is left alone, so on a touch screen a drag on the\nbackground pans a scrolling window as it always did; the band is a mouse\nand pen gesture.\n\n### The walk\n\nThe Finder's Clean Up moved a container's icons one at a time, each\nicon's dotted outline travelling to its cell and the icon landing when\nthe outline arrived. dragIcons is that walk: `{ icon, left, top }`\nmoves in the page's order — which icon goes first is a statement about\nthe page's lattice, and the kit ships none — each through the icon's own\n`dragTo`, with a beat (`WALK_BEAT_MS`, src/motion.ts) after every landing\nthat showed. It resolves when the last icon has landed. One walk per\nfield: a second call finishes the first. A press anywhere, or Escape,\nfinishes it too — every icon still to go lands at its target at once, the\nFinder never made you wait — and so does the field leaving the DOM; an\nicon gone from the DOM by its turn is skipped. Under\n`prefers-reduced-motion` every icon lands at once, no outline, no beat.\n\n### `size` is the view's\n\n`large` or `small`, written onto every icon in the field when set and\nwhenever it changes, so View → by Small Icon is one attribute instead of a\nloop over every icon. Unset, each icon keeps its own.\n\n### The desktop uses it, and renders none\n\nA desktop's icons sit in a field slotted into `vf-desktop` beside the\nwindows, written by the page; a folder window's icons sit in one slotted\ninto the window body. `vf-desktop` builds no field of its own: its furniture\nis slotted light DOM and the page decides what it is, a desktop with no\nicons should carry no empty listbox, and a field inside the desktop's\nshadow is one `closest()` could not reach.\n---\n\n\n### **Slots:**\n - _default_ - The icons.",
453
458
  "attributes": [
454
459
  {
455
460
  "name": "label",
@@ -756,7 +761,7 @@
756
761
  },
757
762
  {
758
763
  "name": "vf-menu-bar",
759
- "description": "`<vf-menu-bar>` — the System 7 menu bar: white strip, 1px black bottom\nrule, slotted `<vf-menu>` children laid out from the left. `rounded` adds\nthe classic screen-corner mask to the top corners.\n\nCoordinates its menus: pressing a label opens that menu (and inverts the\nlabel); while any menu is open, hovering another label switches to it;\nEscape, an outside click, or item selection closes. ArrowLeft/ArrowRight\nmove between menus while one is open; ArrowDown/ArrowUp move focus through\nthe open menu's items, Home/End jump to its first/last, and typed letters\nrun the shared Finder first-letter type-ahead (src/type-ahead.ts).\n\nThe bar also owns the **press-drag-release** gesture (see src/menu-press.ts)\n— press a title, slide onto a command, release over it — because one press\nmay travel across several of its menus. `vf-select` drives its popup by the\nsame mechanic.\n---\n\n\n### **Slots:**\n - _default_ - `vf-menu` elements.\n\n### **CSS Properties:**\n - **--vf-menubar-height** - `vf-menu-bar` _(default: 20px)_\n\n### **CSS Parts:**\n - **bar** - The horizontal layout container.",
764
+ "description": "`<vf-menu-bar>` — the System 7 menu bar: white strip, 1px black bottom\nrule, slotted `<vf-menu>` children laid out from the left. `rounded` adds\nthe classic screen-corner mask to the top corners.\n\nCoordinates its menus: pressing a label opens that menu (and inverts the\nlabel); while any menu is open, hovering another label switches to it;\nEscape, an outside click, or item selection closes. ArrowLeft/ArrowRight\nmove between menus while one is open; ArrowDown/ArrowUp move focus through\nthe open menu's items, Home/End jump to its first/last, and typed letters\nrun the shared Finder first-letter type-ahead (src/type-ahead.ts).\n\nThe bar also owns the **press-drag-release** gesture (see src/menu-press.ts)\n— press a title, slide onto a command, release over it — because one press\nmay travel across several of its menus. `vf-select` drives its popup by the\nsame mechanic.\n---\n\n\n### **Slots:**\n - _default_ - `vf-menu` elements.\n- **end** - The bar's right end: a clock, say. Held 9px in from the end, and a `vf-label` there rides the bar's line, so its baseline is the menu titles'.\n\n### **CSS Properties:**\n - **--vf-menubar-height** - `vf-menu-bar` _(default: 20px)_\n\n### **CSS Parts:**\n - **bar** - The horizontal layout container.",
760
765
  "attributes": [
761
766
  {
762
767
  "name": "label",
@@ -1332,7 +1337,7 @@
1332
1337
  },
1333
1338
  {
1334
1339
  "name": "vf-separator",
1335
- "description": "`<vf-separator>` — a 1px System 7 rule.\n\nHorizontal by default (1px tall, full width); set the `vertical` attribute\nfor a 1px-wide vertical rule (give it a height, or let a flex parent\nstretch it).\n\nContainers may restyle it via custom properties:\n- `--vf-separator-color` — line color (default `var(--vf-black, #000)`).\n- `--vf-separator-style` — line style, e.g. `dotted` (default `solid`).\n `vf-menu` sets these so slotted separators render as the classic dimmed\n dotted menu rule (see Menus.png).\n---\n\n\n### **CSS Properties:**\n - **--vf-separator-color** - `vf-separator` rule color — `vf-menu` sets it to `--vf-disabled` for the dimmed menu rule _(default: undefined)_\n- **--vf-separator-style** - `vf-separator` rule style — `vf-menu` sets `dotted` (see `Menus.png`) _(default: solid)_",
1340
+ "description": "`<vf-separator>` — a 1px System 7 rule.\n\nHorizontal by default (1px tall, full width); set the `vertical` attribute\nfor a 1px-wide vertical rule (give it a height, or let a flex parent\nstretch it).\n\nContainers may restyle it via custom properties:\n- `--vf-separator-color` — line color (default `var(--vf-black, #000)`).\n- `--vf-separator-style` — `solid` (the default) or `dotted`, one system px\n on and one off. `vf-menu` sets these so slotted separators render as the\n classic dimmed dotted menu rule (see Menus.png).\n---\n\n\n### **CSS Properties:**\n - **--vf-separator-color** - `vf-separator` rule color — `vf-menu` sets it to `--vf-disabled` for the dimmed menu rule _(default: undefined)_\n- **--vf-separator-style** - `vf-separator` rule style: `solid` or `dotted` — `vf-menu` sets `dotted` (see `Menus.png`) _(default: solid)_",
1336
1341
  "attributes": [
1337
1342
  {
1338
1343
  "name": "vertical",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
3
3
  "name": "vintage-frames",
4
- "version": "0.13.0",
4
+ "version": "0.14.1",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
@@ -322,7 +322,7 @@
322
322
  },
323
323
  {
324
324
  "name": "vf-checkbox",
325
- "description": "The classic System 7 checkbox: a 13×13 white square with a 1px black\nborder whose checked state is the corner-to-corner ✕ glyph — the pixel-exact\ncross traced from the Classic Macintosh UI Kit sprite. The border \"thickens\"\nwhile pressed, exactly like the original control.\n\nForm-associated: submits `value` under `name` when checked (like a native\ncheckbox) and restores its initial checked state on form reset. Toggles on\nclick and Space.\n---\n\n\n### **Events:**\n - **vf-change** - When toggled by user interaction. `detail: { checked: boolean }`.\n- **input** - Native event, dispatched from the host per user toggle (with `change`, the pair a native checkbox fires). A programmatic `checked` set fires nothing, as on a native checkbox.\n- **change** - Native event, dispatched from the host per user toggle so form delegation and framework bindings hear it.\n\n### **Slots:**\n - _default_ - The label, rendered to the right of the box with a 6px gap. Left empty, the label and its gap collapse: the control is the bare 13×13 box.\n\n### **CSS Parts:**\n - **box** - The 13×13 checkbox square.\n- **label** - The label wrapper around the slot.",
325
+ "description": "The classic System 7 checkbox: a 12×12 white square with a 1px black\nborder whose checked state is the corner-to-corner ✕ glyph — the pixel-exact\ncross traced from the Classic Macintosh UI Kit sprite, filling the 10×10\ninterior. The border \"thickens\" while pressed, exactly like the original\ncontrol.\n\nForm-associated: submits `value` under `name` when checked (like a native\ncheckbox) and restores its initial checked state on form reset. Toggles on\nclick and Space.\n---\n\n\n### **Events:**\n - **vf-change** - When toggled by user interaction. `detail: { checked: boolean }`.\n- **input** - Native event, dispatched from the host per user toggle (with `change`, the pair a native checkbox fires). A programmatic `checked` set fires nothing, as on a native checkbox.\n- **change** - Native event, dispatched from the host per user toggle so form delegation and framework bindings hear it.\n\n### **Slots:**\n - _default_ - The label, rendered to the right of the box with a 6px gap. Left empty, the label and its gap collapse: the control is the bare 12×12 box.\n\n### **CSS Parts:**\n - **box** - The 12×12 checkbox square.\n- **label** - The label wrapper around the slot.",
326
326
  "doc-url": "",
327
327
  "attributes": [
328
328
  {
@@ -374,7 +374,7 @@
374
374
  "slots": [
375
375
  {
376
376
  "name": "",
377
- "description": "The label, rendered to the right of the box with a 6px gap. Left empty, the label and its gap collapse: the control is the bare 13×13 box."
377
+ "description": "The label, rendered to the right of the box with a 6px gap. Left empty, the label and its gap collapse: the control is the bare 12×12 box."
378
378
  }
379
379
  ],
380
380
  "events": [
@@ -478,7 +478,7 @@
478
478
  },
479
479
  {
480
480
  "name": "vf-container",
481
- "description": "`<vf-container>` — a box that is nothing but its declared size.\n\nThe kit's positioned-placement story (src/position.ts) ends with one line of\nCSS it can't write for you: children placed with `top`/`left` need a\npositioned ancestor, and while every kit container is one — a window body, a\nstack, a fieldset — a region of *your own* needs `position: relative` in a\nstylesheet. This component is that region as an element: declare `width` and\n`height` in whole system px, slot anything into it, place children against\nits origin. A DITL's enclosing rectangle, with nothing drawn in it.\n\n```html\n<vf-container width=\"200\" height=\"120\">\n <vf-icon label=\"System\" width=\"64\" top=\"8\" left=\"12\">…</vf-icon>\n <vf-icon label=\"Finder\" width=\"64\" top=\"8\" left=\"104\">…</vf-icon>\n</vf-container>\n```\n\nThe rectangle is the whole API — `width`/`height` here, plus the `top`/`left`\npair nearly every component takes (VfPositioned), so a container is\nitself placeable: inside a window, a desktop, or another container, at whole\nsystem px that keep its box on the device-pixel grid by construction.\n\n**It is not a `vf-stack`.** The stack is a flexbox with opinions — it\ndistributes children along an axis, compiles `fill-width`/`fill-height` into\nflex, defaults a cross-axis alignment. This box has no layout opinion at\nall: in-flow children get normal flow, placed children get a coordinate\nsystem, and that is the whole API. Reach for it when the stack's opinions\nare the thing in the way — a field of placed icons, a fixed stage for\nabsolutely-positioned art, a consumer's own composition that brings its\nlayout with it.\n\n**The declared size is the layout.** `width`/`height` land on the host as a\nlive `calc(var(--vf-scale, 1) * Npx)` (VfSized), so the box scales\nwith the display and sits on the device-pixel grid by construction. Content\nthat outgrows the box overflows it rather than growing it — the number is\nthe layout, and content that doesn't fit is a number to raise. Leave a\ndimension off and that axis shrink-wraps: `fit-content`, not the parent's\nwidth, because a layout box that silently claimed a size nobody declared\nwould be inventing one (the `vf-stack` rule, held here too).\n\n**It paints nothing and means nothing** — unless `pattern` or `rule` say\nwhat to paint. No role, keyboard behavior or selection; what it holds\ndecides what it is.\n\n**`rule` draws the 1px rule on the edges it names** — `rule=\"bottom\"` is\nthe menu bar's anatomy (the box's rows over one row of ink), `rule=\"top\"`\na status strip's, all four a framed box. The rule is the box's own border\n(vfRule), inside the declared size, so a 24px `rule=\"bottom\"`\nstrip is 23 rows of box over the line; content, `fill-width` children and\nplaced children begin inside it, as a rectangle's interior begins inside\nFrameRect's line.\n\n**`pattern` fills the box with a 1-bit pattern**: one of the 38 standard\nMacPaint patterns by name (`pattern=\"bricks\"`, `pattern=\"gray-50\"` —\ndocs/PATTERNS.md has the table), or sixteen hex digits stating a custom\n8×8 pattern row by row, the way a PAT resource did. It is painted as the\nbox's own background — black ink on a `--vf-white` ground, anchored at\nthe box's top-left corner, under the content — by the same repeating tile\nas the desktop dither, so it is 1-bit at every density and zoom and a box\nof any size, declared or not, costs nothing more (src/pattern-fill.ts).\nUnder forced colors the pattern goes flat Canvas.\n\n**It holds its box on the device-pixel grid** — with a `GridSnapController`.\nA container's box is itself the consumer's coordinate system, including for\nnon-`vf` content that cannot correct itself, so the box is the thing to\nhold on the grid. The shadow box below owns the `position: relative` anchor\nand the `vf-snap` class together, so the correction\nmoves the whole coordinate system — everything placed against it rides\nalong instead of being re-corrected child by child. (`vf-stack` shipped\nwithout a controller on the theory that slotted `vf-*` children correct\ntheir own origins; this component is where that theory's gap — consumer\ncontent — became visible, and the stack has since adopted the same\narrangement.)\n\nLike the stack it is **typographically transparent**: `vfBase`'s chrome\ndress is returned to `inherit` on the host, so wrapping content in a sized\nbox changes nothing about how that content reads.\n\n`fill-width` / `fill-height` work here the way they do everywhere: read\nabout the host (be as big as *its* parent allows), and compiled for slotted\nchildren — `width: 100%` in normal flow, so a child filling the cross of a\ndeclared box needs no stylesheet. A height fill needs a declared `height`\nto resolve against; with none it is inert, not an error.\n---\n\n\n### **Slots:**\n - _default_ - The content. In flow by default; `top`/`left` on a kit child places it against this box's origin. `fill-width` / `fill-height` on a child fills it to the declared box.",
481
+ "description": "`<vf-container>` — a box that is nothing but its declared size.\n\nThe kit's positioned-placement story (src/position.ts) ends with one line of\nCSS it can't write for you: children placed with `top`/`left` need a\npositioned ancestor, and while every kit container is one — a window body, a\nstack, a fieldset — a region of *your own* needs `position: relative` in a\nstylesheet. This component is that region as an element: declare `width` and\n`height` in whole system px, slot anything into it, place children against\nits origin. A DITL's enclosing rectangle, with nothing drawn in it.\n\n```html\n<vf-container width=\"200\" height=\"120\">\n <vf-icon label=\"System\" width=\"64\" top=\"8\" left=\"12\">…</vf-icon>\n <vf-icon label=\"Finder\" width=\"64\" top=\"8\" left=\"104\">…</vf-icon>\n</vf-container>\n```\n\nThe rectangle is the whole API — `width`/`height` here, plus the `top`/`left`\npair nearly every component takes (VfPositioned), so a container is\nitself placeable: inside a window, a desktop, or another container, at whole\nsystem px that keep its box on the device-pixel grid by construction.\n\n**It is not a `vf-stack`.** The stack is a flexbox with opinions — it\ndistributes children along an axis, compiles `fill-width`/`fill-height` into\nflex, defaults a cross-axis alignment. This box has no layout opinion at\nall: in-flow children get normal flow, placed children get a coordinate\nsystem, and that is the whole API. Reach for it when the stack's opinions\nare the thing in the way — a field of placed icons, a fixed stage for\nabsolutely-positioned art, a consumer's own composition that brings its\nlayout with it.\n\n**The declared size is the layout.** `width`/`height` land on the host as a\nlive `calc(var(--vf-scale, 1) * Npx)` (VfSized), so the box scales\nwith the display and sits on the device-pixel grid by construction. Content\nthat outgrows the box overflows it rather than growing it — the number is\nthe layout, and content that doesn't fit is a number to raise. Leave a\ndimension off and that axis shrink-wraps: `fit-content`, not the parent's\nwidth, because a layout box that silently claimed a size nobody declared\nwould be inventing one (the `vf-stack` rule, held here too).\n\n**It paints nothing and means nothing** — unless `pattern` or `rule` say\nwhat to paint. No role, keyboard behavior or selection; what it holds\ndecides what it is. A page that gives it a role and a `tabindex` — a\npattern chooser's cells as radios — gets the kit's keyboard focus mark\nrather than the browser's ring: the dashed rule below the box.\n\n**`rule` draws the 1px rule on the edges it names** — `rule=\"bottom\"` is\nthe menu bar's anatomy (the box's rows over one row of ink), `rule=\"top\"`\na status strip's, all four a framed box. The rule is drawn inside the\ndeclared size (vfRule), so a 24px `rule=\"bottom\"` strip is 23 rows\nof box over the line; content, `fill-width` children and placed children\nbegin inside it, as a rectangle's interior begins inside FrameRect's line.\n\n**`pattern` fills the box with a 1-bit pattern**: one of the 38 standard\nMacPaint patterns by name (`pattern=\"bricks\"`, `pattern=\"gray-50\"` —\ndocs/PATTERNS.md has the table), or sixteen hex digits stating a custom\n8×8 pattern row by row, the way a PAT resource did. It is painted as the\nbox's own background — black ink on a `--vf-white` ground, anchored at\nthe box's top-left corner, under the content — by the same repeating tile\nas the desktop dither, so it is 1-bit at every density and zoom and a box\nof any size, declared or not, costs nothing more (src/pattern-fill.ts).\nUnder forced colors the pattern goes flat Canvas.\n\n**It holds its box on the device-pixel grid** — with a `GridSnapController`.\nA container's box is itself the consumer's coordinate system, including for\nnon-`vf` content that cannot correct itself, so the box is the thing to\nhold on the grid. The correction lands on the shadow box below, and the\ncoordinate system sits inside it, so the correction moves the whole\ncoordinate system — everything placed against it rides along instead of\nbeing re-corrected child by child. (`vf-stack` shipped\nwithout a controller on the theory that slotted `vf-*` children correct\ntheir own origins; this component is where that theory's gap — consumer\ncontent — became visible, and the stack has since adopted the same\narrangement.)\n\nLike the stack it is **typographically transparent**: `vfBase`'s chrome\ndress is returned to `inherit` on the host, so wrapping content in a sized\nbox changes nothing about how that content reads.\n\n`fill-width` / `fill-height` work here the way they do everywhere: read\nabout the host (be as big as *its* parent allows), and compiled for slotted\nchildren — `width: 100%` in normal flow, so a child filling the cross of a\ndeclared box needs no stylesheet. A height fill needs a declared `height`\nto resolve against; with none it is inert, not an error.\n---\n\n\n### **Slots:**\n - _default_ - The content. In flow by default; `top`/`left` on a kit child places it against this box's origin. `fill-width` / `fill-height` on a child fills it to the declared box.",
482
482
  "doc-url": "",
483
483
  "attributes": [
484
484
  {
@@ -488,7 +488,7 @@
488
488
  },
489
489
  {
490
490
  "name": "rule",
491
- "description": "The 1px rule on the box's edges: edge names separated by spaces —\n`\"bottom\"`, `\"top bottom\"`, up to all four in any order. Drawn as the\nbox's own border inside the declared size, in `--vf-black`, scaled with\nthe display like every kit frame's border; content and placed children\nbegin inside it.\nUnset, no rule; a value naming anything but an edge draws none and\nwarns once.",
491
+ "description": "The 1px rule on the box's edges: edge names separated by spaces —\n`\"bottom\"`, `\"top bottom\"`, up to all four in any order. Drawn inside\nthe declared size, in `--vf-black`, scaled with the display like every\nkit frame; content and placed children begin inside it.\nUnset, no rule; a value naming anything but an edge draws none and\nwarns once.",
492
492
  "value": { "type": "string | null | undefined" }
493
493
  },
494
494
  {
@@ -538,7 +538,7 @@
538
538
  },
539
539
  {
540
540
  "name": "rule",
541
- "description": "The 1px rule on the box's edges: edge names separated by spaces —\n`\"bottom\"`, `\"top bottom\"`, up to all four in any order. Drawn as the\nbox's own border inside the declared size, in `--vf-black`, scaled with\nthe display like every kit frame's border; content and placed children\nbegin inside it.\nUnset, no rule; a value naming anything but an edge draws none and\nwarns once.",
541
+ "description": "The 1px rule on the box's edges: edge names separated by spaces —\n`\"bottom\"`, `\"top bottom\"`, up to all four in any order. Drawn inside\nthe declared size, in `--vf-black`, scaled with the display like every\nkit frame; content and placed children begin inside it.\nUnset, no rule; a value naming anything but an edge draws none and\nwarns once.",
542
542
  "type": "string | null | undefined"
543
543
  },
544
544
  {
@@ -577,7 +577,7 @@
577
577
  },
578
578
  {
579
579
  "name": "vf-desktop",
580
- "description": "`<vf-desktop>` — the full-bleed classic desktop container.\n\nRenders the desktop pattern — the classic 50% dither by default, or any of\nthe standard patterns by name (`pattern`, System 7's General Controls\nsetting) — and manages the stacking order and `active` state of slotted\n`vf-window` children: a `pointerdown` or\n`focusin` (keyboard focus) anywhere inside a window brings it to the front\nand makes it the single active window. The windows' light-DOM order is kept\nin step with the stacking order (bottom-most first, synced in a task once\nany pointer gesture has ended), so tabbing walks the stack the way the eye\ndoes and Shift+Tab is its exact mirror.\n\nUtility windows (`vf-window[variant=\"utility\"]`) stack in a floating tier\nabove every document-tier window, restack only among themselves, and stand\noutside the single-active invariant entirely — clicking a palette neither\ndeactivates the active document window nor greys the palette, exactly as\nSystem 7's floating windoids behaved while their application was frontmost.\nA slotted `vf-menu-bar` (or a free-standing `vf-menu`) sits on a tier\nabove both, so its dropped menus cover palettes and document windows\nalike; only the screen-corner mask is in front of it.\n\n**Deactivation.** On a real System 7 machine clicking the desktop clicked\nthe *Finder* — the frontmost application's windows lost their stripes.\nclearActive is that gesture's handler: it clears `active` from\nthe whole document tier, and **zero active windows is a legal state**,\nheld until a press or keyboard focus re-enters a document window (or a\nnew one is slotted, which activates it — opening a window brings its\napplication forward). The desktop never takes this decision itself: its\nfurniture is slotted light DOM (an icon layer, say), so only the page\nknows which of its children — or which presses on the bare dither — mean\n\"the Finder\", and it routes those through `clearActive()`. Left alone,\nthe classic always-one-active behavior is unchanged. activeWindow\nreads the current holder, and every change of holder — including to and\nfrom none — fires `vf-activate`.\n\nThe desktop is a raster with an explicit size, always: **`width` and\n`height`**, in system px, the way a WIND resource declared a window's —\nthe host box renders at the declared screen plus `2 × bezel` per axis, a\nwhole number of system pixels by construction (default 512×342, the\ncompact Mac's screen). Pure CSS sizing is not supported; the page sets\nthe numbers — directly, or via VfDesktop.fitWithin on\n`resize`/`onScaleChange` for a viewport-filling desktop — and positions\nthe sized box with its own stylesheet, keeping any sub-system-pixel\nslack on its side. `bezel` (system px) draws the black screen surround —\nthe CRT's unlit margin — around the screen, rounding its four corners\nwith the classic corner mask.\n\n**`pattern`** names the desktop pattern — `gray-50` (the dither) by\ndefault, any of the 38 standard patterns (docs/PATTERNS.md), or sixteen\nhex digits stating a custom 8×8 pattern, as on `vf-container`. It is\npainted as the screen's own background: black ink on an opaque white\npaper, a repeating tile drawn at the display's resolution, 1-bit at every\ndensity and zoom (src/pattern-fill.ts).\n\n**The drag surface.** The Finder dragged an icon as a dotted outline drawn\non the *screen*, clipped at its edge and phase-locked to its raster, so\nthe screen hosts the layer that outline draws on: a full-bleed child of\nthe screen, `pointer-events: none` (never a hit for the page's\n`elementsFromPoint`), whose children paint one tier above the menu bar\nand under the corner mask — the layer itself is deliberately no stacking\ncontext, since a blend inside one would composite against nothing. An\nicon reaches it without an import, the menu-handshake idiom: on a drag's\nfirst step it dispatches `vf-drag-surface-request` (bubbles, non-composed,\n`detail.surface` null), and the nearest desktop on its light-DOM path\nfills the detail with the layer. A window asks the same way and draws\nthere with the same pen: its zoom rects when it opens from a rect\n(`vf-window.show({ from })`), its outline under an `outline-drag`. Not the\ntop layer: stable Safari cannot\nblend an element there against the page (src/cursor.ts), and a second\nkit entry in the top layer would need a re-promotion handshake.\n\nCustom properties:\n- `--vf-desktop-pattern` — a consumer's own tile art in place of the\n pattern (the kit's default is a 1-bit 50% checker, opaque\n black-on-white on a 30-system-px tile). Set, it wins over `pattern` and\n renders as a placed tile grid at that same 30-px geometry\n (src/tile-grid.ts); a token swapped at runtime without touching the\n component wants a `requestUpdate()`.\n- `--vf-desktop` — base color painted *under* the pattern (default\n `#808080`). The pattern's paper is opaque, so this only becomes visible\n when `--vf-desktop-pattern` is overridden with a tile that has\n transparent cells (or with `none`).\n---\n\n\n### **Events:**\n - **vf-activate** - The active document-tier window changed. Detail `{ window: HTMLElement | null }` — the new holder, or `null` when the document tier deactivated (a {@link clearActive} call, or the active window leaving the DOM with none behind it). Fired once per change of holder, never for a re-assertion of the same one.\n\n### **Slots:**\n - _default_ - Default slot: menu bar, windows, anything.\n\n### **CSS Properties:**\n - **--vf-desktop** - base color under the desktop pattern — occluded by the pattern's opaque paper, so it only shows through a custom `--vf-desktop-pattern` _(default: #808080)_\n- **--vf-desktop-pattern** - a consumer's own desktop tile, in place of `pattern` — the kit's default is the 50% checker drawn as opaque black-on-white rects on a 30-system-px tile. Override the whole tile; consumer art renders as a placed tile grid at that same geometry (raster art magnifies nearest-neighbor, the `vf-img` idiom) _(default: undefined)_\n\n### **CSS Parts:**\n - **desktop** - The patterned screen surface — the whole-system-px raster (inset by `bezel` when one is set).",
580
+ "description": "`<vf-desktop>` — the full-bleed classic desktop container.\n\nRenders the desktop pattern — the classic 50% dither by default, or any of\nthe standard patterns by name (`pattern`, System 7's General Controls\nsetting) — and manages the stacking order and `active` state of slotted\n`vf-window` children: a `pointerdown` or\n`focusin` (keyboard focus) anywhere inside a window brings it to the front\nand makes it the single active window. The windows' light-DOM order is kept\nin step with the stacking order (bottom-most first, synced in a task once\nany pointer gesture has ended), so tabbing walks the stack the way the eye\ndoes and Shift+Tab is its exact mirror.\n\nUtility windows (`vf-window[variant=\"utility\"]`) stack in a floating tier\nabove every document-tier window, restack only among themselves, and stand\noutside the single-active invariant entirely — clicking a palette neither\ndeactivates the active document window nor greys the palette, exactly as\nSystem 7's floating windoids behaved while their application was frontmost.\nA slotted `vf-menu-bar` (or a free-standing `vf-menu`) sits on a tier\nabove both, so its dropped menus cover palettes and document windows\nalike; only the screen-corner mask is in front of it.\n\n**Deactivation.** On a real System 7 machine clicking the desktop clicked\nthe *Finder* — the frontmost application's windows lost their stripes.\nclearActive is that gesture's handler: it clears `active` from\nthe whole document tier, and **zero active windows is a legal state**,\nheld until a press or keyboard focus re-enters a document window (or a\nnew one is slotted, which activates it — opening a window brings its\napplication forward). The desktop never takes this decision itself: its\nfurniture is slotted light DOM (an icon layer, say), so only the page\nknows which of its children — or which presses on the bare dither — mean\n\"the Finder\", and it routes those through `clearActive()`. Left alone,\nthe classic always-one-active behavior is unchanged. activeWindow\nreads the current holder, and every change of holder — including to and\nfrom none — fires `vf-activate`.\n\n**Hidden windows.** A window with `hidden` — closed by a page that hides\nits windows rather than removing them, through `vf-window.hide()` or the\nattribute itself — never holds the active state. One slotted hidden waits\nto be shown; `bringToFront()` on one gives it its place in the stack and\nactivates nothing; the holder hiding hands the state to the topmost shown\ndocument window, or to none. A window shown into a tier where none is\nactive, unless the tier was deliberately deactivated, takes it.\nstackingOrder lists the windows as they stand, bottom-most first.\n\n**The work area.** A slotted `vf-menu-bar` along the top takes its band\noff the screen: workArea is what is left, and the gestures on the\nscreen stay in it — a window dragged up stops with its title bar under the\nbar, where it can still be grabbed, and an icon dropped, nudged or walked\non the desktop lands below the bar. `window-top` deepens the area for\nwindows alone (windowArea), for a page with a strip of its own\nunder the bar. A gesture asks for the box it is clamped into with\n`vf-placement-bounds-request` (bubbles, non-composed), the drag surface's\nhandshake, and the desktop answers for the hosts placed on its screen.\n\nThe desktop is a raster with an explicit size, always: **`width` and\n`height`**, in system px, the way a WIND resource declared a window's —\nthe host box renders at the declared screen plus `2 × bezel` per axis, a\nwhole number of system pixels by construction (default 512×342, the\ncompact Mac's screen). Pure CSS sizing is not supported; the page sets\nthe numbers — directly, or via VfDesktop.fitWithin on\n`resize`/`onScaleChange` for a viewport-filling desktop — and positions\nthe sized box with its own stylesheet, keeping any sub-system-pixel\nslack on its side. `bezel` (system px) draws the black screen surround —\nthe CRT's unlit margin — around the screen, rounding its four corners\nwith the classic corner mask.\n\n**`pattern`** names the desktop pattern — `gray-50` (the dither) by\ndefault, any of the 38 standard patterns (docs/PATTERNS.md), or sixteen\nhex digits stating a custom 8×8 pattern, as on `vf-container`. It is\npainted as the screen's own background: black ink on an opaque white\npaper, a repeating tile drawn at the display's resolution, 1-bit at every\ndensity and zoom (src/pattern-fill.ts).\n\n**The drag surface.** The Finder dragged an icon as a dotted outline drawn\non the *screen*, clipped at its edge and phase-locked to its raster, so\nthe screen hosts the layer that outline draws on: a full-bleed child of\nthe screen, `pointer-events: none` (never a hit for the page's\n`elementsFromPoint`), whose children paint one tier above the menu bar\nand under the corner mask — the layer itself is deliberately no stacking\ncontext, since a blend inside one would composite against nothing. An\nicon reaches it without an import, the menu-handshake idiom: on a drag's\nfirst step it dispatches `vf-drag-surface-request` (bubbles, non-composed,\n`detail.surface` null), and the nearest desktop on its light-DOM path\nfills the detail with the layer. A window asks the same way and draws\nthere with the same pen: its zoom rects when it opens from a rect\n(`vf-window.show({ from })`), its outline under an `outline-drag`. Not the\ntop layer: stable Safari cannot\nblend an element there against the page (src/cursor.ts), and a second\nkit entry in the top layer would need a re-promotion handshake.\n\nCustom properties:\n- `--vf-desktop-pattern` — a consumer's own tile art in place of the\n pattern (the kit's default is a 1-bit 50% checker, opaque\n black-on-white on a 30-system-px tile). Set, it wins over `pattern` and\n renders as a placed tile grid at that same 30-px geometry\n (src/tile-grid.ts); a token swapped at runtime without touching the\n component wants a `requestUpdate()`.\n- `--vf-desktop` — base color painted *under* the pattern (default\n `#808080`). The pattern's paper is opaque, so this only becomes visible\n when `--vf-desktop-pattern` is overridden with a tile that has\n transparent cells (or with `none`).\n---\n\n\n### **Events:**\n - **vf-activate** - The active document-tier window changed. Detail `{ window: HTMLElement | null }` — the new holder, or `null` when the document tier deactivated (a {@link clearActive} call, or the active window leaving the DOM or hiding with no shown window behind it). Fired once per change of holder, never for a re-assertion of the same one.\n\n### **Slots:**\n - _default_ - Default slot: menu bar, windows, anything.\n\n### **CSS Properties:**\n - **--vf-desktop** - base color under the desktop pattern — occluded by the pattern's opaque paper, so it only shows through a custom `--vf-desktop-pattern` _(default: #808080)_\n- **--vf-desktop-pattern** - a consumer's own desktop tile, in place of `pattern` — the kit's default is the 50% checker drawn as opaque black-on-white rects on a 30-system-px tile. Override the whole tile; consumer art renders as a placed tile grid at that same geometry (raster art magnifies nearest-neighbor, the `vf-img` idiom) _(default: undefined)_\n\n### **CSS Parts:**\n - **desktop** - The patterned screen surface — the whole-system-px raster (inset by `bezel` when one is set).",
581
581
  "doc-url": "",
582
582
  "attributes": [
583
583
  {
@@ -603,6 +603,11 @@
603
603
  "default": "DEFAULT_PATTERN"
604
604
  }
605
605
  },
606
+ {
607
+ "name": "window-top",
608
+ "description": "The least `top` a window may take, in system px from the screen's top —\nfor a page that keeps a strip of its own under the menu bar, over the\nwindows. A window dragged on this desktop stops there, and\nwindowArea starts there; icons still stop at the menu bar. Below\nthe bar's bottom it changes nothing. Unset, windows stop at the bar.",
609
+ "value": { "type": "number | null | undefined" }
610
+ },
606
611
  {
607
612
  "name": "top",
608
613
  "description": "Offset from the top of the positioning parent, in whole system px.\nSetting this (or `left`) absolutely positions the element within its\nparent; the coordinate left unset is 0. Remove both to return the\nelement to normal flow.",
@@ -633,7 +638,7 @@
633
638
  "events": [
634
639
  {
635
640
  "name": "vf-activate",
636
- "description": "The active document-tier window changed. Detail `{ window: HTMLElement | null }` — the new holder, or `null` when the document tier deactivated (a {@link clearActive} call, or the active window leaving the DOM with none behind it). Fired once per change of holder, never for a re-assertion of the same one."
641
+ "description": "The active document-tier window changed. Detail `{ window: HTMLElement | null }` — the new holder, or `null` when the document tier deactivated (a {@link clearActive} call, or the active window leaving the DOM or hiding with no shown window behind it). Fired once per change of holder, never for a re-assertion of the same one."
637
642
  }
638
643
  ],
639
644
  "js": {
@@ -658,11 +663,31 @@
658
663
  "description": "The desktop pattern — System 7's General Controls setting. A library\npattern by name (`gray-50`, the classic dither, by default; `gray-75`,\n`bricks`, … — docs/PATTERNS.md) or sixteen hex digits stating a custom\n8×8 pattern, as on `vf-container`. Painted black on opaque white over\nthe whole screen, 1-bit at every density and zoom. A\n`--vf-desktop-pattern` token override still wins and renders the\nconsumer's tile as a placed grid; an unrecognized value warns once and\nkeeps the dither.",
659
664
  "type": "string | null | undefined"
660
665
  },
666
+ {
667
+ "name": "windowTop",
668
+ "description": "The least `top` a window may take, in system px from the screen's top —\nfor a page that keeps a strip of its own under the menu bar, over the\nwindows. A window dragged on this desktop stops there, and\nwindowArea starts there; icons still stop at the menu bar. Below\nthe bar's bottom it changes nothing. Unset, windows stop at the bar.",
669
+ "type": "number | null | undefined"
670
+ },
671
+ {
672
+ "name": "workArea",
673
+ "description": "The screen less a slotted `vf-menu-bar` along its top edge, in system\npx from the screen's corner (the bezel excluded, as for\nplacementAt): `{ left, top, width, height }`. The desktop clamps\nthe gestures on its screen into it — an icon dropped, nudged or walked\non the desktop lands below the menu bar, where it can be grabbed again.\nWithout a bar it is the whole screen. Measured at the call.",
674
+ "type": "{ left: number; top: number; width: number; height: number }"
675
+ },
676
+ {
677
+ "name": "windowArea",
678
+ "description": "workArea, deepened to windowTop where that is lower: the\narea windows are dragged in. A window's title bar never goes above it.",
679
+ "type": "{ left: number; top: number; width: number; height: number }"
680
+ },
661
681
  {
662
682
  "name": "activeWindow",
663
- "description": "The active document-tier window, or null while the tier is deactivated\n(or has no windows). Utility windows are never the holder.",
683
+ "description": "The active document-tier window, or null while the tier is deactivated\n(or has no shown windows). Utility windows and hidden windows are never\nthe holder.",
664
684
  "type": "HTMLElement | null"
665
685
  },
686
+ {
687
+ "name": "stackingOrder",
688
+ "description": "The slotted windows in stacking order, bottom-most first: the document\ntier, then the floating tier above it, each in the order its windows\nwere last raised. Hidden windows are included where they stand. This is\nthe order the eye sees; the windows' light-DOM order catches up with it\nonly once a gesture ends, and a raise by keyboard focus moves no node.",
689
+ "type": "HTMLElement[]"
690
+ },
666
691
  {
667
692
  "name": "top",
668
693
  "description": "Offset from the top of the positioning parent, in whole system px.\nSetting this (or `left`) absolutely positions the element within its\nparent; the coordinate left unset is 0. Remove both to return the\nelement to normal flow.",
@@ -687,7 +712,7 @@
687
712
  "events": [
688
713
  {
689
714
  "name": "vf-activate",
690
- "description": "The active document-tier window changed. Detail `{ window: HTMLElement | null }` — the new holder, or `null` when the document tier deactivated (a {@link clearActive} call, or the active window leaving the DOM with none behind it). Fired once per change of holder, never for a re-assertion of the same one."
715
+ "description": "The active document-tier window changed. Detail `{ window: HTMLElement | null }` — the new holder, or `null` when the document tier deactivated (a {@link clearActive} call, or the active window leaving the DOM or hiding with no shown window behind it). Fired once per change of holder, never for a re-assertion of the same one."
691
716
  }
692
717
  ]
693
718
  }
@@ -1019,7 +1044,7 @@
1019
1044
  },
1020
1045
  {
1021
1046
  "name": "vf-icon-field",
1022
- "description": "`<vf-icon-field>` — the container a field of `vf-icon`s sits in: a desktop's\nicons, a folder window's contents.\n\nEvery other set in the kit has its container — `vf-list` owns\n`vf-list-item`, `vf-radio-group` owns `vf-radio`, `vf-menu` owns\n`vf-menu-item`, `vf-select` owns `vf-option` — and `vf-icon` was the one\nitem whose container the consumer wrote by hand: a bare\n`<div role=\"listbox\" aria-multiselectable=\"true\">`, because an `option` is\nonly valid inside a `listbox` that owns it, and every kit container is a\npositioning anchor by design, so nothing in the kit was neutral enough to\nstand in. A consumer who forgot the role got icons that silently degraded\nto pictures. This is that container, as kit furniture:\n\n```html\n<vf-desktop width=\"512\" height=\"342\">\n <vf-icon-field label=\"Desktop\" fill-width fill-height>\n <vf-icon label=\"Macintosh HD\" width=\"64\" selectable movable editable left=\"16\" top=\"24\">…</vf-icon>\n <vf-icon label=\"Trash\" width=\"64\" selectable movable editable left=\"16\" top=\"280\">…</vf-icon>\n </vf-icon-field>\n <vf-window heading=\"Documents\" width=\"320\" height=\"201\" scrollbars=\"both\" top=\"40\" left=\"120\">\n <vf-icon-field label=\"Documents\">\n <vf-icon label=\"Read Me\" width=\"64\" selectable movable editable left=\"16\" top=\"16\">…</vf-icon>\n </vf-icon-field>\n </vf-window>\n</vf-desktop>\n```\n\n### Semantics through internals\n\n`role=\"listbox\"` and `aria-multiselectable=\"true\"` always — the Finder was\nalways multi-select, so there is no attribute for it — and `label` as the\naccessible name, the way `vf-scroll-area` takes one. Internals values are\ndefaults (SPEC §2): a consumer's own `role`/`aria-*` on the tag still wins.\nA `selectable` icon inside becomes a real `option` carrying `aria-selected`;\n`vf-icon` matches this tag directly, since a role written through internals\nnever lands as an attribute for `closest()` to find.\n\n### Layout-neutral, exactly what the div was\n\nAn in-flow block with no size, no inset and no position of its own,\npainting nothing — the `vf-stack` posture. A field whose icons are all\nplaced is a zero-height block, so the icons keep anchoring to the desktop's\nraster or the window's plane, stored coordinates mean what they meant, and\na press on the bare dither still reaches the desktop. It takes `top`/`left`\nand `width`/`height` like the other declared-box containers, so a page that\nwants the field to be a box places and sizes it, at which point it becomes\nthe anchor — the placement working, as documented for everything.\n`fill-width`/`fill-height` are the other way to give it a box, read about\nthe host the way `vf-stack` and `vf-container` read them: a filled field\nstays in flow and static, so its icons keep their anchor, and it has a\nsurface to press — which is what the rubber band needs.\n\n### The rubber band\n\nA press on the field's own background — not on an icon — dragged across\nthe field draws the Finder's dotted selection rectangle from the press to\nthe pointer, and the selection follows it live by the Finder's one rule:\n**an icon is selected exactly when it was selected at the press XOR the\nrectangle touches it.** The press fixes that anchor: a plain press has\nalready cleared everything (the way any press outside an icon does), so\nthe rectangle simply selects what it touches and releases what it leaves;\nwith Shift or ⌘ held the selection survives the press and the rectangle\n*toggles* against it — an icon already selected deselects while the\nrectangle covers it and comes back when it leaves, one that was not\nselects. Each change reports `vf-select` as a press would. \"Touches\"\nmeans the icon's art cell or its name plate (VfIcon.touches), not\nthe empty cell beside them, so a rectangle through the gap between two\nicons selects neither. The release keeps the result; Escape or a\n`pointercancel` cancels, the rectangle vanishes and the selection goes\nback to the anchor. A press that never leaves its system pixel draws\nnothing.\n\nThe rectangle is drawn with the drag outline's pen (* paintSelectionRect: the dotted one-pixel outline, `filter: invert(1)`\nunder `mix-blend-mode: difference`) at the field's own level, which is\nwhere the Finder drew its marquee — on the desktop under the windows, in a\nwindow body over that window's content and under any window above it —\npositioned against the viewport from the field's own shadow, since a\nlayout-neutral field has no box of its own to anchor to. It reaches no\nfurther than the field, inside every clip above the field (a window body,\na scroll viewport, the raster's edge), so it never paints outside the\nregion the icons are visible in. Its dots take the pen's phase on the\n*screen* — the desktop's, found by the `vf-drag-surface-request`\nhandshake the drag outline uses (penPhase) — so over the desktop\ndither the rectangle reads as a black line wherever the field sits; with\nno desktop, the field's own box is the reference.\n\nOnly a field with a box can be pressed: fill it, or place and size it. An\nunplaced, unfilled field of placed icons is zero-height and draws no band.\n`touch-action` is left alone, so on a touch screen a drag on the\nbackground pans a scrolling window as it always did; the band is a mouse\nand pen gesture.\n\n### The walk\n\nThe Finder's Clean Up moved a container's icons one at a time, each\nicon's dotted outline travelling to its cell and the icon landing when\nthe outline arrived. dragIcons is that walk: `{ icon, left, top }`\nmoves in the page's order — which icon goes first is a statement about\nthe page's lattice, and the kit ships none — each through the icon's own\n`dragTo`, with a beat (`WALK_BEAT_MS`, src/motion.ts) after every landing\nthat showed. It resolves when the last icon has landed. One walk per\nfield: a second call finishes the first. A press anywhere, or Escape,\nfinishes it too — every icon still to go lands at its target at once, the\nFinder never made you wait — and so does the field leaving the DOM; an\nicon gone from the DOM by its turn is skipped. Under\n`prefers-reduced-motion` every icon lands at once, no outline, no beat.\n\n### `size` is the view's\n\n`large` or `small`, written onto every icon in the field when set and\nwhenever it changes, so View → by Small Icon is one attribute instead of a\nloop over every icon. Unset, each icon keeps its own.\n\n### The desktop uses it, and renders none\n\nA desktop's icons sit in a field slotted into `vf-desktop` beside the\nwindows, written by the page; a folder window's icons sit in one slotted\ninto the window body. `vf-desktop` builds no field of its own: its furniture\nis slotted light DOM and the page decides what it is, a desktop with no\nicons should carry no empty listbox, and a field inside the desktop's\nshadow is one `closest()` could not reach.\n---\n\n\n### **Slots:**\n - _default_ - The icons.",
1047
+ "description": "`<vf-icon-field>` — the container a field of `vf-icon`s sits in: a desktop's\nicons, a folder window's contents.\n\nEvery other set in the kit has its container — `vf-list` owns\n`vf-list-item`, `vf-radio-group` owns `vf-radio`, `vf-menu` owns\n`vf-menu-item`, `vf-select` owns `vf-option` — and `vf-icon` was the one\nitem whose container the consumer wrote by hand: a bare\n`<div role=\"listbox\" aria-multiselectable=\"true\">`, because an `option` is\nonly valid inside a `listbox` that owns it, and every kit container is a\npositioning anchor by design, so nothing in the kit was neutral enough to\nstand in. A consumer who forgot the role got icons that silently degraded\nto pictures. This is that container, as kit furniture:\n\n```html\n<vf-desktop width=\"512\" height=\"342\">\n <vf-icon-field label=\"Desktop\" fill-width fill-height>\n <vf-icon label=\"Macintosh HD\" width=\"64\" selectable movable editable left=\"16\" top=\"24\">…</vf-icon>\n <vf-icon label=\"Trash\" width=\"64\" selectable movable editable left=\"16\" top=\"280\">…</vf-icon>\n </vf-icon-field>\n <vf-window heading=\"Documents\" width=\"320\" height=\"201\" scrollbars=\"both\" top=\"40\" left=\"120\">\n <vf-icon-field label=\"Documents\">\n <vf-icon label=\"Read Me\" width=\"64\" selectable movable editable left=\"16\" top=\"16\">…</vf-icon>\n </vf-icon-field>\n </vf-window>\n</vf-desktop>\n```\n\n### Semantics through internals\n\n`role=\"listbox\"` and `aria-multiselectable=\"true\"` always — the Finder was\nalways multi-select, so there is no attribute for it — and `label` as the\naccessible name, the way `vf-scroll-area` takes one. Internals values are\ndefaults (SPEC §2): a consumer's own `role`/`aria-*` on the tag still wins.\nA `selectable` icon inside becomes a real `option` carrying `aria-selected`;\n`vf-icon` matches this tag directly, since a role written through internals\nnever lands as an attribute for `closest()` to find.\n\n### Layout-neutral, exactly what the div was\n\nAn in-flow block with no size, no inset and no position of its own,\npainting nothing — the `vf-stack` posture. A field whose icons are all\nplaced is a zero-height block, so the icons keep anchoring to the desktop's\nraster or the window's plane, stored coordinates mean what they meant, and\na press on the bare dither still reaches the desktop. It takes `top`/`left`\nand `width`/`height` like the other declared-box containers, so a page that\nwants the field to be a box places and sizes it, at which point it becomes\nthe anchor — the placement working, as documented for everything.\n`fill-width`/`fill-height` are the other way to give it a box, read about\nthe host the way `vf-stack` and `vf-container` read them: a filled field\nstays in flow and static, so its icons keep their anchor, and it has a\nsurface to press — which is what the rubber band needs.\n\n### The rubber band\n\nA press on the field's own background — not on an icon — dragged across\nthe field draws the Finder's dotted selection rectangle from the press to\nthe pointer, and the selection follows it live by the Finder's one rule:\n**an icon is selected exactly when it was selected at the press XOR the\nrectangle touches it.** The press fixes that anchor: a plain press has\nalready cleared everything (a press on a field's background does), so\nthe rectangle simply selects what it touches and releases what it leaves;\nwith Shift or ⌘ held the selection survives the press and the rectangle\n*toggles* against it — an icon already selected deselects while the\nrectangle covers it and comes back when it leaves, one that was not\nselects. Each change reports `vf-select` as a press would. \"Touches\"\nmeans the icon's art cell or its name plate (VfIcon.touches), not\nthe empty cell beside them, so a rectangle through the gap between two\nicons selects neither. The release keeps the result; Escape or a\n`pointercancel` cancels, the rectangle vanishes and the selection goes\nback to the anchor. A press that never leaves its system pixel draws\nnothing.\n\nThe rectangle is drawn with the drag outline's pen (* paintSelectionRect: the dotted one-pixel outline, `filter: invert(1)`\nunder `mix-blend-mode: difference`) at the field's own level, which is\nwhere the Finder drew its marquee — on the desktop under the windows, in a\nwindow body over that window's content and under any window above it —\npositioned against the viewport from the field's own shadow, since a\nlayout-neutral field has no box of its own to anchor to. It reaches no\nfurther than the field, inside every clip above the field (a window body,\na scroll viewport, the raster's edge), so it never paints outside the\nregion the icons are visible in. Its dots take the pen's phase on the\n*screen* — the desktop's, found by the `vf-drag-surface-request`\nhandshake the drag outline uses (penPhase) — so over the desktop\ndither the rectangle reads as a black line wherever the field sits; with\nno desktop, the field's own box is the reference.\n\nOnly a field with a box can be pressed: fill it, or place and size it. An\nunplaced, unfilled field of placed icons is zero-height and draws no band.\n`touch-action` is left alone, so on a touch screen a drag on the\nbackground pans a scrolling window as it always did; the band is a mouse\nand pen gesture.\n\n### The walk\n\nThe Finder's Clean Up moved a container's icons one at a time, each\nicon's dotted outline travelling to its cell and the icon landing when\nthe outline arrived. dragIcons is that walk: `{ icon, left, top }`\nmoves in the page's order — which icon goes first is a statement about\nthe page's lattice, and the kit ships none — each through the icon's own\n`dragTo`, with a beat (`WALK_BEAT_MS`, src/motion.ts) after every landing\nthat showed. It resolves when the last icon has landed. One walk per\nfield: a second call finishes the first. A press anywhere, or Escape,\nfinishes it too — every icon still to go lands at its target at once, the\nFinder never made you wait — and so does the field leaving the DOM; an\nicon gone from the DOM by its turn is skipped. Under\n`prefers-reduced-motion` every icon lands at once, no outline, no beat.\n\n### `size` is the view's\n\n`large` or `small`, written onto every icon in the field when set and\nwhenever it changes, so View → by Small Icon is one attribute instead of a\nloop over every icon. Unset, each icon keeps its own.\n\n### The desktop uses it, and renders none\n\nA desktop's icons sit in a field slotted into `vf-desktop` beside the\nwindows, written by the page; a folder window's icons sit in one slotted\ninto the window body. `vf-desktop` builds no field of its own: its furniture\nis slotted light DOM and the page decides what it is, a desktop with no\nicons should carry no empty listbox, and a field inside the desktop's\nshadow is one `closest()` could not reach.\n---\n\n\n### **Slots:**\n - _default_ - The icons.",
1023
1048
  "doc-url": "",
1024
1049
  "attributes": [
1025
1050
  {
@@ -1751,7 +1776,7 @@
1751
1776
  },
1752
1777
  {
1753
1778
  "name": "vf-menu-bar",
1754
- "description": "`<vf-menu-bar>` — the System 7 menu bar: white strip, 1px black bottom\nrule, slotted `<vf-menu>` children laid out from the left. `rounded` adds\nthe classic screen-corner mask to the top corners.\n\nCoordinates its menus: pressing a label opens that menu (and inverts the\nlabel); while any menu is open, hovering another label switches to it;\nEscape, an outside click, or item selection closes. ArrowLeft/ArrowRight\nmove between menus while one is open; ArrowDown/ArrowUp move focus through\nthe open menu's items, Home/End jump to its first/last, and typed letters\nrun the shared Finder first-letter type-ahead (src/type-ahead.ts).\n\nThe bar also owns the **press-drag-release** gesture (see src/menu-press.ts)\n— press a title, slide onto a command, release over it — because one press\nmay travel across several of its menus. `vf-select` drives its popup by the\nsame mechanic.\n---\n\n\n### **Slots:**\n - _default_ - `vf-menu` elements.\n\n### **CSS Properties:**\n - **--vf-menubar-height** - `vf-menu-bar` _(default: 20px)_\n\n### **CSS Parts:**\n - **bar** - The horizontal layout container.",
1779
+ "description": "`<vf-menu-bar>` — the System 7 menu bar: white strip, 1px black bottom\nrule, slotted `<vf-menu>` children laid out from the left. `rounded` adds\nthe classic screen-corner mask to the top corners.\n\nCoordinates its menus: pressing a label opens that menu (and inverts the\nlabel); while any menu is open, hovering another label switches to it;\nEscape, an outside click, or item selection closes. ArrowLeft/ArrowRight\nmove between menus while one is open; ArrowDown/ArrowUp move focus through\nthe open menu's items, Home/End jump to its first/last, and typed letters\nrun the shared Finder first-letter type-ahead (src/type-ahead.ts).\n\nThe bar also owns the **press-drag-release** gesture (see src/menu-press.ts)\n— press a title, slide onto a command, release over it — because one press\nmay travel across several of its menus. `vf-select` drives its popup by the\nsame mechanic.\n---\n\n\n### **Slots:**\n - _default_ - `vf-menu` elements.\n- **end** - The bar's right end: a clock, say. Held 9px in from the end, and a `vf-label` there rides the bar's line, so its baseline is the menu titles'.\n\n### **CSS Properties:**\n - **--vf-menubar-height** - `vf-menu-bar` _(default: 20px)_\n\n### **CSS Parts:**\n - **bar** - The horizontal layout container.",
1755
1780
  "doc-url": "",
1756
1781
  "attributes": [
1757
1782
  {
@@ -1790,7 +1815,13 @@
1790
1815
  "value": { "type": "PlacementOrigin | null | undefined" }
1791
1816
  }
1792
1817
  ],
1793
- "slots": [{ "name": "", "description": "`vf-menu` elements." }],
1818
+ "slots": [
1819
+ { "name": "", "description": "`vf-menu` elements." },
1820
+ {
1821
+ "name": "end",
1822
+ "description": "The bar's right end: a clock, say. Held 9px in from the end, and a `vf-label` there rides the bar's line, so its baseline is the menu titles'."
1823
+ }
1824
+ ],
1794
1825
  "events": [],
1795
1826
  "js": {
1796
1827
  "properties": [
@@ -3110,7 +3141,7 @@
3110
3141
  },
3111
3142
  {
3112
3143
  "name": "vf-separator",
3113
- "description": "`<vf-separator>` — a 1px System 7 rule.\n\nHorizontal by default (1px tall, full width); set the `vertical` attribute\nfor a 1px-wide vertical rule (give it a height, or let a flex parent\nstretch it).\n\nContainers may restyle it via custom properties:\n- `--vf-separator-color` — line color (default `var(--vf-black, #000)`).\n- `--vf-separator-style` — line style, e.g. `dotted` (default `solid`).\n `vf-menu` sets these so slotted separators render as the classic dimmed\n dotted menu rule (see Menus.png).\n---\n\n\n### **CSS Properties:**\n - **--vf-separator-color** - `vf-separator` rule color — `vf-menu` sets it to `--vf-disabled` for the dimmed menu rule _(default: undefined)_\n- **--vf-separator-style** - `vf-separator` rule style — `vf-menu` sets `dotted` (see `Menus.png`) _(default: solid)_",
3144
+ "description": "`<vf-separator>` — a 1px System 7 rule.\n\nHorizontal by default (1px tall, full width); set the `vertical` attribute\nfor a 1px-wide vertical rule (give it a height, or let a flex parent\nstretch it).\n\nContainers may restyle it via custom properties:\n- `--vf-separator-color` — line color (default `var(--vf-black, #000)`).\n- `--vf-separator-style` — `solid` (the default) or `dotted`, one system px\n on and one off. `vf-menu` sets these so slotted separators render as the\n classic dimmed dotted menu rule (see Menus.png).\n---\n\n\n### **CSS Properties:**\n - **--vf-separator-color** - `vf-separator` rule color — `vf-menu` sets it to `--vf-disabled` for the dimmed menu rule _(default: undefined)_\n- **--vf-separator-style** - `vf-separator` rule style: `solid` or `dotted` — `vf-menu` sets `dotted` (see `Menus.png`) _(default: solid)_",
3114
3145
  "doc-url": "",
3115
3146
  "attributes": [
3116
3147
  {
@@ -4222,6 +4253,11 @@
4222
4253
  "description": "See minWidth. Unbounded by default.",
4223
4254
  "type": "number | null | undefined"
4224
4255
  },
4256
+ {
4257
+ "name": "sizeLimits",
4258
+ "description": "The sizeRect as it applies, in whole system px: `min-width` and\n`min-height`, or the 80×54 floor where unset, and `max-width` and\n`max-height`, `Infinity` where unbounded — the range the grow box drags\nthe window in. A page that sizes the window itself, re-fitting it to a\nsmaller screen say, reads it to stay inside the same range.",
4259
+ "type": "{ minWidth: number; minHeight: number; maxWidth: number; maxHeight: number }"
4260
+ },
4225
4261
  {
4226
4262
  "name": "scrollbars",
4227
4263
  "description": "Put System 7 scroll rails on the window edge — the classic document\nwindow. The body slot renders inside a built-in `vf-scroll-area` pulled\none system pixel under the frame on every side, so the rails repaint the\nborder lines and a `resizable` window's grow box lands in the corner\ncell — reserved on a single-axis rail too (the area's `corner`), unless\na populated status strip holds the grow box, when the rail runs edge to\nedge onto the strip's rule. Values mirror `vf-scroll-area`'s `axis`; the\n`heading` names the scroll region; the viewport part is re-exported.\nContent runs to the frame and the rails; an inset is the content's own.\nThe slotted composition (SPEC §5 vf-scroll-area) still works for a well\nplaced inside the body.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vintage-frames",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "Lit web components that emulate the look and feel of classic Mac OS System 7",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -36,6 +36,10 @@
36
36
  "types": "./dist/components/vf-*.d.ts",
37
37
  "import": "./dist/components/vf-*.js"
38
38
  },
39
+ "./shell": {
40
+ "types": "./dist/shell/index.d.ts",
41
+ "import": "./dist/shell/index.js"
42
+ },
39
43
  "./package.json": "./package.json"
40
44
  },
41
45
  "files": [
@@ -108,7 +112,11 @@
108
112
  "verify:snap": "node scripts/verify-snap.mjs",
109
113
  "verify:contract": "node scripts/verify-contract.mjs",
110
114
  "verify:names": "node scripts/verify-names.mjs",
111
- "verify:forced-colors": "node scripts/verify-forced-colors.mjs"
115
+ "verify:forced-colors": "node scripts/verify-forced-colors.mjs",
116
+ "verify:shell-unit": "tsc -p tsconfig.unit.json && node --test --test-reporter=tap \"test/*.test.mjs\"",
117
+ "verify:shell-front": "node scripts/verify-shell-front.mjs",
118
+ "verify:shell-windows": "node scripts/verify-shell-windows.mjs",
119
+ "verify:shell-finder": "node scripts/verify-shell-finder.mjs"
112
120
  },
113
121
  "dependencies": {
114
122
  "lit": "^3.2.0"