pathland-core 0.2.0

Pathland 16-byte opcode protocol: fixed-size opcodes, ring buffer, arena, events, and linear-memory layout (no_std)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
//! Protocol constants: categories, commands, component types, value types, flags.
//!
//! These constants are part of the wire protocol (see `spec/OPCODE.md`) and MUST
//! NOT be renumbered once released. Component types were renumbered pre-release
//! to the grouped ranges in `spec/PRIMITIVES.md` (wire version stays 1).

/// Opcode categories (`Category` field, u8).
pub mod category {
    /// Tree mutations (guest → host): node create/delete/insert/remove/move.
    pub const TREE: u8 = 0x01;
    /// Parameters and design tokens (guest → host): the constraint properties
    /// (spacing, padding, alignment, …) and content that native renderers use
    /// to lay out and style native elements. The engine does NOT emit rects.
    pub const PARAMETER: u8 = 0x02;
    /// Raw input events (host → guest): pointer down/move/up, key down/up.
    pub const EVENT: u8 = 0x03;
    /// Control (both directions): reset, environment, custom data.
    pub const META: u8 = 0x04;
}

/// Commands within the `TREE` category.
pub mod tree {
    /// `A=nodeId, B=componentType (u16, low)`
    pub const CREATE_NODE: u8 = 0x01;
    /// `A=nodeId`
    pub const DELETE_NODE: u8 = 0x02;
    /// `A=parentId, B=childId, C=index` (append is `C = u32::MAX`, see [`crate::APPEND`])
    pub const INSERT_CHILD: u8 = 0x03;
    /// `A=parentId, B=childId`
    pub const REMOVE_CHILD: u8 = 0x04;
    /// `A=parentId, B=childId, C=newIndex` (append is `C = u32::MAX`, see [`crate::APPEND`])
    pub const MOVE_CHILD: u8 = 0x05;
}

/// Commands within the `PARAMETER` category.
pub mod parameter {
    /// `A=nodeId, B=(valueType << 16) | propertyId, C=value`
    pub const SET_PROPERTY: u8 = 0x01;
    /// `A=arenaRef (path), B=valueType (u8), C=value`
    pub const SET_DESIGN_TOKEN: u8 = 0x02;
    /// `A=nodeId, B=arenaRef (utf8)`
    pub const SET_TEXT: u8 = 0x03;
    /// **Draft.** `A=nodeId, B=days since epoch (I32), C=millis of day (U32)` —
    /// set a node's date value (e.g. a `DATE_PICKER`); see
    /// `spec/PRIMITIVES.md` / `spec/OPCODE.md`.
    pub const SET_DATE: u8 = 0x04;
    /// `A=nodeId, B=arenaRef (attributed payload)` — set a node's text plus
    /// range-scoped style runs and links (see [`crate::AttributedString`] and
    /// `spec/OPCODE.md`). The payload is binary; the text is its plain fallback.
    pub const SET_ATTRIBUTED_TEXT: u8 = 0x05;
}

/// Commands within the `EVENT` category.
///
/// Events are **raw inputs** (host → guest), each carrying a host-resolved
/// `targetId`. High-level interpretations (tap, drag, long-press) are built by
/// the guest/app from these raw inputs and are NOT part of the protocol.
pub mod event {
    /// `A=targetId, B=x (f32), C=y (f32)` (Flags `POINTER_SECONDARY`)
    pub const POINTER_DOWN: u8 = 0x01;
    /// `A=targetId, B=x (f32), C=y (f32)` (Flags `HOVER_ENTER` / `HOVER_LEAVE`)
    pub const POINTER_MOVE: u8 = 0x02;
    /// `A=targetId, B=x (f32), C=y (f32)` (Flags `POINTER_SECONDARY`)
    pub const POINTER_UP: u8 = 0x03;
    /// `A=targetId, B=keyCode (u16, low), C=modifiers (u8, low)` (Flags `KEY_REPEAT`)
    pub const KEY_DOWN: u8 = 0x04;
    /// `A=targetId, B=keyCode (u16, low), C=modifiers (u8, low)`
    pub const KEY_UP: u8 = 0x05;
    /// `A=targetId, B=value (f32)` — a control's value changed (host → guest).
    /// The renderer resolves the control's semantic value (e.g. a slider thumb
    /// dragged to a point on its track); the guest/app writes it into its state.
    pub const VALUE_CHANGED: u8 = 0x06;
    /// `A=targetId, B=string offset` — a text field's value changed (host →
    /// guest). The new text lives in the batch's string section, referenced by
    /// the *relative* offset in `B` (the same convention as `PARAMETER::SET_TEXT`).
    pub const TEXT_CHANGED: u8 = 0x07;
    /// **Draft.** `A=targetId, B=focused (0/1)` — a node gained/lost focus.
    pub const FOCUS_CHANGED: u8 = 0x08;
    /// **Draft.** `A=targetId, B=editing (0/1)` — an editing session began/ended.
    pub const EDITING_CHANGED: u8 = 0x09;
    /// **Draft.** `A=targetId, B=0` — the user committed a field (onSubmit).
    pub const SUBMIT: u8 = 0x0A;
    /// **Draft.** `A=targetId, B=offsetX (f32), C=offsetY (f32)` — scroll offset.
    pub const SCROLL: u8 = 0x0B;
    /// **Draft.** `A=targetId, B=deltaX (f32), C=deltaY (f32)` — wheel/trackpad.
    pub const WHEEL: u8 = 0x0C;
    /// **Draft.** `A=targetId, B=days since epoch (I32), C=millis of day (U32)`
    /// — a `DATE_PICKER`'s value changed (matches `PARAMETER::SET_DATE`).
    pub const DATE_CHANGED: u8 = 0x0D;
    /// **Draft.** Global navigation request (host → guest), never node-keyed.
    /// With the `NAVIGATE_URL` flag, `B` is a string offset (event arena /
    /// batch string section) to the destination URL; without it, the event means
    /// "back one step" (native back affordance) and `B`/`C` are ignored.
    pub const NAVIGATE: u8 = 0x0E;
    /// **Draft.** A bound `MEDIA_CONTROLLER`'s playback state changed
    /// (host → guest); `B` = 0/1. Reported only when `PLAYBACK_STATE` is bound.
    pub const MEDIA_PLAY_STATE_CHANGED: u8 = 0x0F;
    /// **Draft.** A bound controller's current position (host → guest); `B` =
    /// seconds (f32). Reported while playing; an app-initiated seek is not echoed.
    pub const MEDIA_TIME_UPDATED: u8 = 0x10;
    /// **Draft.** A bound controller reached the end of its media (host → guest).
    pub const MEDIA_ENDED: u8 = 0x11;
    /// **Draft.** A bound controller's volume changed (host → guest); `B` =
    /// volume (f32, 0..1).
    pub const MEDIA_VOLUME_CHANGED: u8 = 0x12;
    /// **Draft.** A `SIZE_THAT_FITS` slot's selected candidate index changed
    /// (host → guest); `B` = index (f32). Reported once after the first measure,
    /// then only when the derived fit index changes.
    pub const FIT_CHANGED: u8 = 0x13;
    /// **Draft.** A bound controller's media duration became known/changed
    /// (host → guest); `B` = seconds (f32). Reported when the resource loads and
    /// only when the value changes — never a stream.
    pub const MEDIA_DURATION_CHANGED: u8 = 0x14;
}

