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
/* Icon
   Icons are tokens (--gl-icon-* in tokens.css), placed by setting a custom
   property — no <svg> in the markup. Adapted from Lea Verou's @nudeui/icons
   0.0.3 (MIT), https://lea.verou.me/blog/2026/icons/, minus its opt-in
   classes: style queries reach every browser this system supports, and
   the class list is closed.

   --gl-icon-start renders in ::before, --gl-icon-end in ::after. --gl-icon
   means "give this component an icon"; each component redirects it to a
   location (see button.css). An icon takes over that pseudo-element, so a
   component that already draws its own ::before or ::after must not
   redirect there.

   All three are non-inheriting: an icon on a <p> must not repeat on every
   <a> inside it. The pseudo-element inherits explicitly instead. */

@property --gl-icon {
  syntax: "*";
  inherits: false;
}
@property --gl-icon-start {
  syntax: "*";
  inherits: false;
}
@property --gl-icon-end {
  syntax: "*";
  inherits: false;
}

/* A 1em square of the text color, masked by the icon. The image-set()
   first candidate is a transparent placeholder for the box's content; the
   second only exists to make the declaration fail — and so drop the
   pseudo-element — when the icon property is unset. overflow: hidden puts
   the box's baseline at its bottom edge so vertical-align can center it on
   the cap height (https://blog.kizu.dev/cap-height-align/). */
@container style(--gl-icon-start) {
  ::before {
    --gl-icon-start: inherit;
    content: image-set(linear-gradient(transparent 0 100%), var(--gl-icon-start));
    display: inline-block;
    vertical-align: calc(0.5cap - var(--gl-icon-style-size, 1em) / 2 + var(--gl-icon-style-voffset, -0.02em));
    overflow: hidden;
    width: var(--gl-icon-style-size, 1em);
    height: var(--gl-icon-style-size, 1em);
    background-color: var(--gl-icon-style-color, currentColor);
    mask: var(--gl-icon-start) no-repeat center / contain;
    pointer-events: none;
    forced-color-adjust: none;
    flex: none;
  }
  :where(:not(:empty))::before { margin-inline-end: var(--gl-icon-style-spacing, 0.3em); }
}

@container style(--gl-icon-end) {
  ::after {
    --gl-icon-end: inherit;
    content: image-set(linear-gradient(transparent 0 100%), var(--gl-icon-end));
    display: inline-block;
    vertical-align: calc(0.5cap - var(--gl-icon-style-size, 1em) / 2 + var(--gl-icon-style-voffset, -0.02em));
    overflow: hidden;
    width: var(--gl-icon-style-size, 1em);
    height: var(--gl-icon-style-size, 1em);
    background-color: var(--gl-icon-style-color, currentColor);
    mask: var(--gl-icon-end) no-repeat center / contain;
    pointer-events: none;
    forced-color-adjust: none;
    flex: none;
  }
  :where(:not(:empty))::after { margin-inline-start: var(--gl-icon-style-spacing, 0.3em); }
}

/* WebKit only, each fix in its own layer so any unlayered rule beats it.
   https://bugs.webkit.org/show_bug.cgi?id=301609 — icons stay missing
   until the first interaction; an animation forces style to re-resolve
   against the right container. Its default duration is already zero.
   https://bugs.webkit.org/show_bug.cgi?id=325900 — `inherit` on a
   non-inheriting registered property is unreliable, so WebKit gets them
   inheriting (the later registration wins) and descendants reset instead. */
@keyframes gl-webkit-301609 {}

@supports ((-webkit-nbsp-mode: normal) or (-webkit-touch-callout: none) or (font: -apple-system-body)) and (content-visibility: auto) {
  @layer gl-webkit-301609 {
    ::before,
    ::after { animation-name: gl-webkit-301609; }
  }

  @property --gl-icon-start {
    syntax: "*";
    inherits: true;
  }
  @property --gl-icon-end {
    syntax: "*";
    inherits: true;
  }

  @layer gl-webkit-325900 {
    @container style(--gl-icon-start) {
      * { --gl-icon-start: initial; }
    }
    @container style(--gl-icon-end) {
      * { --gl-icon-end: initial; }
    }
  }
}