/// Commands within the `META` category.
pub mod meta {
    /// Host must clear all rendered output.
    pub const RESET: u8 = 0x01;
    /// `A=fieldId (u16, low), B=field value` — a platform environment field
    /// (host → guest); see [`crate::environment`]. An extensible field family:
    /// each opcode sets one field (viewport, initial route, …).
    pub const ENVIRONMENT: u8 = 0x02;
    /// The host (renderer) requests a full snapshot of the current tree
    /// (host → guest). `A/B/C = 0`. Used for reconnect/gap recovery.
    pub const RESYNC: u8 = 0x03;
    /// A transport-liveness heartbeat probe (guest → host). `A/B/C = 0`, no
    /// payload. **Network batch transport only** (spec/OPCODE.md §Transport —
    /// heartbeat): the shared-memory ring MUST NOT emit, expect, or relay it.
    pub const PING: u8 = 0x04;
    /// The reply to `META::PING` (host → guest). `A/B/C = 0`, no payload.
    /// Network batch transport only (see [`PING`]).
    pub const PONG: u8 = 0x05;
    /// **Draft.** `A = mode` — renderer-wide color-scheme override
    /// (guest → host): `0` = platform-derived (default), `1` = light,
    /// `2` = dark. The renderer re-resolves every token-referencing property;
    /// while forced, platform scheme changes are ignored. See
    /// `spec/TOKENS.md` §Color Schemes.
    pub const SET_COLOR_SCHEME: u8 = 0x06;
    /// **Draft.** `A/B/C = 0` — clear every application design-token override
    /// (base + `dark.*`) and re-resolve against the renderer defaults
    /// (guest → host). Emit before a replacement theme's `SET_DESIGN_TOKEN`
    /// opcodes in the same frame.
    pub const RESET_THEME: u8 = 0x07;
    /// **Draft.** `A = fieldId (u16, low), B = value` — presentation metadata
    /// for the host window/surface that owns this stream (guest → host):
    /// title, description, locale (and future fields — an extensible family
    /// like [`ENVIRONMENT`]). Each field defines its own `B` encoding; today
    /// every field is a `STRING` offset (the arena / batch string-section
    /// convention). Renderer-global: survives `META::RESET`, and a full
    /// snapshot re-emits it. Each renderer maps the fields onto its own chrome;
    /// the browser mapping is `<title>` / `<meta name="description">` /
    /// `<html lang>`, not the protocol definition.
    pub const SET_WINDOW_METADATA: u8 = 0x08;
}

/// Window/surface metadata field ids for `META::SET_WINDOW_METADATA`
/// (guest → host).
///
/// Each opcode sets one field; new fields are new ids, never new commands
/// (spec/OPCODE.md §Window metadata). An empty string clears the field and the
/// renderer falls back to its default.
pub mod window_field {
    /// The window/surface title (STRING in `B`).
    pub const TITLE: u16 = 0x0001;
    /// A human-readable description of the current content (STRING in `B`).
    /// Renderers map it to their own affordance (browser meta description,
    /// native accessible description, …).
    pub const DESCRIPTION: u16 = 0x0002;
    /// The content locale as a BCP 47 tag (STRING in `B`). The browser maps it
    /// to `<html lang>`; native renderers may use it for accessibility/formatting.
    pub const LOCALE: u16 = 0x0003;

    /// Every field this protocol version defines.
    pub const ALL: [u16; 3] = [TITLE, DESCRIPTION, LOCALE];
}

/// Values for `META::SET_COLOR_SCHEME`'s `A` field.
pub mod color_scheme_mode {
    /// Follow the platform's native light/dark signal (default).
    pub const PLATFORM: u32 = 0;
    /// Force the light scheme.
    pub const LIGHT: u32 = 1;
    /// Force the dark scheme.
    pub const DARK: u32 = 2;
}

/// Environment field ids for `META::ENVIRONMENT` (host → guest).
///
/// Each opcode sets one platform environment field; new fields are new ids, never
/// new commands (spec/OPCODE.md §Environment fields).
pub mod environment {
    /// Viewport width in logical points (f32 in `B`).
    pub const VIEWPORT_WIDTH: u16 = 0x0001;
    /// Viewport height in logical points (f32 in `B`).
    pub const VIEWPORT_HEIGHT: u16 = 0x0002;
    /// The initial route/deep-link path (STRING: `B` is a string-section/event-arena
    /// offset — the `TEXT_CHANGED`/`NAVIGATE` dual convention).
    pub const ROUTE: u16 = 0x0003;
}

/// Flag bits used across categories.
pub mod flag {
    /// `POINTER_DOWN` / `POINTER_UP`: secondary button (bit 0).
    pub const POINTER_SECONDARY: u16 = 0x0001;
    /// `POINTER_MOVE`: pointer is entering/hovering (bit 0).
    pub const HOVER_ENTER: u16 = 0x0001;
    /// `POINTER_MOVE`: pointer is leaving (bit 1).
    pub const HOVER_LEAVE: u16 = 0x0002;
    /// `KEY_DOWN`: key repeat (bit 1).
    pub const KEY_REPEAT: u16 = 0x0002;
    /// `NAVIGATE`: `B` is a URL string offset (bit 0). Without this flag the
    /// event is a back request.
    pub const NAVIGATE_URL: u16 = 0x0001;
}

/// Bits for the `EVENT_LISTENERS` semantic property (a u32 bitmask).
///
/// Each bit requests that a renderer attach native input recognition for the
/// matching raw-input event and report it for that node — so any element (not
/// just a button) can emit raw events. Bits are independent of the `EVENT`
/// command ids; more event kinds can be added later.
pub mod listener {
    /// `POINTER_DOWN` events (bit 0).
    pub const POINTER_DOWN: u32 = 1 << 0;
    /// `POINTER_MOVE` events (bit 1).
    pub const POINTER_MOVE: u32 = 1 << 1;
    /// `POINTER_UP` events (bit 2).
    pub const POINTER_UP: u32 = 1 << 2;
    /// `KEY_DOWN` events (bit 3).
    pub const KEY_DOWN: u32 = 1 << 3;
    /// `KEY_UP` events (bit 4).
    pub const KEY_UP: u32 = 1 << 4;
    /// **Draft.** `FOCUS_CHANGED` events (bit 5).
    pub const FOCUS: u32 = 1 << 5;
    /// **Draft.** `EDITING_CHANGED` events (bit 6).
    pub const EDITING: u32 = 1 << 6;
    /// **Draft.** `SUBMIT` events (bit 7).
    pub const SUBMIT: u32 = 1 << 7;
    /// **Draft.** `SCROLL` events (bit 8).
    pub const SCROLL: u32 = 1 << 8;
    /// **Draft.** `WHEEL` events (bit 9).
    pub const WHEEL: u32 = 1 << 9;

    /// All pointer events (down + move + up).
    pub const POINTER: u32 = POINTER_DOWN | POINTER_MOVE | POINTER_UP;
}

/// Bits for the `BORDER_EDGES` style property (a u32 bitmask).
///
/// Each bit selects one edge of a node's border. `LEADING`/`TRAILING` are
/// direction-aware; a renderer resolves them to physical `left`/`right`
/// according to its layout direction (LTR by default).
pub mod border_edges {
    /// Top edge (bit 0).
    pub const TOP: u32 = 1 << 0;
    /// Leading edge (bit 1) — physical left in LTR.
    pub const LEADING: u32 = 1 << 1;
    /// Bottom edge (bit 2).
    pub const BOTTOM: u32 = 1 << 2;
    /// Trailing edge (bit 3) — physical right in LTR.
    pub const TRAILING: u32 = 1 << 3;

    /// All four edges.
    pub const ALL: u32 = TOP | LEADING | BOTTOM | TRAILING;
}

/// Value types for `PARAMETER` properties (u8, encoded in the high byte of `B`).
pub mod value_type {
    pub const U8: u8 = 0x01;
    pub const U32: u8 = 0x02;
    pub const I32: u8 = 0x03;
    pub const F32: u8 = 0x04;
    pub const STRING: u8 = 0x05;
    pub const ENUM: u8 = 0x06;
    pub const COLOR: u8 = 0x07;
    pub const DESIGN_TOKEN: u8 = 0x08;
    /// **Draft.** Arena-backed length-prefixed array: `[u32 count][element × count]`
    /// in the string arena (each element holds the value-type's bit pattern —
    /// today `F32`s, e.g. the `FIT_QUERY` threshold table).
    pub const LIST: u8 = 0x09;
}

/// Component types (u16, encoded in the low half of `B` of `TREE::CREATE_NODE`).
///
/// IDs are grouped into three definitive ranges (see `spec/PRIMITIVES.md`):
/// Primitive Drawing `0x01`–`0x0F`, Layout & Container `0x10`–`0x1F`, Semantic
/// Control `0x20`–`0x2F`, plus the utility `COMMENT` at `0x7F`. Renumbered
/// pre-release (wire version stays 1).
pub mod component_type {
    // ── Primitive Drawing & Visual Nodes (0x01–0x0F) ────────────────────────
    /// Standard styled text display.
    pub const TEXT: u16 = 0x01;
    /// Raster, vector, or system icon asset.
    pub const IMAGE: u16 = 0x02;
    /// **Draft.** Solid color / layout-filling background view.
    pub const COLOR: u16 = 0x03;
    /// **Draft.** Vector geometry (`SHAPE_KIND` selects the shape).
    pub const SHAPE: u16 = 0x04;
    /// **Draft.** Axis-aligned separator line.
    pub const DIVIDER: u16 = 0x05;
    /// Flexible expanding layout filler.
    pub const SPACER: u16 = 0x06;
    /// **Draft.** Determinate progress or activity indicator.
    pub const PROGRESS_VIEW: u16 = 0x07;
    /// **Draft.** Range meter against a scale (read-only).
    pub const GAUGE: u16 = 0x08;
    // 0x09 freed (formerly AUDIO — audio now has no view; see MEDIA_CONTROLLER).
    /// **Draft.** Video playback **surface** — renders a `MEDIA_CONTROLLER`'s
    /// video output; it references the controller via `MEDIA_CONTROLLER_ID` and
    /// carries no source of its own (spec/MEDIA.md).
    pub const VIDEO: u16 = 0x0A;
    /// **Draft.** Semantic icon (`ICON_NAME` selects a renderer-native symbol —
    /// Adwaita on GTK, Lucide on the web; spec/ICONS.md).
    pub const ICON: u16 = 0x0B;
    // 0x0C–0x0F reserved (future drawing nodes).

    // ── Layout & Container Primitives (0x10–0x1F) ───────────────────────────
    /// Vertical flex stack.
    pub const VSTACK: u16 = 0x10;
    /// Horizontal flex stack.
    pub const HSTACK: u16 = 0x11;
    /// **Draft.** Depth-overlapping layer stack.
    pub const ZSTACK: u16 = 0x12;
    /// Static 2D matrix grid (eagerly rendered).
    pub const GRID: u16 = 0x13;
    /// Scrollable content container.
    pub const SCROLLVIEW: u16 = 0x14;
    /// **Draft.** Virtualized vertical grid.
    pub const LAZY_VGRID: u16 = 0x15;
    /// **Draft.** Virtualized horizontal grid.
    pub const LAZY_HGRID: u16 = 0x16;
    /// **Draft.** Fit slot (`SizeThatFits`): shows its single selected child —
    /// only the selected candidate is ever transmitted. The renderer measures
    /// its own allocated width against `FIT_QUERY` and reports `FIT_CHANGED`.
    pub const SIZE_THAT_FITS: u16 = 0x17;
    // 0x18–0x1A reserved (formerly composite views, removed).
    /// **Draft.** Virtualized vertical stack.
    pub const LAZY_VSTACK: u16 = 0x1B;
    /// **Draft.** Virtualized horizontal stack.
    pub const LAZY_HSTACK: u16 = 0x1C;
    /// **Draft.** Explicit row grouping for a `GRID`: a grid child whose children
    /// are one row's cells (the SwiftUI `GridRow` surface). Renders nothing
    /// outside a `GRID`.
    pub const GRID_ROW: u16 = 0x1D;
    /// **Draft.** Proxy view (`spec/PROXY.md`): a transparent single-child
    /// container whose child subtree is served by **another** Pathland server.
    /// Renderers render it as a plain container; the proxying server remaps the
    /// foreign subtree's node ids into a disjoint high range and routes its
    /// events back to the origin server.
    pub const PROXY_VIEW: u16 = 0x1E;
    // 0x1F reserved (future layout nodes).

    // ── Semantic Control Nodes (0x20–0x2F) ──────────────────────────────────
    /// Action trigger control.
    pub const BUTTON: u16 = 0x20;
    /// Single-line text input (secure variant via `IS_SECURE`).
    pub const TEXT_FIELD: u16 = 0x21;
    /// **Draft.** Multi-line text editing area.
    pub const TEXT_EDITOR: u16 = 0x22;
    // 0x23 reserved.
    /// Boolean control; the visual variant is `TOGGLE_STYLE`
    /// (`Switch`/`Checkbox`/`Button`).
    pub const TOGGLE: u16 = 0x24;
    /// Continuous or stepped numeric range control.
    pub const SLIDER: u16 = 0x25;
    /// **Draft.** Discrete increment/decrement control.
    pub const STEPPER: u16 = 0x26;
    /// **Draft.** Date & time selection control (`PARAMETER::SET_DATE` value).
    pub const DATE_PICKER: u16 = 0x27;
    /// **Draft.** Selection control (options are child nodes).
    pub const PICKER: u16 = 0x28;
    /// **Draft.** Contextual action trigger + popover container.
    pub const MENU: u16 = 0x29;
    /// **Draft.** Native system color picker control.
    pub const COLOR_PICKER: u16 = 0x2A;
    // 0x2B–0x2F reserved (future semantic controls).

    // ── Non-visual / Resource Nodes (0x30–0x3F) ─────────────────────────────
    /// **Draft.** Media controller — a **non-visual** node that owns a media
    /// resource (`MEDIA_SOURCE`) and its transport state (`PLAYBACK_STATE`,
    /// `MEDIA_POSITION`, `MEDIA_VOLUME`, `MEDIA_MUTED`, `MEDIA_LOOP`,
    /// `MEDIA_RATE`). A `VIDEO` surface references it by id
    /// (`MEDIA_CONTROLLER_ID`); audio has no view and is controlled by the
    /// application's own views. Layout-transparent (spec/MEDIA.md).
    pub const MEDIA_CONTROLLER: u16 = 0x30;
    // 0x31–0x3F reserved (future non-visual/resource nodes).

    /// Opaque/debug node; renderers ignore it (no native element).
    pub const COMMENT: u16 = 0x7F;
}

/// Property IDs (u16, encoded in the low half of `B` of `PARAMETER::SET_PROPERTY`).
///
/// IDs are specified in `spec/OPCODE.md` (carried forward from the historical protocol).
pub mod property_id {
    // Stack
    pub const SPACING: u16 = 0x0001;
    pub const ALIGNMENT: u16 = 0x0002;
    // 0x0003 reserved (formerly JUSTIFICATION; main-axis distribution is
    // expressed via a spacer element instead).
    // 0x0004 reserved (formerly PADDING; now a styling modifier at 0x1011).
    pub const CONTENT_MARGINS: u16 = 0x0005;
    // Text
    pub const TEXT: u16 = 0x000A;
    pub const LINE_LIMIT: u16 = 0x000B;
    pub const TEXT_ALIGNMENT: u16 = 0x000C;
    pub const TRUNCATION_MODE: u16 = 0x000D;
    /// **Draft.** `SHAPE` geometry kind (F32 enum): `Circle`=0, `Rectangle`=1,
    /// `RoundedRectangle`=2, `Capsule`=3, `Ellipse`=4, `Path`=5.
    pub const SHAPE_KIND: u16 = 0x0006;
    // Layout modifiers (draft, 0x000E–0x001D)
    /// **Draft.** Post-layout translation, x (F32). `.offset(x:y:)`.
    pub const OFFSET_X: u16 = 0x000E;
    /// **Draft.** Post-layout translation, y (F32).
    pub const OFFSET_Y: u16 = 0x000F;
    /// **Draft.** Absolute position within the parent, x (F32). `.position(x:y:)`.
    pub const POSITION_X: u16 = 0x0010;
    /// **Draft.** Absolute position within the parent, y (F32).
    pub const POSITION_Y: u16 = 0x0011;
    /// **Draft.** Minimum width (F32). `.frame(minWidth:...)`.
    pub const MIN_WIDTH: u16 = 0x0012;
    // 0x0013 was IDEAL_WIDTH: retired in the POC; do not reuse.
    /// **Draft.** Maximum width (F32).
    pub const MAX_WIDTH: u16 = 0x0014;
    /// **Draft.** Minimum height (F32).
    pub const MIN_HEIGHT: u16 = 0x0015;
    // 0x0016 was IDEAL_HEIGHT: retired in the POC; do not reuse.
    /// **Draft.** Maximum height (F32).
    pub const MAX_HEIGHT: u16 = 0x0017;
    /// **Draft.** Fixed-size hint, horizontal (U8 0/1). `.fixedSize()`.
    pub const FIXED_SIZE_HORIZONTAL: u16 = 0x0018;
    /// **Draft.** Fixed-size hint, vertical (U8 0/1).
    pub const FIXED_SIZE_VERTICAL: u16 = 0x0019;
    /// **Draft.** Layout priority (F32). `.layoutPriority(_:)`.
    pub const LAYOUT_PRIORITY: u16 = 0x001A;
    /// **Draft.** Aspect ratio (F32). `.aspectRatio(_:)`.
    pub const ASPECT_RATIO: u16 = 0x001B;
    /// **Draft.** Content mode (F32 enum): `Fit`=0, `Fill`=1.
    pub const CONTENT_MODE: u16 = 0x001C;
    /// **Draft.** Minimum scale factor (F32). `.minimumScaleFactor(_:)`.
    pub const MINIMUM_SCALE_FACTOR: u16 = 0x001D;
    /// **Draft.** Grid column count (F32, constructor property): a positive value
    /// pins the count (equal `1fr` tracks); `FILL`/absent = auto-fit. Never a
    /// pixel width — the grid's box comes from `WIDTH`/`HEIGHT`.
    pub const GRID_COLUMNS: u16 = 0x001E;
    /// **Draft.** Grid row count (F32, constructor property): the `LAZY_HGRID`
    /// fixed track; positive = count, `FILL`/absent = auto-fit.
    pub const GRID_ROWS: u16 = 0x001F;
    /// **Draft.** Grid track spec (STRING, constructor property): a comma-
    /// separated list of per-track sizes — `flex` | `fixed:<points>` |
    /// `adaptive:<points>` — taking precedence over `GRID_COLUMNS`/`GRID_ROWS`
    /// (the equal-`1fr` count is `N`×`flex` sugar). CSS-grid-native: renderers
    /// without a native equivalent (GTK `GtkGrid`) fall back to natural sizing.
    pub const GRID_TRACKS: u16 = 0x0020;
    /// **Draft.** A `SCROLLVIEW`'s scroll axis (F32 enum): `Vertical`=0 (default
    /// when absent), `Horizontal`=1. The view is layout-greedy on this axis; the
    /// cross axis hugs its content (fill propagation applies).
    pub const SCROLL_AXIS: u16 = 0x0021;
    // Style (0x1000 range)
    pub const BACKGROUND_COLOR: u16 = 0x1001;
    /// **Draft.** Image source (STRING: a resource name, file path, or URL —
    /// an **asset reference**, resolved and loaded by the renderer/host; never
    /// embedded in the opcode stream).
    pub const IMAGE_SOURCE: u16 = 0x1002;
    // 0x1033, 0x1034 freed (formerly AUDIO_SOURCE / VIDEO_SOURCE).
    /// **Draft.** Media playback state (U32 0=pause, 1=play) on a
    /// `MEDIA_CONTROLLER`. When bound, the renderer reports
    /// `MEDIA_PLAY_STATE_CHANGED`.
    pub const PLAYBACK_STATE: u16 = 0x1035;
    /// **Draft.** Media position in seconds (F32) on a `MEDIA_CONTROLLER`; a
    /// change seeks. When bound, the renderer reports `MEDIA_TIME_UPDATED`.
    pub const MEDIA_POSITION: u16 = 0x1036;
    /// **Draft.** Media volume (F32 0..1) on a `MEDIA_CONTROLLER`. When bound,
    /// the renderer reports `MEDIA_VOLUME_CHANGED`.
    pub const MEDIA_VOLUME: u16 = 0x1037;
    /// **Draft.** The referenced `MEDIA_CONTROLLER`'s node id (U32) on a `VIDEO`
    /// surface — the binding that connects the surface to its playback.
    pub const MEDIA_CONTROLLER_ID: u16 = 0x103A;
    /// **Draft.** Media resource (STRING asset reference, see `IMAGE_SOURCE`) on
    /// a `MEDIA_CONTROLLER`.
    pub const MEDIA_SOURCE: u16 = 0x103B;
    /// **Draft.** Mute (U8 0/1) on a `MEDIA_CONTROLLER`; independent of
    /// `MEDIA_VOLUME`.
    pub const MEDIA_MUTED: u16 = 0x103C;
    /// **Draft.** Loop the resource on end (U8 0/1) on a `MEDIA_CONTROLLER`.
    pub const MEDIA_LOOP: u16 = 0x103D;
    /// **Draft.** Playback rate (F32, 1.0 = normal) on a `MEDIA_CONTROLLER`.
    pub const MEDIA_RATE: u16 = 0x103E;
    /// **Draft.** Semantic icon name (STRING, canonical; spec/ICONS.md) on an
    /// `ICON` node. The renderer maps it to its native icon set and falls back
    /// to a renderer-default visual for unknown names.
    pub const ICON_NAME: u16 = 0x1038;
    pub const BORDER_WIDTH: u16 = 0x1003;
    pub const BORDER_COLOR: u16 = 0x1004;
    pub const BORDER_RADIUS: u16 = 0x1005;
    pub const PADDING_STYLE: u16 = 0x1006;
    pub const FONT_SIZE: u16 = 0x1007;
    pub const FONT_WEIGHT: u16 = 0x1008;
    pub const FONT_FAMILY: u16 = 0x1009;
    pub const COLOR: u16 = 0x100A;
    pub const WIDTH: u16 = 0x100B;
    pub const HEIGHT: u16 = 0x100C;
    pub const OPACITY: u16 = 0x100D;
    pub const VISIBLE: u16 = 0x100E;
    pub const Z_INDEX: u16 = 0x100F;
    pub const CLIPS_TO_BOUNDS: u16 = 0x1010;
    pub const PADDING: u16 = 0x1011;
    pub const PADDING_TOP: u16 = 0x1012;
    pub const PADDING_RIGHT: u16 = 0x1013;
    pub const PADDING_BOTTOM: u16 = 0x1014;
    pub const PADDING_LEFT: u16 = 0x1015;
    /// `BORDER_EDGES` — a u32 bitmask (see [`crate::border_edges`]) selecting
    /// which edges of a node's border are drawn.
    pub const BORDER_EDGES: u16 = 0x1016;
    // Text-format modifiers (draft, 0x1017–0x1020)
    /// **Draft.** Font style (F32 enum): `Normal`=0, `Italic`=1.
    pub const FONT_STYLE: u16 = 0x1017;
    /// **Draft.** Font design (F32 enum): `Default`=0, `Serif`=1, `Rounded`=2,
    /// `Monospaced`=3.
    pub const FONT_DESIGN: u16 = 0x1018;
    /// **Draft.** Font width (F32, 0.5–1.5, 1.0 default).
    pub const FONT_WIDTH: u16 = 0x1019;
    /// **Draft.** Kerning (F32 points). `.kerning(_:)`.
    pub const KERNING: u16 = 0x101A;
    /// **Draft.** Tracking (F32 points). `.tracking(_:)`.
    pub const TRACKING: u16 = 0x101B;
    /// **Draft.** Baseline offset (F32 points). `.baselineOffset(_:)`.
    pub const BASELINE_OFFSET: u16 = 0x101C;
    /// **Draft.** Line spacing (F32 points). `.lineSpacing(_:)`.
    pub const LINE_SPACING: u16 = 0x101D;
    /// **Draft.** Text case (F32 enum): `None`=0, `Uppercase`=1, `Lowercase`=2.
    pub const TEXT_CASE: u16 = 0x101E;
    /// **Draft.** Underline (U8 0/1). `.underline()`.
    pub const UNDERLINE: u16 = 0x101F;
    /// **Draft.** Strikethrough (U8 0/1). `.strikethrough()`.
    pub const STRIKETHROUGH: u16 = 0x1020;
    // Effect modifiers (draft, 0x1021–0x102C)
    /// **Draft.** Shadow color (COLOR). `.shadow(color:...)`.
    pub const SHADOW_COLOR: u16 = 0x1021;
    /// **Draft.** Shadow radius (F32).
    pub const SHADOW_RADIUS: u16 = 0x1022;
    /// **Draft.** Shadow x offset (F32).
    pub const SHADOW_X: u16 = 0x1023;
    /// **Draft.** Shadow y offset (F32).
    pub const SHADOW_Y: u16 = 0x1024;
    /// **Draft.** Blur radius (F32). `.blur(radius:)`.
    pub const BLUR_RADIUS: u16 = 0x1025;
    /// **Draft.** Saturation (F32 0–1). `.saturation(_:)`.
    pub const SATURATION: u16 = 0x1026;
    /// **Draft.** Contrast (F32 0–1). `.contrast(_:)`.
    pub const CONTRAST: u16 = 0x1027;
    /// **Draft.** Brightness (F32 −1–1). `.brightness(_:)`.
    pub const BRIGHTNESS: u16 = 0x1028;
    /// **Draft.** Grayscale (F32 0–1). `.grayscale(_:)`.
    pub const GRAYSCALE: u16 = 0x1029;
    /// **Draft.** Hue rotation (F32 degrees). `.hueRotation(_:)`.
    pub const HUE_ROTATION: u16 = 0x102A;
    /// **Draft.** Color multiply (COLOR). `.colorMultiply(_:)`.
    pub const COLOR_MULTIPLY: u16 = 0x102B;
    /// **Draft.** Color invert (U8 0/1). `.colorInvert()`.
    pub const COLOR_INVERT: u16 = 0x102C;
    // Transform (draft)
    /// **Draft.** Rotation (F32 degrees, counter-clockwise). `.rotationEffect(_:)`.
    pub const ROTATION_DEGREES: u16 = 0x102D;
    /// **Draft.** Uniform scale (F32). `.scaleEffect(_:)`.
    pub const SCALE: u16 = 0x102E;
    /// **Draft.** Whether the element participates in hit testing (U8 0/1).
    /// `.allowsHitTesting(_:)`.
    pub const ALLOWS_HIT_TESTING: u16 = 0x102F;
    /// **Draft.** Accent/tint color (COLOR). `.tint(_:)`.
    pub const TINT: u16 = 0x1030;
    /// **Draft.** Presentation hint for structural swaps (F32 enum code):
    /// `None`=0, `PlatformDefault`=1, `Fade`=2, `Slide`=3, `Scale`=4 — emitted
    /// by a `NavigationContainer`/`Conditional.when` slot; the renderer may
    /// animate the swap and must render normally when it ignores the hint.
    pub const TRANSITION: u16 = 0x1031;
    /// **Draft.** A `SIZE_THAT_FITS` slot's candidate fit-query (LIST): the
    /// candidates' `minWidth` thresholds, ascending. The renderer measures its
    /// allocated width and reports the derived fit index (`FIT_CHANGED`).
    pub const FIT_QUERY: u16 = 0x1039;
    /// **Draft.** Predefined typography (ENUM code, see [`crate::text_style`]):
    /// `.font(.title2)` picks a whole design-system typography; the heading
    /// styles (LargeTitle…Headline) imply a heading element on a `TEXT`.
    /// Raw font modifiers (`FONT_SIZE`/`FONT_WEIGHT`/`FONT_FAMILY`/…) override
    /// the visual on top and never imply a heading.
    pub const TEXT_STYLE: u16 = 0x1032;
    // Semantic (0x2000 range)
    pub const ROLE: u16 = 0x2001;
    pub const STATE: u16 = 0x2002;
    pub const ENABLED: u16 = 0x2003;
    pub const SELECTED: u16 = 0x2004;
    /// `EVENT_LISTENERS` — a u32 bitmask (see [`crate::listener`]) declaring
    /// which raw-input events a node wants the renderer to report. This is the
    /// declarative signal the application sets so a renderer attaches native
    /// input recognition to any element — not just buttons.
    pub const EVENT_LISTENERS: u16 = 0x2005;
    /// The current value of a value-bearing control (e.g. a `SLIDER`).
    pub const VALUE: u16 = 0x2006;
    /// The inclusive minimum of a value-bearing control's range (e.g. a `SLIDER`).
    pub const MIN_VALUE: u16 = 0x2007;
    /// The inclusive maximum of a value-bearing control's range (e.g. a `SLIDER`).
    pub const MAX_VALUE: u16 = 0x2008;
    /// The caption label of a `TEXT_FIELD` (a `STRING` property).
    pub const LABEL: u16 = 0x200A;
    /// The placeholder text of a `TEXT_FIELD` (a `STRING` property).
    pub const PROMPT: u16 = 0x200B;
    /// **Draft.** Stepper increment per press (F32).
    pub const STEP_VALUE: u16 = 0x2009;
    /// **Draft.** Control size (F32 enum): `Small`=0, `Regular`=1, `Large`=2.
    pub const CONTROL_SIZE: u16 = 0x200C;
    /// **Draft.** Masked-input token for a `TEXT_FIELD` (U8 0/1).
    pub const IS_SECURE: u16 = 0x200D;
    /// **Draft.** Determinate progress fraction of a `PROGRESS_VIEW` (F32).
    pub const PROGRESS: u16 = 0x200E;
    /// **Draft.** Indeterminate (activity) token of a `PROGRESS_VIEW` (U8 0/1).
    pub const IS_INDETERMINATE: u16 = 0x200F;
    /// **Draft.** Selected child index of a `PICKER`/`MENU` (U32).
    pub const SELECTION: u16 = 0x2010;
    /// **Draft.** Current color of a `COLOR_PICKER` (COLOR).
    pub const COLOR_VALUE: u16 = 0x2012;
    /// **Draft.** `DATE_PICKER` presentation (F32 enum): `Date`=0, `Time`=1,
    /// `DateAndTime`=2.
    pub const DATE_PICKER_MODE: u16 = 0x2013;
    /// **Draft.** `PICKER` presentation (F32 enum): `Menu`=0, `Segmented`=1,
    /// `Wheel`=2, `RadioGroup`=3.
    pub const PICKER_STYLE: u16 = 0x2014;
    /// **Draft.** Bound callback id; gates event delivery for this node.
    pub const ACTION_ID: u16 = 0x2016;
    /// **Draft.** Two-way binding id (control value ↔ app state).
    pub const BINDING_ID: u16 = 0x2017;
    /// **Draft.** Visual style token for a `TOGGLE` (F32 enum code):
    /// `Switch`=0, `Checkbox`=1, `Button`=2.
    pub const TOGGLE_STYLE: u16 = 0x2018;
    /// **Draft.** Current navigation path (STRING, arenaRef), emitted by a
    /// `NavigationContainer` slot; drives web URL sync.
    pub const ROUTE: u16 = 0x2019;
    /// **Draft.** Navigation back-stack depth (U32: number of destinations in
    /// the app's path, including the current one — `push` increments, `pop`
    /// decrements, `replace` leaves it unchanged). Emitted by a
    /// `NavigationContainer` slot so native navigation adapters can reconcile
    /// their page stack by depth (push/pop/replace/reset) instead of route
    /// tags alone. See `spec/DSL.md §4.5` and `spec/MODIFIERS.md §6`.
    pub const NAV_DEPTH: u16 = 0x201A;
    /// **Draft.** Navigation chrome mode (F32 enum code) on a
    /// `NavigationContainer` slot: `PlatformDefault`=0 (the renderer supplies
    /// the navigation chrome — the native container where one exists, a
    /// renderer-drawn back affordance on DOM), `Custom`=1 (the developer owns
    /// all navigation UI and the renderer adds none). A container emits this
    /// once at mount (it never varies per destination). See `spec/DSL.md §4.5`
    /// and `spec/MODIFIERS.md §6`.
    pub const NAV_CHROME: u16 = 0x201B;
}

/// The protocol value type for a property id.
///
/// Color-valued properties (COLOR, BACKGROUND_COLOR, BORDER_COLOR) are emitted
/// with the `COLOR` value type; `EVENT_LISTENERS` and `BORDER_EDGES` are raw
/// `U32` bitmasks; `LABEL`/`PROMPT`/`FONT_FAMILY` are `STRING`; `LINE_LIMIT`,
/// `ACTION_ID`, and `BINDING_ID` are `U32`; all other constraint/style
/// properties are `F32` (enum-valued properties like `ALIGNMENT`/`TOGGLE_STYLE`
/// carry their numeric code as an `F32`). See `spec/MODIFIERS.md` for the
/// canonical mapping.
pub fn value_type_for(prop: u16) -> u8 {
    match prop {
        property_id::COLOR
        | property_id::BACKGROUND_COLOR
        | property_id::BORDER_COLOR
        | property_id::COLOR_VALUE
        | property_id::COLOR_MULTIPLY
        | property_id::SHADOW_COLOR
        | property_id::TINT => value_type::COLOR,
        property_id::EVENT_LISTENERS | property_id::BORDER_EDGES => value_type::U32,
        property_id::SELECTED
        | property_id::IS_SECURE
        | property_id::IS_INDETERMINATE
        | property_id::VISIBLE
        | property_id::ENABLED
        | property_id::CLIPS_TO_BOUNDS
        | property_id::UNDERLINE
        | property_id::STRIKETHROUGH
        | property_id::COLOR_INVERT
        | property_id::ALLOWS_HIT_TESTING
        | property_id::FIXED_SIZE_HORIZONTAL
        | property_id::FIXED_SIZE_VERTICAL
        | property_id::MEDIA_MUTED
        | property_id::MEDIA_LOOP => value_type::U8,
        property_id::LABEL
        | property_id::PROMPT
        | property_id::FONT_FAMILY
        | property_id::IMAGE_SOURCE
        | property_id::GRID_TRACKS
        | property_id::MEDIA_SOURCE
        | property_id::ICON_NAME
        | property_id::ROUTE => value_type::STRING,
        property_id::LINE_LIMIT
        | property_id::SELECTION
        | property_id::ACTION_ID
        | property_id::BINDING_ID
        | property_id::PLAYBACK_STATE
        | property_id::MEDIA_CONTROLLER_ID
        | property_id::NAV_DEPTH => value_type::U32,
        property_id::FIT_QUERY => value_type::LIST,
        _ => value_type::F32,
    }
}

/// Special size constants for `WIDTH` / `HEIGHT`.
pub mod size {
    /// Fill the available space (parent main-axis remainder).
    pub const FILL: f32 = -1.0;
    /// Hug content (size to the intrinsic content).
    pub const HUG_CONTENT: f32 = -2.0;
}

/// Semantic-role codes for the `ROLE` semantic property (`0x2001`).
///
/// Roles are protocol-semantic (carried as an `F32` enum code; see
/// `spec/OPCODE.md` §semantic properties). The catalog is **semantic structure
/// only** — interactive/control roles (button, link, checkbox, …) are NOT roles:
/// they are intrinsic to the control components (a `BUTTON` renders as
/// `<button>`, a `TOGGLE` as `<input type="checkbox">`, a `MENU` as
/// `role="menu"`), and a custom-looking button is expressed with `Button` +
/// `ButtonStyle`. The web renderer maps each semantic role onto its native
/// element. Values MUST NOT be renumbered once released (wire version stays 1).
pub mod role {
    /// No semantic role (the default).
    pub const NONE: u8 = 0;
    /// A heading (ARIA `heading`; the HTML renderer uses `<hN>`, the level
    /// driven by a `TEXT_STYLE` typography when present, default `<h2>`).
    pub const HEADER: u8 = 1;
    /// A paragraph (HTML `<p>`).
    pub const PARAGRAPH: u8 = 2;
    /// A list container (the HTML renderer uses `<ul>`).
    pub const LIST: u8 = 3;
    /// An item within a list (HTML `<li>`).
    pub const LIST_ITEM: u8 = 4;
    /// A summarising/complementary region (HTML `<section>`).
    pub const SUMMARY: u8 = 5;
    /// Site banner (HTML `<header>`).
    pub const BANNER: u8 = 6;
    /// Site navigation (HTML `<nav>`).
    pub const NAVIGATION: u8 = 7;
    /// The page's main content (HTML `<main>`).
    pub const MAIN: u8 = 8;
    /// Site footer / content info (HTML `<footer>`).
    pub const CONTENT_INFO: u8 = 9;
    /// Complementary/aside content (HTML `<aside>`).
    pub const COMPLEMENTARY: u8 = 10;
    /// A self-contained article (HTML `<article>`).
    pub const ARTICLE: u8 = 11;
    /// A thematically grouped section (HTML `<section>`).
    pub const SECTION: u8 = 12;
    /// A search region (HTML `<search>`).
    pub const SEARCH: u8 = 13;
}

/// Predefined typography codes for the `TEXT_STYLE` property (see
/// `spec/MODIFIERS.md`). Each value selects a whole typography from the design
/// system (font size/weight/design). The **heading** styles (LargeTitle through
/// Headline) imply a heading element when applied to a `TEXT`: the renderer
/// emits `<h1>`–`<h5>` (the level comes from the style — no `ROLE` needed). The
/// non-heading styles render as plain `<span>` text. A raw font modifier
/// (`FONT_SIZE`, `FONT_WEIGHT`, `FONT_FAMILY`, …) never implies a heading — it
/// only overrides the typography's visual.
pub mod text_style {
    /// The largest title style (heading level 1).
    pub const LARGE_TITLE: u8 = 0;
    /// A primary title (heading level 2).
    pub const TITLE: u8 = 1;
    /// A secondary title (heading level 3).
    pub const TITLE2: u8 = 2;
    /// A tertiary title (heading level 4).
    pub const TITLE3: u8 = 3;
    /// A headline (heading level 5).
    pub const HEADLINE: u8 = 4;
    /// A sub-headline (NOT a heading — plain `<span>` text).
    pub const SUBHEADLINE: u8 = 5;
    /// Body text (the default).
    pub const BODY: u8 = 6;
    /// A callout (slightly larger than body).
    pub const CALLOUT: u8 = 7;
    /// Footnote text.
    pub const FOOTNOTE: u8 = 8;
    /// Caption text.
    pub const CAPTION: u8 = 9;
    /// A second, smaller caption.
    pub const CAPTION2: u8 = 10;
}

/// Canonical icon names (`ICON_NAME` values; spec/ICONS.md).
///
/// The spec is the **vocabulary contract only**: these names are the protocol
/// `ICON_NAME` surface every renderer understands. The canonical-name →
/// native-glyph mapping is **renderer-owned** (Adwaita on GTK, Remix filled on
/// the web, SF Symbols on Apple) and lives in each renderer — never here, never
/// in the spec.
pub mod icon {
    pub const HOME: &str = "home";
    pub const SETTINGS: &str = "settings";
    pub const SEARCH: &str = "search";
    pub const MENU: &str = "menu";
    pub const CLOSE: &str = "close";
    pub const CLOUD: &str = "cloud";
    pub const CHEVRON_LEFT: &str = "chevron-left";
    pub const CHEVRON_RIGHT: &str = "chevron-right";
    pub const CHEVRON_UP: &str = "chevron-up";
    pub const CHEVRON_DOWN: &str = "chevron-down";
    pub const ARROW_LEFT: &str = "arrow-left";
    pub const ARROW_RIGHT: &str = "arrow-right";
    pub const ADD: &str = "add";
    pub const REMOVE: &str = "remove";
    pub const CHECK: &str = "check";
    pub const EDIT: &str = "edit";
    pub const DELETE: &str = "delete";
    pub const SAVE: &str = "save";
    pub const SHARE: &str = "share";
    pub const DOWNLOAD: &str = "download";
    pub const UPLOAD: &str = "upload";
    pub const REFRESH: &str = "refresh";
    pub const PLAY: &str = "play";
    pub const PAUSE: &str = "pause";
    pub const STOP: &str = "stop";
    pub const SKIP_BACK: &str = "skip-back";
    pub const SKIP_FORWARD: &str = "skip-forward";
    pub const VOLUME: &str = "volume";
    pub const VOLUME_MUTE: &str = "volume-mute";
    pub const SHUFFLE: &str = "shuffle";
    pub const REPEAT: &str = "repeat";
    pub const INFO: &str = "info";
    pub const WARNING: &str = "warning";
    pub const ERROR: &str = "error";
    pub const SUCCESS: &str = "success";
    pub const HEART: &str = "heart";
    pub const STAR: &str = "star";
    pub const USER: &str = "user";
    pub const USERS: &str = "users";
    pub const LOCK: &str = "lock";
    pub const LOGOUT: &str = "logout";
    pub const BELL: &str = "bell";
    pub const FOLDER: &str = "folder";
    pub const FILE: &str = "file";
    pub const IMAGE: &str = "image";
    pub const MUSIC: &str = "music";
    pub const GRID: &str = "grid";
    pub const LIST: &str = "list";
    pub const FILTER: &str = "filter";

    /// Every canonical name, in deterministic (spec, spec/ICONS.md) order.
    pub const NAMES: &[&str] = &[
        HOME, SETTINGS, SEARCH, MENU, CLOSE, CLOUD, CHEVRON_LEFT, CHEVRON_RIGHT,
        CHEVRON_UP, CHEVRON_DOWN, ARROW_LEFT, ARROW_RIGHT, ADD, REMOVE, CHECK,
        EDIT, DELETE, SAVE, SHARE, DOWNLOAD, UPLOAD, REFRESH, PLAY, PAUSE, STOP,
        SKIP_BACK, SKIP_FORWARD, VOLUME, VOLUME_MUTE, SHUFFLE, REPEAT, INFO,
        WARNING, ERROR, SUCCESS, HEART, STAR, USER, USERS, LOCK, LOGOUT, BELL,
        FOLDER, FILE, IMAGE, MUSIC, GRID, LIST, FILTER,
    ];

    /// Whether `name` is a canonical `ICON_NAME` in the spec vocabulary.
    pub fn is_canonical(name: &str) -> bool {
        NAMES.contains(&name)
    }
}

/// Sentinel for append positions (`index = u32::MAX`).
pub const APPEND: u32 = u32::MAX;