@campminder/components 0.1.0 → 0.3.0

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.
package/dist/side-nav.js CHANGED
@@ -1,11 +1,11 @@
1
- import { A as I, b as t, i as f, n as c, a as m, t as x } from "./property-B5JHHBCF.js";
2
- import { r as Z } from "./state-Ns9O6R8g.js";
1
+ import { A, b as n, S as C, i as b, n as h, a as w, t as y } from "./shell-tokens-BjECzZvL.js";
2
+ import { r as m } from "./state-BvQoY71J.js";
3
3
  /**
4
4
  * @license
5
5
  * Copyright 2018 Google LLC
6
6
  * SPDX-License-Identifier: BSD-3-Clause
7
7
  */
8
- const b = (e) => e ?? I, S = t` <svg
8
+ const v = (e) => e ?? A, R = n` <svg
9
9
  width="20"
10
10
  height="20"
11
11
  viewBox="0 0 20 20"
@@ -16,7 +16,7 @@ const b = (e) => e ?? I, S = t` <svg
16
16
  d="M15 1.6665H5.00001C4.08334 1.6665 3.33334 2.4165 3.33334 3.33317V16.6665C3.33334 17.5832 4.08334 18.3332 5.00001 18.3332H15C15.9167 18.3332 16.6667 17.5832 16.6667 16.6665V3.33317C16.6667 2.4165 15.9167 1.6665 15 1.6665ZM5.00001 3.33317H9.16668V9.99984L7.08334 8.74984L5.00001 9.99984V3.33317Z"
17
17
  fill="white"
18
18
  />
19
- </svg>`, E = t`<svg
19
+ </svg>`, D = n`<svg
20
20
  width="20"
21
21
  height="20"
22
22
  viewBox="0 0 20 20"
@@ -27,7 +27,7 @@ const b = (e) => e ?? I, S = t` <svg
27
27
  d="M15.95 10.7833C15.9833 10.5333 16 10.275 16 10C16 9.73333 15.9833 9.46667 15.9417 9.21667L17.6333 7.9C17.7833 7.78333 17.825 7.55833 17.7333 7.39167L16.1333 4.625C16.0333 4.44167 15.825 4.38333 15.6417 4.44167L13.65 5.24167C13.2333 4.925 12.7917 4.65833 12.3 4.45833L12 2.34167C11.9667 2.14167 11.8 2 11.6 2H8.39999C8.19999 2 8.04166 2.14167 8.00832 2.34167L7.70832 4.45833C7.21666 4.65833 6.76666 4.93333 6.35832 5.24167L4.36666 4.44167C4.18332 4.375 3.97499 4.44167 3.87499 4.625L2.28332 7.39167C2.18332 7.56667 2.21666 7.78333 2.38332 7.9L4.07499 9.21667C4.03332 9.46667 3.99999 9.74167 3.99999 10C3.99999 10.2583 4.01666 10.5333 4.05832 10.7833L2.36666 12.1C2.21666 12.2167 2.17499 12.4417 2.26666 12.6083L3.86666 15.375C3.96666 15.5583 4.17499 15.6167 4.35832 15.5583L6.34999 14.7583C6.76666 15.075 7.20832 15.3417 7.69999 15.5417L7.99999 17.6583C8.04166 17.8583 8.19999 18 8.39999 18H11.6C11.8 18 11.9667 17.8583 11.9917 17.6583L12.2917 15.5417C12.7833 15.3417 13.2333 15.075 13.6417 14.7583L15.6333 15.5583C15.8167 15.625 16.025 15.5583 16.125 15.375L17.725 12.6083C17.825 12.425 17.7833 12.2167 17.625 12.1L15.95 10.7833ZM9.99999 13C8.34999 13 6.99999 11.65 6.99999 10C6.99999 8.35 8.34999 7 9.99999 7C11.65 7 13 8.35 13 10C13 11.65 11.65 13 9.99999 13Z"
28
28
  fill="white"
29
29
  />
30
- </svg> `, T = t`<svg
30
+ </svg> `, _ = n`<svg
31
31
  width="20"
32
32
  height="20"
33
33
  viewBox="0 0 20 20"
@@ -38,7 +38,7 @@ const b = (e) => e ?? I, S = t` <svg
38
38
  d="M4.16668 10.9833V14.3167L10 17.5L15.8333 14.3167V10.9833L10 14.1667L4.16668 10.9833ZM10 2.5L0.833344 7.5L10 12.5L17.5 8.40833V14.1667H19.1667V7.5L10 2.5Z"
39
39
  fill="white"
40
40
  />
41
- </svg> `, $ = t`<svg
41
+ </svg> `, F = n`<svg
42
42
  width="20"
43
43
  height="20"
44
44
  viewBox="0 0 20 20"
@@ -49,7 +49,7 @@ const b = (e) => e ?? I, S = t` <svg
49
49
  d="M9.99999 1.6665C5.39999 1.6665 1.66666 5.39984 1.66666 9.99984C1.66666 14.5998 5.39999 18.3332 9.99999 18.3332C14.6 18.3332 18.3333 14.5998 18.3333 9.99984C18.3333 5.39984 14.6 1.6665 9.99999 1.6665ZM9.99999 4.1665C11.3833 4.1665 12.5 5.28317 12.5 6.6665C12.5 8.04984 11.3833 9.1665 9.99999 9.1665C8.61666 9.1665 7.49999 8.04984 7.49999 6.6665C7.49999 5.28317 8.61666 4.1665 9.99999 4.1665ZM9.99999 15.9998C7.91666 15.9998 6.07499 14.9332 4.99999 13.3165C5.02499 11.6582 8.33332 10.7498 9.99999 10.7498C11.6583 10.7498 14.975 11.6582 15 13.3165C13.925 14.9332 12.0833 15.9998 9.99999 15.9998Z"
50
50
  fill="white"
51
51
  />
52
- </svg>`, B = t`<svg
52
+ </svg>`, P = n`<svg
53
53
  width="20"
54
54
  height="20"
55
55
  viewBox="0 0 20 20"
@@ -60,7 +60,7 @@ const b = (e) => e ?? I, S = t` <svg
60
60
  d="M16.6667 15.4167C17.5833 15.4167 18.325 14.6667 18.325 13.7501L18.3333 4.58341C18.3333 3.66675 17.5833 2.91675 16.6667 2.91675H3.33333C2.41667 2.91675 1.66667 3.66675 1.66667 4.58341V13.7501C1.66667 14.6667 2.41667 15.4167 3.33333 15.4167H0C0 16.3334 0.75 17.0834 1.66667 17.0834H18.3333C19.25 17.0834 20 16.3334 20 15.4167H16.6667ZM3.33333 4.58341H16.6667V13.7501H3.33333V4.58341ZM10 16.2501C9.54167 16.2501 9.16667 15.8751 9.16667 15.4167C9.16667 14.9584 9.54167 14.5834 10 14.5834C10.4583 14.5834 10.8333 14.9584 10.8333 15.4167C10.8333 15.8751 10.4583 16.2501 10 16.2501Z"
61
61
  fill="white"
62
62
  />
63
- </svg>`, N = t`<svg
63
+ </svg>`, $ = n`<svg
64
64
  width="8"
65
65
  height="12"
66
66
  viewBox="0 0 8 12"
@@ -71,7 +71,7 @@ const b = (e) => e ?? I, S = t` <svg
71
71
  d="M1.70687 0L0.296875 1.41L4.87687 6L0.296875 10.59L1.70687 12L7.70687 6L1.70687 0Z"
72
72
  fill="white"
73
73
  />
74
- </svg>`, k = (e = "#505050") => t`<svg
74
+ </svg>`, z = (e = "#505050") => n`<svg
75
75
  width="14"
76
76
  height="14"
77
77
  viewBox="0 0 14 14"
@@ -82,7 +82,7 @@ const b = (e) => e ?? I, S = t` <svg
82
82
  d="M14 1.41L12.59 0L7 5.59L1.41 0L0 1.41L5.59 7L0 12.59L1.41 14L7 8.41L12.59 14L14 12.59L8.41 7L14 1.41Z"
83
83
  fill="${e}"
84
84
  />
85
- </svg>`, A = t`<svg
85
+ </svg>`, G = n`<svg
86
86
  width="20"
87
87
  height="20"
88
88
  viewBox="0 0 20 20"
@@ -93,7 +93,7 @@ const b = (e) => e ?? I, S = t` <svg
93
93
  d="M15 9.16683V10.8335H18.3333V9.16683H15ZM13.3333 14.6752C14.1333 15.2668 15.175 16.0502 16 16.6668C16.3333 16.2252 16.6667 15.7752 17 15.3335C16.175 14.7168 15.1333 13.9335 14.3333 13.3335C14 13.7835 13.6667 14.2335 13.3333 14.6752ZM17 4.66683C16.6667 4.22516 16.3333 3.77516 16 3.3335C15.175 3.95016 14.1333 4.7335 13.3333 5.3335C13.6667 5.77516 14 6.22516 14.3333 6.66683C15.1333 6.06683 16.175 5.29183 17 4.66683ZM3.33332 7.50016C2.41666 7.50016 1.66666 8.25016 1.66666 9.16683V10.8335C1.66666 11.7502 2.41666 12.5002 3.33332 12.5002H4.16666V15.8335H5.83332V12.5002H6.66666L10.8333 15.0002V5.00016L6.66666 7.50016H3.33332ZM12.9167 10.0002C12.9167 8.89183 12.4333 7.89183 11.6667 7.2085V12.7835C12.4333 12.1085 12.9167 11.1085 12.9167 10.0002Z"
94
94
  fill="white"
95
95
  />
96
- </svg> `, p = t`<svg
96
+ </svg> `, H = n`<svg
97
97
  width="20"
98
98
  height="20"
99
99
  viewBox="0 0 20 20"
@@ -104,7 +104,7 @@ const b = (e) => e ?? I, S = t` <svg
104
104
  d="M15.95 10.7833C15.9833 10.5333 16 10.275 16 10C16 9.73333 15.9833 9.46667 15.9417 9.21667L17.6333 7.9C17.7833 7.78333 17.825 7.55833 17.7333 7.39167L16.1333 4.625C16.0333 4.44167 15.825 4.38333 15.6417 4.44167L13.65 5.24167C13.2333 4.925 12.7917 4.65833 12.3 4.45833L12 2.34167C11.9667 2.14167 11.8 2 11.6 2H8.39999C8.19999 2 8.04166 2.14167 8.00832 2.34167L7.70832 4.45833C7.21666 4.65833 6.76666 4.93333 6.35832 5.24167L4.36666 4.44167C4.18332 4.375 3.97499 4.44167 3.87499 4.625L2.28332 7.39167C2.18332 7.56667 2.21666 7.78333 2.38332 7.9L4.07499 9.21667C4.03332 9.46667 3.99999 9.74167 3.99999 10C3.99999 10.2583 4.01666 10.5333 4.05832 10.7833L2.36666 12.1C2.21666 12.2167 2.17499 12.4417 2.26666 12.6083L3.86666 15.375C3.96666 15.5583 4.17499 15.6167 4.35832 15.5583L6.34999 14.7583C6.76666 15.075 7.20832 15.3417 7.69999 15.5417L7.99999 17.6583C8.04166 17.8583 8.19999 18 8.39999 18H11.6C11.8 18 11.9667 17.8583 11.9917 17.6583L12.2917 15.5417C12.7833 15.3417 13.2333 15.075 13.6417 14.7583L15.6333 15.5583C15.8167 15.625 16.025 15.5583 16.125 15.375L17.725 12.6083C17.825 12.425 17.7833 12.2167 17.625 12.1L15.95 10.7833ZM9.99999 13C8.34999 13 6.99999 11.65 6.99999 10C6.99999 8.35 8.34999 7 9.99999 7C11.65 7 13 8.35 13 10C13 11.65 11.65 13 9.99999 13Z"
105
105
  fill="white"
106
106
  />
107
- </svg> `, O = t`<svg
107
+ </svg> `, U = n`<svg
108
108
  width="20"
109
109
  height="20"
110
110
  viewBox="0 0 20 20"
@@ -115,7 +115,7 @@ const b = (e) => e ?? I, S = t` <svg
115
115
  d="M9.99999 1.6665C5.39999 1.6665 1.66666 5.39984 1.66666 9.99984C1.66666 14.5998 5.39999 18.3332 9.99999 18.3332C14.6 18.3332 18.3333 14.5998 18.3333 9.99984C18.3333 5.39984 14.6 1.6665 9.99999 1.6665ZM10.7333 14.7998V15.8332H9.27499V14.7582C8.65832 14.6082 7.28332 14.1165 6.75832 12.2915L8.13332 11.7332C8.18332 11.9165 8.61666 13.4748 10.1333 13.4748C10.9083 13.4748 11.7833 13.0748 11.7833 12.1332C11.7833 11.3332 11.2 10.9165 9.88332 10.4415C8.96666 10.1165 7.09166 9.58317 7.09166 7.68317C7.09166 7.59984 7.09999 5.68317 9.27499 5.2165V4.1665H10.7333V5.19984C12.2667 5.4665 12.825 6.6915 12.95 7.05817L11.6333 7.6165C11.5417 7.32484 11.1417 6.49984 10.05 6.49984C9.46666 6.49984 8.54166 6.80817 8.54166 7.65817C8.54166 8.44984 9.25832 8.74984 10.7417 9.2415C12.7417 9.93317 13.25 10.9498 13.25 12.1165C13.25 14.3082 11.1667 14.7248 10.7333 14.7998Z"
116
116
  fill="white"
117
117
  />
118
- </svg>`, H = t`<svg
118
+ </svg>`, Z = n`<svg
119
119
  width="20"
120
120
  height="20"
121
121
  viewBox="0 0 20 20"
@@ -126,7 +126,7 @@ const b = (e) => e ?? I, S = t` <svg
126
126
  d="M8.33332 17.0832V12.0832H11.6667V17.0832H15.8333V10.4165H18.3333L9.99999 2.9165L1.66666 10.4165H4.16666V17.0832H8.33332Z"
127
127
  fill="white"
128
128
  />
129
- </svg>`, R = t`<svg
129
+ </svg>`, K = n`<svg
130
130
  width="20"
131
131
  height="20"
132
132
  viewBox="0 0 20 20"
@@ -137,7 +137,7 @@ const b = (e) => e ?? I, S = t` <svg
137
137
  d="M16.6667 4.99984H13.3333V3.33317C13.3333 2.4165 12.5833 1.6665 11.6667 1.6665H8.33332C7.41666 1.6665 6.66666 2.4165 6.66666 3.33317V4.99984H3.33332C2.41666 4.99984 1.66666 5.74984 1.66666 6.6665V16.6665C1.66666 17.5832 2.41666 18.3332 3.33332 18.3332H16.6667C17.5833 18.3332 18.3333 17.5832 18.3333 16.6665V6.6665C18.3333 5.74984 17.5833 4.99984 16.6667 4.99984ZM8.33332 3.33317H11.6667V4.99984H8.33332V3.33317ZM13.3333 12.4998H10.8333V14.9998H9.16666V12.4998H6.66666V10.8332H9.16666V8.33317H10.8333V10.8332H13.3333V12.4998Z"
138
138
  fill="white"
139
139
  />
140
- </svg> `, z = t` <svg
140
+ </svg> `, j = n` <svg
141
141
  width="24"
142
142
  height="24"
143
143
  viewBox="0 0 24 24"
@@ -148,7 +148,7 @@ const b = (e) => e ?? I, S = t` <svg
148
148
  d="M3 18H16V16H3V18ZM3 13H13V11H3V13ZM3 6V8H16V6H3ZM21 15.59L17.42 12L21 8.41L19.59 7L14.59 12L19.59 17L21 15.59Z"
149
149
  fill="white"
150
150
  />
151
- </svg>`, _ = t`<svg
151
+ </svg>`, L = n`<svg
152
152
  width="24"
153
153
  height="24"
154
154
  viewBox="0 0 24 24"
@@ -156,7 +156,7 @@ const b = (e) => e ?? I, S = t` <svg
156
156
  xmlns="http://www.w3.org/2000/svg"
157
157
  >
158
158
  <path d="M3 18H21V16H3V18ZM3 13H21V11H3V13ZM3 6V8H21V6H3Z" fill="white" />
159
- </svg>`, G = t`<svg
159
+ </svg>`, q = n`<svg
160
160
  width="20"
161
161
  height="20"
162
162
  viewBox="0 0 20 20"
@@ -167,7 +167,7 @@ const b = (e) => e ?? I, S = t` <svg
167
167
  d="M12.5 2.5H4.16667C3.25 2.5 2.50833 3.25 2.50833 4.16667L2.5 15.8333C2.5 16.75 3.24167 17.5 4.15833 17.5H15.8333C16.75 17.5 17.5 16.75 17.5 15.8333V7.5L12.5 2.5ZM6.66667 14.1667C6.20833 14.1667 5.83333 13.7917 5.83333 13.3333C5.83333 12.875 6.20833 12.5 6.66667 12.5C7.125 12.5 7.5 12.875 7.5 13.3333C7.5 13.7917 7.125 14.1667 6.66667 14.1667ZM6.66667 10.8333C6.20833 10.8333 5.83333 10.4583 5.83333 10C5.83333 9.54167 6.20833 9.16667 6.66667 9.16667C7.125 9.16667 7.5 9.54167 7.5 10C7.5 10.4583 7.125 10.8333 6.66667 10.8333ZM6.66667 7.5C6.20833 7.5 5.83333 7.125 5.83333 6.66667C5.83333 6.20833 6.20833 5.83333 6.66667 5.83333C7.125 5.83333 7.5 6.20833 7.5 6.66667C7.5 7.125 7.125 7.5 6.66667 7.5ZM11.6667 8.33333V3.75L16.25 8.33333H11.6667Z"
168
168
  fill="white"
169
169
  />
170
- </svg>`, P = t`<svg
170
+ </svg>`, Y = n`<svg
171
171
  width="20"
172
172
  height="20"
173
173
  viewBox="0 0 20 20"
@@ -178,7 +178,7 @@ const b = (e) => e ?? I, S = t` <svg
178
178
  d="M14.1667 10.8332H10V14.9998H14.1667V10.8332ZM13.3333 1.6665V3.33317H6.66667V1.6665H5V3.33317H4.16667C3.24167 3.33317 2.50833 4.08317 2.50833 4.99984L2.5 16.6665C2.5 17.5832 3.24167 18.3332 4.16667 18.3332H15.8333C16.75 18.3332 17.5 17.5832 17.5 16.6665V4.99984C17.5 4.08317 16.75 3.33317 15.8333 3.33317H15V1.6665H13.3333ZM15.8333 16.6665H4.16667V7.49984H15.8333V16.6665Z"
179
179
  fill="white"
180
180
  />
181
- </svg> `, D = t`<svg
181
+ </svg> `, Q = n`<svg
182
182
  width="20"
183
183
  height="20"
184
184
  viewBox="0 0 20 20"
@@ -189,7 +189,7 @@ const b = (e) => e ?? I, S = t` <svg
189
189
  d="M16.6667 5.83317H12.5V3.33317C12.5 2.4165 11.75 1.6665 10.8333 1.6665H9.16666C8.24999 1.6665 7.49999 2.4165 7.49999 3.33317V5.83317H3.33332C2.41666 5.83317 1.66666 6.58317 1.66666 7.49984V16.6665C1.66666 17.5832 2.41666 18.3332 3.33332 18.3332H16.6667C17.5833 18.3332 18.3333 17.5832 18.3333 16.6665V7.49984C18.3333 6.58317 17.5833 5.83317 16.6667 5.83317ZM7.49999 9.99984C8.19166 9.99984 8.74999 10.5582 8.74999 11.2498C8.74999 11.9415 8.19166 12.4998 7.49999 12.4998C6.80832 12.4998 6.24999 11.9415 6.24999 11.2498C6.24999 10.5582 6.80832 9.99984 7.49999 9.99984ZM9.99999 14.9998H4.99999V14.3748C4.99999 13.5415 6.66666 13.1248 7.49999 13.1248C8.33332 13.1248 9.99999 13.5415 9.99999 14.3748V14.9998ZM10.8333 7.49984H9.16666V3.33317H10.8333V7.49984ZM15 13.7498H11.6667V12.4998H15V13.7498ZM15 11.2498H11.6667V9.99984H15V11.2498Z"
190
190
  fill="white"
191
191
  />
192
- </svg> `, U = t`<svg
192
+ </svg> `, W = n`<svg
193
193
  width="20"
194
194
  height="20"
195
195
  viewBox="0 0 20 20"
@@ -200,7 +200,183 @@ const b = (e) => e ?? I, S = t` <svg
200
200
  d="M10 2.0835C6.66668 2.0835 3.33334 2.50016 3.33334 5.41683V13.3335C3.33334 14.1252 3.65001 14.8418 4.16668 15.3668V17.0835C4.16668 17.5418 4.54168 17.9168 5.00001 17.9168H5.83334C6.29168 17.9168 6.66668 17.5418 6.66668 17.0835V16.2502H13.3333V17.0835C13.3333 17.5418 13.7083 17.9168 14.1667 17.9168H15C15.4583 17.9168 15.8333 17.5418 15.8333 17.0835V15.3668C16.35 14.8418 16.6667 14.1252 16.6667 13.3335V5.41683C16.6667 2.50016 13.6833 2.0835 10 2.0835ZM7.08334 13.7502C6.39168 13.7502 5.83334 13.1918 5.83334 12.5002C5.83334 11.8085 6.39168 11.2502 7.08334 11.2502C7.77501 11.2502 8.33334 11.8085 8.33334 12.5002C8.33334 13.1918 7.77501 13.7502 7.08334 13.7502ZM12.9167 13.7502C12.225 13.7502 11.6667 13.1918 11.6667 12.5002C11.6667 11.8085 12.225 11.2502 12.9167 11.2502C13.6083 11.2502 14.1667 11.8085 14.1667 12.5002C14.1667 13.1918 13.6083 13.7502 12.9167 13.7502ZM15 8.75016H5.00001V6.25016H15V8.75016Z"
201
201
  fill="white"
202
202
  />
203
- </svg> `, j = t`<svg
203
+ </svg> `, E = 248, T = 16, f = 530, X = b`
204
+ /* ===== HOST-LEVEL CUSTOM PROPERTIES ===== */
205
+ :host {
206
+ /* '--cm-side-nav-width' is set on 'campminder-app-shell''s ':host'
207
+ * (packages/campminder/src/layout.ts is the source of truth) and
208
+ * pierces the shadow boundary, so it's readable here even though this
209
+ * package is portal-agnostic. It also switches to the collapsed
210
+ * width, which a literal '168px' can't — the fallback below is only
211
+ * for standalone rendering with no shell present.
212
+ * '100vw' is correct for production, where the shell fills the
213
+ * viewport and the nav starts at x=0; it reads over-wide in this
214
+ * harness only because the harness page has a 24px inset the shell
215
+ * doesn't have — a harness-geometry artifact, not a formula bug. */
216
+ --cm-mega-menu-max-width: calc(100vw - var(--cm-side-nav-width, 168px));
217
+
218
+ /* Redeclared even though it would be inherited anyway. Unlike the top bar
219
+ * and the banner, '<cm-mega-menu>' is NOT a sibling shadow root: 'SideNav.ts'
220
+ * renders it inside the side nav's own shadow root (deliberately, rather than
221
+ * through a slot — see the note at that call site), so it is a descendant in
222
+ * the flattened tree and custom properties already reach it.
223
+ *
224
+ * Declaring it regardless keeps the flyout's typeface a property of the
225
+ * flyout, so it survives being reparented or slotted later, and means all
226
+ * four chrome stylesheets read the same way. It cannot drift from the side
227
+ * nav's value because both resolve the one 'SHELL_FONT_FAMILY' constant;
228
+ * an inherited-only version would quietly start differing the moment either
229
+ * file stopped doing that. Rationale for the chain: '../shell-tokens.ts'. */
230
+ --font-family: ${C};
231
+ }
232
+
233
+ /* ===== CSS RESET ===== */
234
+ * {
235
+ margin: 0;
236
+ padding: 0;
237
+ box-sizing: border-box;
238
+ }
239
+
240
+ /* ===== ANIMATIONS ===== */
241
+ @keyframes fadeIn {
242
+ from {
243
+ opacity: 0;
244
+ }
245
+ to {
246
+ opacity: 1;
247
+ }
248
+ }
249
+
250
+ /* ===== MEGA MENU CONTAINER ===== */
251
+ .mega-menu {
252
+ position: absolute;
253
+ left: 100%;
254
+ top: 0;
255
+ max-width: var(--cm-mega-menu-max-width);
256
+ height: 100%;
257
+ border-radius: 4px;
258
+ background: #fff;
259
+ box-shadow: 0px 2px 16px 0px rgba(0, 0, 0, 0.12);
260
+ animation: fadeIn 0.5s ease;
261
+ }
262
+
263
+ /* ===== HEADER SECTION ===== */
264
+ .header {
265
+ display: flex;
266
+ align-items: center;
267
+ justify-content: space-between;
268
+ color: #505050;
269
+ border-bottom: 1px solid rgba(160, 160, 160, 1);
270
+ margin: 0 16px;
271
+ height: 56px;
272
+ }
273
+
274
+ .header-left {
275
+ display: flex;
276
+ align-items: center;
277
+ }
278
+
279
+ .header-title {
280
+ display: grid;
281
+ place-content: center;
282
+ }
283
+
284
+ .header-icon {
285
+ margin-right: 8px;
286
+ display: flex;
287
+ justify-content: center;
288
+ align-items: center;
289
+ }
290
+
291
+ /* ===== CLOSE BUTTON ===== */
292
+ .close-button {
293
+ display: flex;
294
+ width: 24px;
295
+ height: 24px;
296
+ justify-content: center;
297
+ align-items: center;
298
+ border-radius: 4px;
299
+ cursor: pointer;
300
+ transition: background 0.2s ease;
301
+ }
302
+
303
+ .close-button:hover {
304
+ background: rgba(119, 61, 189, 0.12);
305
+ }
306
+
307
+ /* ===== TYPOGRAPHY ===== */
308
+ .title-text {
309
+ color: #505050;
310
+ font-family: var(--font-family);
311
+ font-size: 16px;
312
+ font-weight: 600;
313
+ line-height: 24px;
314
+ letter-spacing: 0.0025em;
315
+ }
316
+
317
+ /* ===== MENU ITEMS CONTAINER ===== */
318
+ .menu-items {
319
+ height: calc(100% - 56px);
320
+ max-width: var(--cm-mega-menu-max-width);
321
+ display: flex;
322
+ flex-flow: column wrap;
323
+ padding: 10px 16px 10px 0px;
324
+ overflow: auto;
325
+ }
326
+
327
+ /* ===== MENU ITEM ===== */
328
+ .menu-item {
329
+ width: ${E}px;
330
+ margin-left: ${T}px;
331
+ margin-bottom: 12px;
332
+ font-family: var(--font-family);
333
+ font-size: 14px;
334
+ font-weight: 400;
335
+ line-height: 20px;
336
+ letter-spacing: -0.001em;
337
+ }
338
+
339
+ .menu-title {
340
+ display: flex;
341
+ width: 248px;
342
+ padding: 4px 12px;
343
+ align-items: center;
344
+ gap: 8px;
345
+ }
346
+
347
+ /* ===== MENU LINKS ===== */
348
+ .menu-url {
349
+ display: flex;
350
+ align-items: center;
351
+ width: 248px;
352
+ min-height: 32px;
353
+ padding: 6px 12px;
354
+ border-radius: 4px;
355
+ text-decoration: none;
356
+ color: #380f8c;
357
+ transition: background 0.2s ease;
358
+ }
359
+
360
+ .menu-url:hover,
361
+ .menu-url:focus {
362
+ background: rgba(119, 61, 189, 0.12);
363
+ outline: none;
364
+ cursor: pointer;
365
+ }
366
+
367
+ .new-tab-icon {
368
+ margin-left: 4px;
369
+ display: grid;
370
+ place-content: center;
371
+ }
372
+
373
+ /* ===== RESPONSIVE ===== */
374
+ @media (max-width: 1150px) {
375
+ .menu-items {
376
+ flex-wrap: nowrap;
377
+ }
378
+ }
379
+ `, J = n`<svg
204
380
  width="24"
205
381
  height="24"
206
382
  viewBox="0 0 24 24"
@@ -211,7 +387,7 @@ const b = (e) => e ?? I, S = t` <svg
211
387
  d="M18 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V4C20 2.9 19.1 2 18 2ZM6 4H11V12L8.5 10.5L6 12V4Z"
212
388
  fill="#505050"
213
389
  />
214
- </svg>`, F = t`<svg
390
+ </svg>`, ee = n`<svg
215
391
  width="24"
216
392
  height="24"
217
393
  viewBox="0 0 24 24"
@@ -222,7 +398,7 @@ const b = (e) => e ?? I, S = t` <svg
222
398
  d="M19.1401 12.9399C19.1801 12.6399 19.2001 12.3299 19.2001 11.9999C19.2001 11.6799 19.1801 11.3599 19.1301 11.0599L21.1601 9.4799C21.3401 9.3399 21.3901 9.0699 21.2801 8.8699L19.3601 5.5499C19.2401 5.3299 18.9901 5.2599 18.7701 5.3299L16.3801 6.2899C15.8801 5.9099 15.3501 5.5899 14.7601 5.3499L14.4001 2.8099C14.3601 2.5699 14.1601 2.3999 13.9201 2.3999H10.0801C9.84011 2.3999 9.65011 2.5699 9.61011 2.8099L9.25011 5.3499C8.66011 5.5899 8.12011 5.9199 7.63011 6.2899L5.24011 5.3299C5.02011 5.2499 4.77011 5.3299 4.65011 5.5499L2.74011 8.8699C2.62011 9.0799 2.66011 9.3399 2.86011 9.4799L4.89011 11.0599C4.84011 11.3599 4.80011 11.6899 4.80011 11.9999C4.80011 12.3099 4.82011 12.6399 4.87011 12.9399L2.84011 14.5199C2.66011 14.6599 2.61011 14.9299 2.72011 15.1299L4.64011 18.4499C4.76011 18.6699 5.01011 18.7399 5.23011 18.6699L7.62011 17.7099C8.12011 18.0899 8.65011 18.4099 9.24011 18.6499L9.60011 21.1899C9.65011 21.4299 9.84011 21.5999 10.0801 21.5999H13.9201C14.1601 21.5999 14.3601 21.4299 14.3901 21.1899L14.7501 18.6499C15.3401 18.4099 15.8801 18.0899 16.3701 17.7099L18.7601 18.6699C18.9801 18.7499 19.2301 18.6699 19.3501 18.4499L21.2701 15.1299C21.3901 14.9099 21.3401 14.6599 21.1501 14.5199L19.1401 12.9399ZM12.0001 15.5999C10.0201 15.5999 8.40011 13.9799 8.40011 11.9999C8.40011 10.0199 10.0201 8.3999 12.0001 8.3999C13.9801 8.3999 15.6001 10.0199 15.6001 11.9999C15.6001 13.9799 13.9801 15.5999 12.0001 15.5999Z"
223
399
  fill="#505050"
224
400
  />
225
- </svg>`, K = t`<svg
401
+ </svg>`, te = n`<svg
226
402
  width="24"
227
403
  height="24"
228
404
  viewBox="0 0 24 24"
@@ -233,7 +409,7 @@ const b = (e) => e ?? I, S = t` <svg
233
409
  d="M5 13.18V17.18L12 21L19 17.18V13.18L12 17L5 13.18ZM12 3L1 9L12 15L21 10.09V17H23V9L12 3Z"
234
410
  fill="#505050"
235
411
  />
236
- </svg>`, Y = t`<svg
412
+ </svg>`, oe = n`<svg
237
413
  width="24"
238
414
  height="24"
239
415
  viewBox="0 0 24 24"
@@ -244,7 +420,7 @@ const b = (e) => e ?? I, S = t` <svg
244
420
  d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 5C13.66 5 15 6.34 15 8C15 9.66 13.66 11 12 11C10.34 11 9 9.66 9 8C9 6.34 10.34 5 12 5ZM12 19.2C9.5 19.2 7.29 17.92 6 15.98C6.03 13.99 10 12.9 12 12.9C13.99 12.9 17.97 13.99 18 15.98C16.71 17.92 14.5 19.2 12 19.2Z"
245
421
  fill="#505050"
246
422
  />
247
- </svg>`, W = t`<svg
423
+ </svg>`, ie = n`<svg
248
424
  width="20"
249
425
  height="20"
250
426
  viewBox="0 0 20 20"
@@ -255,7 +431,7 @@ const b = (e) => e ?? I, S = t` <svg
255
431
  d="M16.6667 15.4167C17.5833 15.4167 18.325 14.6667 18.325 13.7501L18.3333 4.58341C18.3333 3.66675 17.5833 2.91675 16.6667 2.91675H3.33333C2.41667 2.91675 1.66667 3.66675 1.66667 4.58341V13.7501C1.66667 14.6667 2.41667 15.4167 3.33333 15.4167H0C0 16.3334 0.75 17.0834 1.66667 17.0834H18.3333C19.25 17.0834 20 16.3334 20 15.4167H16.6667ZM3.33333 4.58341H16.6667V13.7501H3.33333V4.58341ZM10 16.2501C9.54167 16.2501 9.16667 15.8751 9.16667 15.4167C9.16667 14.9584 9.54167 14.5834 10 14.5834C10.4583 14.5834 10.8333 14.9584 10.8333 15.4167C10.8333 15.8751 10.4583 16.2501 10 16.2501Z"
256
432
  fill="#505050"
257
433
  />
258
- </svg>`, q = t`<svg
434
+ </svg>`, ne = n`<svg
259
435
  width="24"
260
436
  height="24"
261
437
  viewBox="0 0 24 24"
@@ -266,7 +442,7 @@ const b = (e) => e ?? I, S = t` <svg
266
442
  d="M18 11V13H22V11H18ZM16 17.61C16.96 18.32 18.21 19.26 19.2 20C19.6 19.47 20 18.93 20.4 18.4C19.41 17.66 18.16 16.72 17.2 16C16.8 16.54 16.4 17.08 16 17.61ZM20.4 5.6C20 5.07 19.6 4.53 19.2 4C18.21 4.74 16.96 5.68 16 6.4C16.4 6.93 16.8 7.47 17.2 8C18.16 7.28 19.41 6.35 20.4 5.6ZM4 9C2.9 9 2 9.9 2 11V13C2 14.1 2.9 15 4 15H5V19H7V15H8L13 18V6L8 9H4ZM15.5 12C15.5 10.67 14.92 9.47 14 8.65V15.34C14.92 14.53 15.5 13.33 15.5 12Z"
267
443
  fill="#505050"
268
444
  />
269
- </svg> `, u = t`<svg
445
+ </svg> `, V = n`<svg
270
446
  width="24"
271
447
  height="24"
272
448
  viewBox="0 0 24 24"
@@ -277,7 +453,7 @@ const b = (e) => e ?? I, S = t` <svg
277
453
  d="M19.1401 12.9399C19.1801 12.6399 19.2001 12.3299 19.2001 11.9999C19.2001 11.6799 19.1801 11.3599 19.1301 11.0599L21.1601 9.4799C21.3401 9.3399 21.3901 9.0699 21.2801 8.8699L19.3601 5.5499C19.2401 5.3299 18.9901 5.2599 18.7701 5.3299L16.3801 6.2899C15.8801 5.9099 15.3501 5.5899 14.7601 5.3499L14.4001 2.8099C14.3601 2.5699 14.1601 2.3999 13.9201 2.3999H10.0801C9.84011 2.3999 9.65011 2.5699 9.61011 2.8099L9.25011 5.3499C8.66011 5.5899 8.12011 5.9199 7.63011 6.2899L5.24011 5.3299C5.02011 5.2499 4.77011 5.3299 4.65011 5.5499L2.74011 8.8699C2.62011 9.0799 2.66011 9.3399 2.86011 9.4799L4.89011 11.0599C4.84011 11.3599 4.80011 11.6899 4.80011 11.9999C4.80011 12.3099 4.82011 12.6399 4.87011 12.9399L2.84011 14.5199C2.66011 14.6599 2.61011 14.9299 2.72011 15.1299L4.64011 18.4499C4.76011 18.6699 5.01011 18.7399 5.23011 18.6699L7.62011 17.7099C8.12011 18.0899 8.65011 18.4099 9.24011 18.6499L9.60011 21.1899C9.65011 21.4299 9.84011 21.5999 10.0801 21.5999H13.9201C14.1601 21.5999 14.3601 21.4299 14.3901 21.1899L14.7501 18.6499C15.3401 18.4099 15.8801 18.0899 16.3701 17.7099L18.7601 18.6699C18.9801 18.7499 19.2301 18.6699 19.3501 18.4499L21.2701 15.1299C21.3901 14.9099 21.3401 14.6599 21.1501 14.5199L19.1401 12.9399ZM12.0001 15.5999C10.0201 15.5999 8.40011 13.9799 8.40011 11.9999C8.40011 10.0199 10.0201 8.3999 12.0001 8.3999C13.9801 8.3999 15.6001 10.0199 15.6001 11.9999C15.6001 13.9799 13.9801 15.5999 12.0001 15.5999Z"
278
454
  fill="#505050"
279
455
  />
280
- </svg>`, X = t`<svg
456
+ </svg>`, ae = n`<svg
281
457
  width="24"
282
458
  height="24"
283
459
  viewBox="0 0 24 24"
@@ -288,7 +464,7 @@ const b = (e) => e ?? I, S = t` <svg
288
464
  d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12.88 17.76V19H11.13V17.71C10.39 17.53 8.74 16.94 8.11 14.75L9.76 14.08C9.82 14.3 10.34 16.17 12.16 16.17C13.09 16.17 14.14 15.69 14.14 14.56C14.14 13.6 13.44 13.1 11.86 12.53C10.76 12.14 8.51 11.5 8.51 9.22C8.51 9.12 8.52 6.82 11.13 6.26V5H12.88V6.24C14.72 6.56 15.39 8.03 15.54 8.47L13.96 9.14C13.85 8.79 13.37 7.8 12.06 7.8C11.36 7.8 10.25 8.17 10.25 9.19C10.25 10.14 11.11 10.5 12.89 11.09C15.29 11.92 15.9 13.14 15.9 14.54C15.9 17.17 13.4 17.67 12.88 17.76Z"
289
465
  fill="#505050"
290
466
  />
291
- </svg> `, J = t`<svg
467
+ </svg> `, se = n`<svg
292
468
  width="24"
293
469
  height="24"
294
470
  viewBox="0 0 24 24"
@@ -299,7 +475,7 @@ const b = (e) => e ?? I, S = t` <svg
299
475
  d="M20 6H16V4C16 2.9 15.1 2 14 2H10C8.9 2 8 2.9 8 4V6H4C2.9 6 2 6.9 2 8V20C2 21.1 2.9 22 4 22H20C21.1 22 22 21.1 22 20V8C22 6.9 21.1 6 20 6ZM10 4H14V6H10V4ZM16 15H13V18H11V15H8V13H11V10H13V13H16V15Z"
300
476
  fill="#505050"
301
477
  />
302
- </svg> `, w = t`<svg
478
+ </svg> `, I = n`<svg
303
479
  width="16"
304
480
  height="16"
305
481
  viewBox="0 0 16 16"
@@ -310,7 +486,7 @@ const b = (e) => e ?? I, S = t` <svg
310
486
  d="M12.6667 12.6667H3.33333V3.33333H8V2H3.33333C2.59333 2 2 2.6 2 3.33333V12.6667C2 13.4 2.59333 14 3.33333 14H12.6667C13.4 14 14 13.4 14 12.6667V8H12.6667V12.6667ZM9.33333 2V3.33333H11.7267L5.17333 9.88667L6.11333 10.8267L12.6667 4.27333V6.66667H14V2H9.33333Z"
311
487
  fill="#282828"
312
488
  />
313
- </svg> `, Q = t`<svg
489
+ </svg> `, re = n`<svg
314
490
  width="24"
315
491
  height="24"
316
492
  viewBox="0 0 24 24"
@@ -321,7 +497,7 @@ const b = (e) => e ?? I, S = t` <svg
321
497
  d="M15 3H5C3.9 3 3.01 3.9 3.01 5L3 19C3 20.1 3.89 21 4.99 21H19C20.1 21 21 20.1 21 19V9L15 3ZM8 17C7.45 17 7 16.55 7 16C7 15.45 7.45 15 8 15C8.55 15 9 15.45 9 16C9 16.55 8.55 17 8 17ZM8 13C7.45 13 7 12.55 7 12C7 11.45 7.45 11 8 11C8.55 11 9 11.45 9 12C9 12.55 8.55 13 8 13ZM8 9C7.45 9 7 8.55 7 8C7 7.45 7.45 7 8 7C8.55 7 9 7.45 9 8C9 8.55 8.55 9 8 9ZM14 10V4.5L19.5 10H14Z"
322
498
  fill="#505050"
323
499
  />
324
- </svg> `, e1 = t`<svg
500
+ </svg> `, le = n`<svg
325
501
  width="24"
326
502
  height="24"
327
503
  viewBox="0 0 24 24"
@@ -332,7 +508,7 @@ const b = (e) => e ?? I, S = t` <svg
332
508
  d="M17 13H12V18H17V13ZM16 2V4H8V2H6V4H5C3.89 4 3.01 4.9 3.01 6L3 20C3 21.1 3.89 22 5 22H19C20.1 22 21 21.1 21 20V6C21 4.9 20.1 4 19 4H18V2H16ZM19 20H5V9H19V20Z"
333
509
  fill="#505050"
334
510
  />
335
- </svg> `, t1 = t`<svg
511
+ </svg> `, ce = n`<svg
336
512
  width="24"
337
513
  height="24"
338
514
  viewBox="0 0 24 24"
@@ -343,7 +519,7 @@ const b = (e) => e ?? I, S = t` <svg
343
519
  d="M20 7H15V4C15 2.9 14.1 2 13 2H11C9.9 2 9 2.9 9 4V7H4C2.9 7 2 7.9 2 9V20C2 21.1 2.9 22 4 22H20C21.1 22 22 21.1 22 20V9C22 7.9 21.1 7 20 7ZM9 12C9.83 12 10.5 12.67 10.5 13.5C10.5 14.33 9.83 15 9 15C8.17 15 7.5 14.33 7.5 13.5C7.5 12.67 8.17 12 9 12ZM12 18H6V17.25C6 16.25 8 15.75 9 15.75C10 15.75 12 16.25 12 17.25V18ZM13 9H11V4H13V9ZM18 16.5H14V15H18V16.5ZM18 13.5H14V12H18V13.5Z"
344
520
  fill="#505050"
345
521
  />
346
- </svg> `, o1 = t`<svg
522
+ </svg> `, he = n`<svg
347
523
  width="24"
348
524
  height="24"
349
525
  viewBox="0 0 24 24"
@@ -354,122 +530,275 @@ const b = (e) => e ?? I, S = t` <svg
354
530
  d="M12 2.5C8 2.5 4 3 4 6.5V16C4 16.95 4.38 17.81 5 18.44V20.5C5 21.05 5.45 21.5 6 21.5H7C7.55 21.5 8 21.05 8 20.5V19.5H16V20.5C16 21.05 16.45 21.5 17 21.5H18C18.55 21.5 19 21.05 19 20.5V18.44C19.62 17.81 20 16.95 20 16V6.5C20 3 16.42 2.5 12 2.5ZM8.5 16.5C7.67 16.5 7 15.83 7 15C7 14.17 7.67 13.5 8.5 13.5C9.33 13.5 10 14.17 10 15C10 15.83 9.33 16.5 8.5 16.5ZM15.5 16.5C14.67 16.5 14 15.83 14 15C14 14.17 14.67 13.5 15.5 13.5C16.33 13.5 17 14.17 17 15C17 15.83 16.33 16.5 15.5 16.5ZM18 10.5H6V7.5H18V10.5Z"
355
531
  fill="#505050"
356
532
  />
357
- </svg>`, M = 248, V = 16, i1 = f`
358
- /* ===== HOST-LEVEL CUSTOM PROPERTIES ===== */
533
+ </svg>`, O = {
534
+ AccountsSvgIcon: J,
535
+ AdminSvgIcon: ee,
536
+ AlumniSvgIcon: te,
537
+ CamperSvgIcon: oe,
538
+ CommunicationSvgIcon: ne,
539
+ CampInTouchSvgIcon: ie,
540
+ FinancialSvgIcon: ae,
541
+ MedicalSvgIcon: se,
542
+ ReportingSvgIcon: re,
543
+ SchedulingSvgIcon: le,
544
+ StaffSvgIcon: ce,
545
+ TravelSvgIcon: he
546
+ };
547
+ function de(e) {
548
+ return e ? e.id === "home" ? Z : O[`${e.label}SvgIcon`] ?? V : V;
549
+ }
550
+ function Le(e) {
551
+ return e ? e.id === "home" ? !0 : `${e.label}SvgIcon` in O : !1;
552
+ }
553
+ function p(e) {
554
+ return e.startsWith("http") ? new URL(e).pathname + new URL(e).search : e;
555
+ }
556
+ function ge(e, t) {
557
+ const i = p(t);
558
+ for (const o of e) {
559
+ if (o.href && p(o.href) === i)
560
+ return o.id;
561
+ for (const a of o.subCategories)
562
+ if (a.href && p(a.href) === i || a.items.find((r) => p(r.href) === i)) return o.id;
563
+ }
564
+ }
565
+ function ue(e) {
566
+ return e.items.length > 0 || !!e.href;
567
+ }
568
+ function d(e) {
569
+ return e.subCategories.filter(ue);
570
+ }
571
+ function S(e, t) {
572
+ const i = e.find((o) => o.id === t);
573
+ return !!i && d(i).length > 0;
574
+ }
575
+ function pe(e, t) {
576
+ return t === "/" ? "home" : ge(e, t) ?? "";
577
+ }
578
+ function B(e) {
579
+ return e.popup ? n`
580
+ <a
581
+ class="menu-url"
582
+ href="#nowhere"
583
+ @click=${() => {
584
+ const t = window.open(e.href, "", e.popupProperties);
585
+ return t && (t.opener = null), !1;
586
+ }}
587
+ target="_top"
588
+ >
589
+ ${e.label}
590
+ <span class="new-tab-icon">${I}</span>
591
+ </a>
592
+ ` : n`
593
+ <a
594
+ class="menu-url"
595
+ href="${e.href}"
596
+ target=${e.newTab ? "_blank" : "_self"}
597
+ rel=${v(e.newTab ? "noopener noreferrer" : void 0)}
598
+ >
599
+ ${e.label} ${e.newTab ? n`<span class="new-tab-icon">${I}</span>` : null}
600
+ </a>
601
+ `;
602
+ }
603
+ var me = Object.defineProperty, ve = Object.getOwnPropertyDescriptor, x = (e, t, i, o) => {
604
+ for (var a = o > 1 ? void 0 : o ? ve(t, i) : t, s = e.length - 1, r; s >= 0; s--)
605
+ (r = e[s]) && (a = (o ? r(t, i, a) : r(a)) || a);
606
+ return o && a && me(t, i, a), a;
607
+ };
608
+ let g = class extends w {
609
+ constructor() {
610
+ super(...arguments), this.tree = [], this.categoryId = "", this.handleKeyDown = (e) => {
611
+ var t, i;
612
+ if (e.key === "Escape")
613
+ this.handleCloseMegaMenu(!0);
614
+ else if (e.key === "Tab") {
615
+ const o = (t = this.shadowRoot) == null ? void 0 : t.querySelectorAll("a.menu-title, .menu-url");
616
+ if (!o || o.length === 0) return;
617
+ const a = (i = this.shadowRoot) == null ? void 0 : i.activeElement;
618
+ e.shiftKey && a === o[0] ? (e.preventDefault(), this.handleCloseMegaMenu(!0)) : !e.shiftKey && a === o[o.length - 1] && (e.preventDefault(), o[0].focus());
619
+ }
620
+ };
621
+ }
622
+ connectedCallback() {
623
+ super.connectedCallback(), this.addEventListener("keydown", this.handleKeyDown);
624
+ }
625
+ disconnectedCallback() {
626
+ super.disconnectedCallback(), this.removeEventListener("keydown", this.handleKeyDown);
627
+ }
628
+ get categoryData() {
629
+ return this.tree.find((e) => e.id === this.categoryId);
630
+ }
631
+ /**
632
+ * The close event keeps its name, `bubbles` and `composed` flags; `detail` is
633
+ * new and carries the caller's focus intent onward to `<cm-side-nav>`'s
634
+ * `dismissFlyout()`, which is the one place the focus rule is applied. Both
635
+ * keyboard paths ask for restoration — they are the paths where focus is inside
636
+ * the flyout and would otherwise be dropped on the document body. The close
637
+ * button asks too; it is harmless when focus is not inside, because
638
+ * `dismissFlyout` only moves focus that actually sits in the flyout.
639
+ */
640
+ handleCloseMegaMenu(e = !0) {
641
+ this.dispatchEvent(
642
+ new CustomEvent("cm-mega-menu-close", {
643
+ detail: { restoreFocus: e },
644
+ bubbles: !0,
645
+ composed: !0,
646
+ cancelable: !0
647
+ })
648
+ );
649
+ }
650
+ /**
651
+ * Packs menu items into as many 248px columns as the container's own
652
+ * measured height allows. The `getBoundingClientRect()` calls below are
653
+ * this component measuring its own shadow root, not a sibling, so they
654
+ * don't trip the one rule. The `window.innerWidth <= 1150` gate is a
655
+ * different thing and does not get the same pass: it's a page-viewport
656
+ * read uncorrelated with this component's actual available width, kept
657
+ * only because it's what upstream gated on. `window.innerWidth` is 1024
658
+ * under jsdom, so this early return fires on every test run and the
659
+ * packing logic below it was, until the test added for this floor,
660
+ * unexercised by the suite.
661
+ */
662
+ setMenuItemsContainerWidth() {
663
+ var a;
664
+ const e = (a = this.shadowRoot) == null ? void 0 : a.querySelector(".menu-items");
665
+ if (!e || window.innerWidth <= 1150) return;
666
+ const t = e.getBoundingClientRect().height - 20;
667
+ let i = 1, o = 0;
668
+ for (const s of e.children)
669
+ o + s.getBoundingClientRect().height + 12 > // 12 for bottom margin on item
670
+ t && (i += 1, o = 0), o += s.getBoundingClientRect().height + 12;
671
+ e.style.width = `${i * E + (i + 1) * T}px`;
672
+ }
673
+ updated(e) {
674
+ super.updated(e), this.setMenuItemsContainerWidth();
675
+ }
676
+ render() {
677
+ const e = this.categoryData, t = e ? d(e) : [];
678
+ return !e || t.length === 0 ? null : n`
679
+ <section class="mega-menu">
680
+ <div class="header">
681
+ <div class="header-left">
682
+ <div class="header-icon">${de(e)}</div>
683
+ <p class="header-title title-text">${e.label}</p>
684
+ </div>
685
+ <p class="close-button" @click=${() => this.handleCloseMegaMenu(!0)}>
686
+ ${z()}
687
+ </p>
688
+ </div>
689
+ <div class="menu-items">
690
+ ${t.map(
691
+ (i) => n`
692
+ <div class="menu-item">
693
+ ${// Deliberate addition, not upstream parity — core-js's
694
+ // `sub_categories[]` never carried a `url`, so there's no parity to
695
+ // break. `MenuSubCategory.href?` lets a sub-category be a direct
696
+ // link, and `isRenderableSubCategory` (`Utils/helpers.ts`) already
697
+ // keeps such a node alive when it has no items. Rendering only
698
+ // `sub.items` left that node's header going nowhere — no live case
699
+ // in `campminder.json` today, but Floor 6's visibility filter can
700
+ // produce one: an `href`-bearing sub-category whose every leaf is
701
+ // gated off for the viewer.
702
+ i.href ? n`<a class="title-text menu-title" href="${i.href}">${i.label}</a>` : n`<p class="title-text menu-title">${i.label}</p>`}
703
+ ${i.items.map((o) => B(o))}
704
+ </div>
705
+ `
706
+ )}
707
+ </div>
708
+ </section>
709
+ `;
710
+ }
711
+ };
712
+ g.styles = [X];
713
+ x([
714
+ h({ attribute: !1 })
715
+ ], g.prototype, "tree", 2);
716
+ x([
717
+ h({ type: String, attribute: "category-id" })
718
+ ], g.prototype, "categoryId", 2);
719
+ g = x([
720
+ y("cm-mega-menu")
721
+ ], g);
722
+ const fe = b`
359
723
  :host {
360
- /* '--cm-side-nav-width' is set on 'campminder-app-shell''s ':host'
361
- * (packages/campminder/src/layout.ts is the source of truth) and
362
- * pierces the shadow boundary, so it's readable here even though this
363
- * package is portal-agnostic. It also switches to the collapsed
364
- * width, which a literal '168px' can't — the fallback below is only
365
- * for standalone rendering with no shell present.
366
- * '100vw' is correct for production, where the shell fills the
367
- * viewport and the nav starts at x=0; it reads over-wide in this
368
- * harness only because the harness page has a 24px inset the shell
369
- * doesn't have — a harness-geometry artifact, not a formula bug. */
370
- --cm-mega-menu-max-width: calc(100vw - var(--cm-side-nav-width, 168px));
724
+ /* The mobile drill-down is rendered inside '<cm-side-nav>'s shadow root, so
725
+ * it would inherit this anyway. Declaring it keeps the panel's typeface a
726
+ * property of the panel — it survives being reparented or slotted later —
727
+ * and cannot drift from the side nav's value, because both resolve the one
728
+ * 'SHELL_FONT_FAMILY' constant. Rationale: '../shell-tokens.ts'. */
729
+ --font-family: ${C};
371
730
  }
372
731
 
373
- /* ===== CSS RESET ===== */
374
732
  * {
375
733
  margin: 0;
376
734
  padding: 0;
377
735
  box-sizing: border-box;
378
736
  }
379
737
 
380
- /* ===== ANIMATIONS ===== */
381
- @keyframes fadeIn {
382
- from {
383
- opacity: 0;
384
- }
385
- to {
386
- opacity: 1;
387
- }
388
- }
389
-
390
- /* ===== MEGA MENU CONTAINER ===== */
391
- .mega-menu {
392
- position: absolute;
393
- left: 100%;
394
- top: 0;
395
- max-width: var(--cm-mega-menu-max-width);
738
+ .mega-menu-mobile {
396
739
  height: 100%;
397
- border-radius: 4px;
740
+ display: flex;
741
+ flex-direction: column;
398
742
  background: #fff;
399
- box-shadow: 0px 2px 16px 0px rgba(0, 0, 0, 0.12);
400
- animation: fadeIn 0.5s ease;
401
743
  }
402
744
 
403
- /* ===== HEADER SECTION ===== */
404
745
  .header {
405
746
  display: flex;
406
747
  align-items: center;
407
- justify-content: space-between;
748
+ gap: 8px;
408
749
  color: #505050;
409
750
  border-bottom: 1px solid rgba(160, 160, 160, 1);
410
- margin: 0 16px;
751
+ padding: 0 16px;
411
752
  height: 56px;
753
+ flex-shrink: 0;
412
754
  }
413
755
 
414
- .header-left {
415
- display: flex;
416
- align-items: center;
417
- }
418
-
419
- .header-title {
420
- display: grid;
421
- place-content: center;
422
- }
423
-
424
- .header-icon {
425
- margin-right: 8px;
426
- display: flex;
427
- justify-content: center;
428
- align-items: center;
429
- }
430
-
431
- /* ===== CLOSE BUTTON ===== */
432
- .close-button {
756
+ .back-button {
433
757
  display: flex;
434
758
  width: 24px;
435
759
  height: 24px;
436
760
  justify-content: center;
437
761
  align-items: center;
762
+ border: none;
763
+ background: transparent;
438
764
  border-radius: 4px;
439
765
  cursor: pointer;
440
766
  transition: background 0.2s ease;
441
767
  }
442
768
 
443
- .close-button:hover {
769
+ .back-button:hover,
770
+ .back-button:focus-visible {
444
771
  background: rgba(119, 61, 189, 0.12);
445
772
  }
446
773
 
447
- /* ===== TYPOGRAPHY ===== */
774
+ .back-icon {
775
+ display: flex;
776
+ transform: rotate(180deg);
777
+ }
778
+
779
+ .header-title {
780
+ display: grid;
781
+ place-content: center;
782
+ }
783
+
448
784
  .title-text {
449
785
  color: #505050;
450
- font-family: 'Inter', sans-serif;
786
+ font-family: var(--font-family);
451
787
  font-size: 16px;
452
788
  font-weight: 600;
453
789
  line-height: 24px;
454
790
  letter-spacing: 0.0025em;
455
791
  }
456
792
 
457
- /* ===== MENU ITEMS CONTAINER ===== */
458
793
  .menu-items {
459
- height: calc(100% - 56px);
460
- max-width: var(--cm-mega-menu-max-width);
461
- display: flex;
462
- flex-flow: column wrap;
463
- padding: 10px 16px 10px 0px;
794
+ flex: 1;
464
795
  overflow: auto;
796
+ padding: 10px 16px;
465
797
  }
466
798
 
467
- /* ===== MENU ITEM ===== */
468
799
  .menu-item {
469
- width: ${M}px;
470
- margin-left: ${V}px;
471
800
  margin-bottom: 12px;
472
- font-family: 'Inter', sans-serif;
801
+ font-family: var(--font-family);
473
802
  font-size: 14px;
474
803
  font-weight: 400;
475
804
  line-height: 20px;
@@ -478,17 +807,19 @@ const b = (e) => e ?? I, S = t` <svg
478
807
 
479
808
  .menu-title {
480
809
  display: flex;
481
- width: 248px;
482
- padding: 4px 12px;
810
+ width: 100%;
811
+ padding: 8px 12px;
483
812
  align-items: center;
484
813
  gap: 8px;
814
+ background: var(--color-section-bg, rgba(0, 0, 0, 0.04));
815
+ border-radius: 4px;
816
+ margin-bottom: 4px;
485
817
  }
486
818
 
487
- /* ===== MENU LINKS ===== */
488
819
  .menu-url {
489
820
  display: flex;
490
821
  align-items: center;
491
- width: 248px;
822
+ width: 100%;
492
823
  min-height: 32px;
493
824
  padding: 6px 12px;
494
825
  border-radius: 4px;
@@ -509,74 +840,23 @@ const b = (e) => e ?? I, S = t` <svg
509
840
  display: grid;
510
841
  place-content: center;
511
842
  }
512
-
513
- /* ===== RESPONSIVE ===== */
514
- @media (max-width: 1150px) {
515
- .menu-items {
516
- flex-wrap: nowrap;
517
- }
518
- }
519
- `, y = {
520
- AccountsSvgIcon: j,
521
- AdminSvgIcon: F,
522
- AlumniSvgIcon: K,
523
- CamperSvgIcon: Y,
524
- CommunicationSvgIcon: q,
525
- CampInTouchSvgIcon: W,
526
- FinancialSvgIcon: X,
527
- MedicalSvgIcon: J,
528
- ReportingSvgIcon: Q,
529
- SchedulingSvgIcon: e1,
530
- StaffSvgIcon: t1,
531
- TravelSvgIcon: o1
843
+ `;
844
+ var Ce = Object.defineProperty, be = Object.getOwnPropertyDescriptor, M = (e, t, i, o) => {
845
+ for (var a = o > 1 ? void 0 : o ? be(t, i) : t, s = e.length - 1, r; s >= 0; s--)
846
+ (r = e[s]) && (a = (o ? r(t, i, a) : r(a)) || a);
847
+ return o && a && Ce(t, i, a), a;
532
848
  };
533
- function n1(e) {
534
- return e ? e.id === "home" ? H : y[`${e.label}SvgIcon`] ?? u : u;
535
- }
536
- function w1(e) {
537
- return e ? e.id === "home" ? !0 : `${e.label}SvgIcon` in y : !1;
538
- }
539
- function d(e) {
540
- return e.startsWith("http") ? new URL(e).pathname + new URL(e).search : e;
541
- }
542
- function s1(e, o) {
543
- const n = d(o);
544
- for (const i of e) {
545
- if (i.href && d(i.href) === n)
546
- return i.id;
547
- for (const s of i.subCategories)
548
- if (s.href && d(s.href) === n || s.items.find((a) => d(a.href) === n)) return i.id;
549
- }
550
- }
551
- function r1(e) {
552
- return e.items.length > 0 || !!e.href;
553
- }
554
- function C(e) {
555
- return e.subCategories.filter(r1);
556
- }
557
- function a1(e, o) {
558
- const n = e.find((i) => i.id === o);
559
- return !!n && C(n).length > 0;
560
- }
561
- function l1(e, o) {
562
- return o === "/" ? "home" : s1(e, o) ?? "";
563
- }
564
- var h1 = Object.defineProperty, c1 = Object.getOwnPropertyDescriptor, v = (e, o, n, i) => {
565
- for (var s = i > 1 ? void 0 : i ? c1(o, n) : o, r = e.length - 1, a; r >= 0; r--)
566
- (a = e[r]) && (s = (i ? a(o, n, s) : a(s)) || s);
567
- return i && s && h1(o, n, s), s;
568
- };
569
- let h = class extends m {
849
+ let u = class extends w {
570
850
  constructor() {
571
851
  super(...arguments), this.tree = [], this.categoryId = "", this.handleKeyDown = (e) => {
572
- var o, n;
852
+ var t, i;
573
853
  if (e.key === "Escape")
574
- this.handleCloseMegaMenu();
854
+ e.stopPropagation(), this.handleBack();
575
855
  else if (e.key === "Tab") {
576
- const i = (o = this.shadowRoot) == null ? void 0 : o.querySelectorAll("a.menu-title, .menu-url");
577
- if (!i || i.length === 0) return;
578
- const s = (n = this.shadowRoot) == null ? void 0 : n.activeElement;
579
- e.shiftKey && s === i[0] ? (e.preventDefault(), this.handleCloseMegaMenu()) : !e.shiftKey && s === i[i.length - 1] && (e.preventDefault(), i[0].focus());
856
+ const o = (t = this.shadowRoot) == null ? void 0 : t.querySelectorAll(".back-button, a.menu-title, .menu-url");
857
+ if (!o || o.length === 0) return;
858
+ const a = (i = this.shadowRoot) == null ? void 0 : i.activeElement;
859
+ e.shiftKey && a === o[0] ? (e.preventDefault(), e.stopPropagation(), this.handleBack()) : !e.shiftKey && a === o[o.length - 1] && (e.preventDefault(), e.stopPropagation(), o[0].focus());
580
860
  }
581
861
  };
582
862
  }
@@ -589,97 +869,44 @@ let h = class extends m {
589
869
  get categoryData() {
590
870
  return this.tree.find((e) => e.id === this.categoryId);
591
871
  }
592
- handleCloseMegaMenu() {
872
+ /**
873
+ * Requests the host go back to the main mobile menu list. Named `-back`, not
874
+ * `-close`, because it does not dismiss the mobile overlay itself — only
875
+ * `<cm-side-nav>`'s own toggle/backdrop does that (see its doc comment).
876
+ */
877
+ handleBack() {
593
878
  this.dispatchEvent(
594
- new CustomEvent("cm-mega-menu-close", {
879
+ new CustomEvent("cm-mega-menu-mobile-back", {
595
880
  bubbles: !0,
596
- composed: !0,
597
- cancelable: !0
881
+ composed: !0
598
882
  })
599
883
  );
600
884
  }
601
885
  /**
602
- * Packs menu items into as many 248px columns as the container's own
603
- * measured height allows. The `getBoundingClientRect()` calls below are
604
- * this component measuring its own shadow root, not a sibling, so they
605
- * don't trip the one rule. The `window.innerWidth <= 1150` gate is a
606
- * different thing and does not get the same pass: it's a page-viewport
607
- * read uncorrelated with this component's actual available width, kept
608
- * only because it's what upstream gated on. `window.innerWidth` is 1024
609
- * under jsdom, so this early return fires on every test run and the
610
- * packing logic below it was, until the test added for this floor,
611
- * unexercised by the suite.
886
+ * Required, not decorative: drilling in removes the category button focus
887
+ * was on from the DOM (it belonged to the main list, now unmounted), so
888
+ * without this, focus is dropped onto the document body.
612
889
  */
613
- setMenuItemsContainerWidth() {
614
- var s;
615
- const e = (s = this.shadowRoot) == null ? void 0 : s.querySelector(".menu-items");
616
- if (!e || window.innerWidth <= 1150) return;
617
- const o = e.getBoundingClientRect().height - 20;
618
- let n = 1, i = 0;
619
- for (const r of e.children)
620
- i + r.getBoundingClientRect().height + 12 > // 12 for bottom margin on item
621
- o && (n += 1, i = 0), i += r.getBoundingClientRect().height + 12;
622
- e.style.width = `${n * M + (n + 1) * V}px`;
623
- }
624
- updated(e) {
625
- super.updated(e), this.setMenuItemsContainerWidth();
626
- }
627
- // 2026-09-04: `label` may carry an unresolved `{{Bunk:Proper:Default}}`-style
628
- // terminology token, on both a sub-category header and a leaf. Rendered
629
- // verbatim below on purpose — see AGENTS.md's "Never resolve a terminology
630
- // token."
631
- renderLeaf(e) {
632
- return e.popup ? t`
633
- <a
634
- class="menu-url"
635
- href="#nowhere"
636
- @click=${() => {
637
- const o = window.open(e.href, "", e.popupProperties);
638
- return o && (o.opener = null), !1;
639
- }}
640
- target="_top"
641
- >
642
- ${e.label}
643
- <span class="new-tab-icon">${w}</span>
644
- </a>
645
- ` : t`
646
- <a
647
- class="menu-url"
648
- href="${e.href}"
649
- target=${e.newTab ? "_blank" : "_self"}
650
- rel=${b(e.newTab ? "noopener noreferrer" : void 0)}
651
- >
652
- ${e.label}
653
- ${e.newTab ? t`<span class="new-tab-icon">${w}</span>` : null}
654
- </a>
655
- `;
890
+ firstUpdated() {
891
+ var e, t;
892
+ (t = (e = this.shadowRoot) == null ? void 0 : e.querySelector(".back-button")) == null || t.focus();
656
893
  }
657
894
  render() {
658
- const e = this.categoryData, o = e ? C(e) : [];
659
- return !e || o.length === 0 ? null : t`
660
- <section class="mega-menu">
895
+ const e = this.categoryData, t = e ? d(e) : [];
896
+ return !e || t.length === 0 ? null : n`
897
+ <section class="mega-menu-mobile">
661
898
  <div class="header">
662
- <div class="header-left">
663
- <div class="header-icon">${n1(e)}</div>
664
- <p class="header-title title-text">${e.label}</p>
665
- </div>
666
- <p class="close-button" @click=${this.handleCloseMegaMenu}>${k()}</p>
899
+ <button class="back-button" @click=${() => this.handleBack()} aria-label="Back">
900
+ <span class="back-icon">${$}</span>
901
+ </button>
902
+ <p class="header-title title-text">${e.label}</p>
667
903
  </div>
668
904
  <div class="menu-items">
669
- ${o.map(
670
- (n) => t`
905
+ ${t.map(
906
+ (i) => n`
671
907
  <div class="menu-item">
672
- ${// Deliberate addition, not upstream parity — core-js's
673
- // `sub_categories[]` never carried a `url`, so there's no parity to
674
- // break. `MenuSubCategory.href?` lets a sub-category be a direct
675
- // link, and `isRenderableSubCategory` (`Utils/helpers.ts`) already
676
- // keeps such a node alive when it has no items. Rendering only
677
- // `sub.items` left that node's header going nowhere — no live case
678
- // in `campminder.json` today, but Floor 6's visibility filter can
679
- // produce one: an `href`-bearing sub-category whose every leaf is
680
- // gated off for the viewer.
681
- n.href ? t`<a class="title-text menu-title" href="${n.href}">${n.label}</a>` : t`<p class="title-text menu-title">${n.label}</p>`}
682
- ${n.items.map((i) => this.renderLeaf(i))}
908
+ ${i.href ? n`<a class="title-text menu-title" href="${i.href}">${i.label}</a>` : n`<p class="title-text menu-title">${i.label}</p>`}
909
+ ${i.items.map((o) => B(o))}
683
910
  </div>
684
911
  `
685
912
  )}
@@ -688,17 +915,17 @@ let h = class extends m {
688
915
  `;
689
916
  }
690
917
  };
691
- h.styles = [i1];
692
- v([
693
- c({ attribute: !1 })
694
- ], h.prototype, "tree", 2);
695
- v([
696
- c({ type: String, attribute: "category-id" })
697
- ], h.prototype, "categoryId", 2);
698
- h = v([
699
- x("cm-mega-menu")
700
- ], h);
701
- const g1 = f`
918
+ u.styles = [fe];
919
+ M([
920
+ h({ attribute: !1 })
921
+ ], u.prototype, "tree", 2);
922
+ M([
923
+ h({ type: String, attribute: "category-id" })
924
+ ], u.prototype, "categoryId", 2);
925
+ u = M([
926
+ y("cm-mega-menu-mobile")
927
+ ], u);
928
+ const we = b`
702
929
  /* ===== CSS CUSTOM PROPERTIES (DESIGN TOKENS) ===== */
703
930
  :host {
704
931
  display: block;
@@ -732,7 +959,12 @@ const g1 = f`
732
959
  --easing-exit: cubic-bezier(0.4, 0, 0.2, 1);
733
960
 
734
961
  /* Typography tokens */
735
- --font-family: 'Inter', sans-serif;
962
+ /* Every text rule below reads this. The shell hardcoded 'Inter' until
963
+ * AB#27079 while nothing in this repo ever loaded Inter, so the chrome
964
+ * silently rendered in the browser's default sans-serif next to a host
965
+ * showing General Sans. The fallback chain and why it must stay a read-only
966
+ * var() live on 'SHELL_FONT_FAMILY' in '../shell-tokens.ts'. */
967
+ --font-family: ${C};
736
968
  --font-size-base: 14px;
737
969
  --font-size-medium: 15px;
738
970
  --font-size-large: 16px;
@@ -764,13 +996,13 @@ const g1 = f`
764
996
  box-sizing: border-box;
765
997
  }
766
998
 
767
- /* ===== MENU TOGGLE BUTTON (mobile; unused until Floor 5D, kept for parity) ===== */
999
+ /* ===== MENU TOGGLE BUTTON (mobile) ===== */
768
1000
  .menu-toggle {
769
1001
  width: var(--sidebar-header-height);
770
1002
  height: var(--sidebar-header-height);
771
1003
  cursor: pointer;
772
1004
  display: none;
773
- background: white;
1005
+ background: var(--color-bg-gradient);
774
1006
  border: none;
775
1007
  border-bottom: 1px solid var(--color-border-gray);
776
1008
  justify-content: center;
@@ -782,6 +1014,74 @@ const g1 = f`
782
1014
  height: var(--icon-size-base);
783
1015
  }
784
1016
 
1017
+ /* ===== MOBILE NAV (Floor 5D) ===== */
1018
+ .mobile-nav {
1019
+ display: none;
1020
+ position: relative;
1021
+ }
1022
+
1023
+ .mobile-overlay-backdrop {
1024
+ position: fixed;
1025
+ inset: 0;
1026
+ background: var(--color-backdrop);
1027
+ }
1028
+
1029
+ .mobile-overlay-menu {
1030
+ position: fixed;
1031
+ top: 0;
1032
+ left: 0;
1033
+ width: var(--overlay-menu-width);
1034
+ max-width: var(--overlay-menu-max-width);
1035
+ height: 100%;
1036
+ background: var(--color-bg-gradient);
1037
+ color: var(--color-text);
1038
+ /* Deliberately not a scroll-lock on document.body (banned, see AGENTS.md's
1039
+ * one rule) — this is the panel's own scroll boundary staying put under
1040
+ * background touch-scroll, the plan's declared, narrower substitute. */
1041
+ overscroll-behavior: contain;
1042
+ overflow: auto;
1043
+ }
1044
+
1045
+ .mobile-categories-container,
1046
+ .mobile-categories-list {
1047
+ list-style: none;
1048
+ margin: 0;
1049
+ padding: 0;
1050
+ }
1051
+
1052
+ .mobile-categories-list li {
1053
+ display: contents;
1054
+ }
1055
+
1056
+ .mobile-category {
1057
+ width: 100%;
1058
+ height: var(--category-height);
1059
+ display: flex;
1060
+ align-items: center;
1061
+ border: none;
1062
+ border-bottom: 1px solid var(--color-border);
1063
+ background: transparent;
1064
+ text-decoration: none;
1065
+ padding: var(--spacing-md);
1066
+ color: var(--color-text);
1067
+ cursor: pointer;
1068
+ font-family: var(--font-family);
1069
+ font-size: var(--font-size-base);
1070
+ font-weight: 400;
1071
+ line-height: var(--line-height-base);
1072
+ letter-spacing: -0.001em;
1073
+ text-align: left;
1074
+ }
1075
+
1076
+ .mobile-category.selected {
1077
+ background: var(--color-selected);
1078
+ }
1079
+
1080
+ .mobile-category:hover,
1081
+ .mobile-category:focus {
1082
+ background: var(--color-hover);
1083
+ }
1084
+
785
1085
  /* ===== NAVIGATION CONTAINER ===== */
786
1086
  .nav-container {
787
1087
  display: flex;
@@ -976,6 +1276,10 @@ const g1 = f`
976
1276
  text-align: left;
977
1277
  }
978
1278
 
1279
+ /* Rendered only by the mobile category list (Floor 5D, AB#26231) — the
1280
+ desktop .category button never emits this markup (see side-nav.test.ts's
1281
+ "no chevron on desktop" regression); the desktop indicator stays
1282
+ .category-hovered::after. */
979
1283
  .chevron-right {
980
1284
  margin-left: auto;
981
1285
  display: flex;
@@ -991,35 +1295,62 @@ const g1 = f`
991
1295
  animation-iteration-count: 1 !important;
992
1296
  }
993
1297
  }
994
- `, L = {
995
- AccountsSvgIcon: S,
996
- AdminSvgIcon: E,
997
- AlumniSvgIcon: T,
998
- CamperSvgIcon: $,
999
- CommunicationSvgIcon: A,
1000
- CampInTouchSvgIcon: B,
1001
- FinancialSvgIcon: O,
1002
- HomeSvgIcon: H,
1003
- MedicalSvgIcon: R,
1004
- ReportingSvgIcon: G,
1005
- SchedulingSvgIcon: P,
1006
- StaffSvgIcon: D,
1007
- TravelSvgIcon: U
1298
+
1299
+ /* ===== MOBILE / DESKTOP VARIANT SWITCH (Floor 5D) =====
1300
+ * Deliberately LAST in this stylesheet. A media query adds no specificity —
1301
+ * it only groups rules that still compete on source order at equal
1302
+ * specificity with anything outside it. This block was originally placed
1303
+ * right after the mobile-only rules it complements (before ".nav-container"'s
1304
+ * own base rule), which put it BEFORE that base rule in source order; the
1305
+ * base rule then won the cascade for ".nav-container" at every viewport,
1306
+ * silently no-opping this block's "display: none" for it. Caught by live
1307
+ * browser measurement 2026-09-17 — see the evidence doc. Keeping this block
1308
+ * last guarantees it wins the cascade against every base rule above,
1309
+ * including any added later; do not insert a new base rule after this one. */
1310
+ @media (max-width: ${f}px) {
1311
+ .nav-container {
1312
+ display: none;
1313
+ }
1314
+
1315
+ .mobile-nav {
1316
+ display: block;
1317
+ }
1318
+
1319
+ .menu-toggle {
1320
+ display: flex;
1321
+ }
1322
+ }
1323
+ `, N = {
1324
+ AccountsSvgIcon: R,
1325
+ AdminSvgIcon: D,
1326
+ AlumniSvgIcon: _,
1327
+ CamperSvgIcon: F,
1328
+ CommunicationSvgIcon: G,
1329
+ CampInTouchSvgIcon: P,
1330
+ FinancialSvgIcon: U,
1331
+ HomeSvgIcon: Z,
1332
+ MedicalSvgIcon: K,
1333
+ ReportingSvgIcon: q,
1334
+ SchedulingSvgIcon: Y,
1335
+ StaffSvgIcon: Q,
1336
+ TravelSvgIcon: W
1008
1337
  };
1009
- function d1(e) {
1010
- return e ? L[`${e}SvgIcon`] ?? p : p;
1338
+ function k(e) {
1339
+ return e ? N[`${e}SvgIcon`] ?? H : H;
1011
1340
  }
1012
- function f1(e) {
1013
- return !!e && `${e}SvgIcon` in L;
1341
+ function Ve(e) {
1342
+ return !!e && `${e}SvgIcon` in N;
1014
1343
  }
1015
- var C1 = Object.defineProperty, v1 = Object.getOwnPropertyDescriptor, g = (e, o, n, i) => {
1016
- for (var s = i > 1 ? void 0 : i ? v1(o, n) : o, r = e.length - 1, a; r >= 0; r--)
1017
- (a = e[r]) && (s = (i ? a(o, n, s) : a(s)) || s);
1018
- return i && s && C1(o, n, s), s;
1344
+ var ye = Object.defineProperty, xe = Object.getOwnPropertyDescriptor, c = (e, t, i, o) => {
1345
+ for (var a = o > 1 ? void 0 : o ? xe(t, i) : t, s = e.length - 1, r; s >= 0; s--)
1346
+ (r = e[s]) && (a = (o ? r(t, i, a) : r(a)) || a);
1347
+ return o && a && ye(t, i, a), a;
1019
1348
  };
1020
- let l = class extends m {
1349
+ let l = class extends w {
1021
1350
  constructor() {
1022
- super(...arguments), this.hoveredCategory = "", this.collapsed = !1, this.currentPath = "", this.tree = [], this.toggleSidenav = () => {
1351
+ super(...arguments), this.hoveredCategory = "", this.mobileMenuOpen = !1, this.activeMobileCategoryId = "", this.isNarrowViewport = l.readViewportWidthFallback(), this.collapsed = !1, this.currentPath = "", this.tree = [], this.handleMobileMediaChange = (e) => {
1352
+ this.isNarrowViewport = e.matches;
1353
+ }, this.toggleSidenav = () => {
1023
1354
  this.dispatchEvent(
1024
1355
  new CustomEvent("cm-side-nav-toggle", {
1025
1356
  detail: { collapsed: !this.collapsed },
@@ -1027,6 +1358,18 @@ let l = class extends m {
1027
1358
  composed: !0
1028
1359
  })
1029
1360
  );
1361
+ }, this.handleMobileOverlayKeyDown = (e) => {
1362
+ var t, i;
1363
+ if (!this.openMobileCategory) {
1364
+ if (e.key === "Escape")
1365
+ this.dismissMobileMenu(!0);
1366
+ else if (e.key === "Tab") {
1367
+ const o = (t = this.shadowRoot) == null ? void 0 : t.querySelectorAll(".mobile-overlay-menu .mobile-category");
1368
+ if (!o || o.length === 0) return;
1369
+ const a = (i = this.shadowRoot) == null ? void 0 : i.activeElement;
1370
+ e.shiftKey && a === o[0] ? (e.preventDefault(), o[o.length - 1].focus()) : !e.shiftKey && a === o[o.length - 1] && (e.preventDefault(), o[0].focus());
1371
+ }
1372
+ }
1030
1373
  };
1031
1374
  }
1032
1375
  /**
@@ -1039,10 +1382,24 @@ let l = class extends m {
1039
1382
  * getter needs to cache.
1040
1383
  */
1041
1384
  get selectedCategory() {
1042
- return l1(this.tree, this.currentPath);
1385
+ return pe(this.tree, this.currentPath);
1386
+ }
1387
+ connectedCallback() {
1388
+ super.connectedCallback(), this.initMobileMediaQuery();
1043
1389
  }
1044
1390
  disconnectedCallback() {
1045
- super.disconnectedCallback(), this.clearHoverTimeout();
1391
+ super.disconnectedCallback(), this.clearHoverTimeout(), this.teardownMobileMediaQuery();
1392
+ }
1393
+ /** The fallback used where `matchMedia` is unavailable — see the class doc comment. */
1394
+ static readViewportWidthFallback() {
1395
+ return window.innerWidth <= f;
1396
+ }
1397
+ initMobileMediaQuery() {
1398
+ typeof window.matchMedia == "function" && (this.mobileMediaQuery = window.matchMedia(`(max-width: ${f}px)`), this.isNarrowViewport = this.mobileMediaQuery.matches, this.mobileMediaQuery.addEventListener("change", this.handleMobileMediaChange));
1399
+ }
1400
+ teardownMobileMediaQuery() {
1401
+ var e;
1402
+ (e = this.mobileMediaQuery) == null || e.removeEventListener("change", this.handleMobileMediaChange), this.mobileMediaQuery = void 0;
1046
1403
  }
1047
1404
  setSelectedCategory(e) {
1048
1405
  this.handleMenuItemHover(e);
@@ -1061,26 +1418,173 @@ let l = class extends m {
1061
1418
  handleMouseLeave() {
1062
1419
  this.clearHoverTimeout();
1063
1420
  }
1421
+ /**
1422
+ * The single dismissal entry point for the flyout — every trigger routes through
1423
+ * here (the flyout's own Escape and shift-Tab paths, the nav's mouseleave, and
1424
+ * the shell's page-level Escape / outside pointer press) so the focus rule is
1425
+ * applied in exactly one place and no trigger can bypass it.
1426
+ *
1427
+ * `restoreFocus` is the caller's *intent*; focus only actually moves when it is
1428
+ * also true that focus is currently inside the flyout. A person typing in a form
1429
+ * field while the flyout is dismissed keeps their cursor where it is, and a
1430
+ * pointer press outside keeps the focus the press itself produces.
1431
+ *
1432
+ * The focus target is read BEFORE `hoveredCategory` is cleared, and that order is
1433
+ * load-bearing: the target is found via the `category-hovered` class, which is
1434
+ * derived from `hoveredCategory` in `buildCategoryClass`. Clearing first would
1435
+ * leave nothing to find and silently drop focus onto the document body — the very
1436
+ * defect this method exists to fix.
1437
+ */
1438
+ dismissFlyout(e) {
1439
+ if (!this.openCategory) return;
1440
+ const t = e && this.focusIsInsideFlyout() ? this.focusRestoreTarget() : null;
1441
+ this.clearHoverTimeout(), this.hoveredCategory = "", t == null || t.focus();
1442
+ }
1443
+ focusIsInsideFlyout() {
1444
+ var t, i;
1445
+ const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector("cm-mega-menu");
1446
+ return e ? ((i = e.shadowRoot) == null ? void 0 : i.activeElement) != null : !1;
1447
+ }
1448
+ /**
1449
+ * The category control the flyout was opened from, or the collapse control when
1450
+ * that category control no longer exists — it always does, so focus can never
1451
+ * land on the document body.
1452
+ */
1453
+ focusRestoreTarget() {
1454
+ const e = this.shadowRoot;
1455
+ return e ? e.querySelector(".category-hovered") ?? e.querySelector(".sidebar-toggle") : null;
1456
+ }
1064
1457
  // Utility Methods
1065
1458
  get hamburgerIcon() {
1066
- return this.collapsed ? _ : z;
1459
+ return this.collapsed ? L : j;
1067
1460
  }
1068
1461
  /**
1069
1462
  * The category the mega-menu flyout is open for, or `undefined` when none
1070
1463
  * is. Guards on `renderableSubCategories(category).length > 0` (the same
1071
- * predicate `hasSubmenus` uses for the chevron above) rather than on
1464
+ * predicate `hasSubmenus` uses to render a category as a button) rather than on
1072
1465
  * `hoveredCategory` alone — `hoveredCategory` can also be the literal
1073
1466
  * string `'sidebar-toggle'` (see `handleMouseEnter` call sites), and a
1074
1467
  * category with no renderable sub-categories must not open onto nothing.
1075
1468
  */
1076
1469
  get openCategory() {
1077
- const e = this.tree.find((o) => o.id === this.hoveredCategory);
1078
- if (!(!e || C(e).length === 0))
1470
+ const e = this.tree.find((t) => t.id === this.hoveredCategory);
1471
+ if (!(!e || d(e).length === 0))
1079
1472
  return e;
1080
1473
  }
1081
1474
  buildCategoryClass(e) {
1082
- const o = ["category"];
1083
- return e.id === this.selectedCategory && o.push("selected"), e.id === this.hoveredCategory && o.push("category-hovered"), o.join(" ");
1475
+ const t = ["category"];
1476
+ return e.id === this.selectedCategory && t.push("selected"), e.id === this.hoveredCategory && t.push("category-hovered"), t.join(" ");
1477
+ }
1478
+ /** The category the mobile drill-down is showing, mirroring `openCategory`. */
1479
+ get openMobileCategory() {
1480
+ const e = this.tree.find((t) => t.id === this.activeMobileCategoryId);
1481
+ if (!(!e || d(e).length === 0))
1482
+ return e;
1483
+ }
1484
+ toggleMobileMenu() {
1485
+ if (this.mobileMenuOpen) {
1486
+ this.dismissMobileMenu(!1);
1487
+ return;
1488
+ }
1489
+ this.mobileMenuOpen = !0;
1490
+ }
1491
+ /**
1492
+ * The single dismissal entry point for the mobile overlay — every trigger
1493
+ * (the backdrop click, `.menu-toggle`, the overlay's own Escape) routes
1494
+ * through here, mirroring `dismissFlyout`'s reasoning, so the focus rule is
1495
+ * applied in exactly one place and no trigger can bypass it.
1496
+ *
1497
+ * `restoreFocus` is the caller's intent; focus only actually moves when it is
1498
+ * also true that focus is currently inside the overlay. The target is read
1499
+ * BEFORE state is cleared, same load-bearing order as `dismissFlyout` — the
1500
+ * restore target is `.menu-toggle`, which stays in the DOM regardless of
1501
+ * `mobileMenuOpen`, but focus-inside-overlay is only answerable while the
1502
+ * overlay is still open.
1503
+ */
1504
+ dismissMobileMenu(e) {
1505
+ var i;
1506
+ if (!this.mobileMenuOpen) return;
1507
+ const t = e && this.focusIsInsideMobileOverlay() ? (i = this.shadowRoot) == null ? void 0 : i.querySelector(".menu-toggle") : null;
1508
+ this.mobileMenuOpen = !1, this.activeMobileCategoryId = "", t == null || t.focus();
1509
+ }
1510
+ focusIsInsideMobileOverlay() {
1511
+ var t, i, o, a;
1512
+ const e = (t = this.shadowRoot) == null ? void 0 : t.querySelector(".mobile-overlay-menu");
1513
+ if (!e) return !1;
1514
+ if (this.openMobileCategory) {
1515
+ const s = (i = this.shadowRoot) == null ? void 0 : i.querySelector("cm-mega-menu-mobile");
1516
+ return ((o = s == null ? void 0 : s.shadowRoot) == null ? void 0 : o.activeElement) != null;
1517
+ }
1518
+ return e.contains(((a = this.shadowRoot) == null ? void 0 : a.activeElement) ?? null);
1519
+ }
1520
+ openMobileSubmenu(e) {
1521
+ this.activeMobileCategoryId = e;
1522
+ }
1523
+ async closeMobileSubmenu() {
1524
+ var o;
1525
+ const e = this.activeMobileCategoryId;
1526
+ if (this.activeMobileCategoryId = "", await this.updateComplete, !this.mobileMenuOpen || this.activeMobileCategoryId !== "") return;
1527
+ const t = (o = this.shadowRoot) == null ? void 0 : o.querySelectorAll(".mobile-category"), i = Array.from(t ?? []).find(
1528
+ (a) => a.dataset.categoryId === e
1529
+ );
1530
+ i == null || i.focus();
1531
+ }
1532
+ buildMobileCategoryClass(e) {
1533
+ const t = ["mobile-category"];
1534
+ return e.id === this.selectedCategory && t.push("selected"), t.join(" ");
1535
+ }
1536
+ // 2026-09-17: `category.label` may carry an unresolved `{{Bunk:Proper:Default}}`-style
1537
+ // terminology token — rendered verbatim, same rule as the desktop list above.
1538
+ getMobileCategoryHtml(e) {
1539
+ const t = this.buildMobileCategoryClass(e), i = S(this.tree, e.id), o = k(e.label);
1540
+ return i ? n`
1541
+ <button
1542
+ class="${t}"
1543
+ data-category-id=${e.id}
1544
+ @click=${() => this.openMobileSubmenu(e.id)}
1545
+ >
1546
+ <div class="category-icon">${o}</div>
1547
+ <div class="category-name">${e.label}</div>
1548
+ <span class="chevron-right">${$}</span>
1549
+ </button>
1550
+ ` : n`
1551
+ <a
1552
+ class="${t}"
1553
+ data-category-id=${e.id}
1554
+ href="${v(e.href)}"
1555
+ >
1556
+ <div class="category-icon">${o}</div>
1557
+ <div class="category-name">${e.label}</div>
1558
+ </a>
1559
+ `;
1560
+ }
1561
+ renderMobileMainMenu() {
1562
+ return n`
1563
+ <nav class="mobile-categories-container" role="navigation" aria-label="Main categories">
1564
+ <ul class="mobile-categories-list" role="list">
1565
+ ${this.tree.map(
1566
+ (e) => n` <li role="listitem">${this.getMobileCategoryHtml(e)}</li> `
1567
+ )}
1568
+ </ul>
1569
+ </nav>
1570
+ `;
1571
+ }
1572
+ /**
1573
+ * The mobile overlay's body — either the main category list, or the
1574
+ * drill-down for whichever category is active. `cm-mega-menu-mobile-back`
1575
+ * is the drill-down asking to return to the list; it does not close the
1576
+ * overlay (that's `.menu-toggle` / the backdrop), so it only clears
1577
+ * `activeMobileCategoryId`.
1578
+ */
1579
+ renderMobileOverlayBody() {
1580
+ const e = this.openMobileCategory;
1581
+ return e ? n`
1582
+ <cm-mega-menu-mobile
1583
+ .tree=${this.tree}
1584
+ category-id=${e.id}
1585
+ @cm-mega-menu-mobile-back=${() => this.closeMobileSubmenu()}
1586
+ ></cm-mega-menu-mobile>
1587
+ ` : this.renderMobileMainMenu();
1084
1588
  }
1085
1589
  // 2026-09-02: `category.label` may still carry an unresolved `{{Bunk:Proper:Default}}`-style
1086
1590
  // terminology token — per-client substitution is a host concern, deferred by the plan (see
@@ -1088,50 +1592,50 @@ let l = class extends m {
1088
1592
  // future truncation, tooltip reformat, or `.trim()`/regex touch-up to `category.label` must
1089
1593
  // not assume it is plain text.
1090
1594
  getCategoryHtml(e) {
1091
- const o = this.buildCategoryClass(e), n = a1(this.tree, e.id), i = d1(e.label);
1092
- return n ? t`
1595
+ const t = this.buildCategoryClass(e), i = S(this.tree, e.id), o = k(e.label);
1596
+ return i ? n`
1093
1597
  <button
1094
- class="${o}"
1598
+ class="${t}"
1095
1599
  @mouseenter=${() => this.handleMouseEnter(e.id)}
1096
1600
  @mouseleave=${() => this.handleMouseLeave()}
1097
1601
  @click=${() => this.handleMenuItemHover(e.id)}
1098
1602
  >
1099
- <div class="category-icon">${i}</div>
1603
+ <div class="category-icon">${o}</div>
1100
1604
  <div class="category-name">${e.label}</div>
1101
- <div class="chevron-right">${N}</div>
1102
1605
  </button>
1103
- ` : t`
1606
+ ` : n`
1104
1607
  <a
1105
- class="${o}"
1608
+ class="${t}"
1106
1609
  @mouseenter=${() => this.handleMouseEnter(e.id)}
1107
1610
  @mouseleave=${() => this.handleMouseLeave()}
1108
1611
  @click=${() => this.setSelectedCategory(e.id)}
1109
- href="${b(e.href)}"
1612
+ href="${v(e.href)}"
1110
1613
  >
1111
- <div class="category-icon">${i}</div>
1614
+ <div class="category-icon">${o}</div>
1112
1615
  <div class="category-name">${e.label}</div>
1113
1616
  </a>
1114
1617
  `;
1115
1618
  }
1116
1619
  renderMainMenu() {
1117
- return t`
1620
+ return n`
1118
1621
  <nav class="categories-container" role="navigation" aria-label="Main categories">
1119
1622
  <ul class="categories-list" role="list">
1120
1623
  ${this.tree.map(
1121
- (e) => t` <li role="listitem">${this.getCategoryHtml(e)}</li> `
1624
+ (e) => n` <li role="listitem">${this.getCategoryHtml(e)}</li> `
1122
1625
  )}
1123
1626
  </ul>
1124
1627
  </nav>
1125
1628
  `;
1126
1629
  }
1127
1630
  render() {
1128
- const e = this.openCategory;
1129
- return t`
1631
+ const e = this.openCategory, t = this.isNarrowViewport;
1632
+ return n`
1130
1633
  <nav
1131
1634
  class="nav-container"
1132
1635
  role="navigation"
1133
1636
  aria-label="Main navigation"
1134
- @mouseleave=${() => this.hoveredCategory = ""}
1637
+ aria-hidden=${t ? "true" : "false"}
1638
+ @mouseleave=${() => this.dismissFlyout(!1)}
1135
1639
  >
1136
1640
  <aside
1137
1641
  class=${`side-nav ${this.collapsed ? "collapsed-sidebar" : ""}`}
@@ -1159,40 +1663,90 @@ let l = class extends m {
1159
1663
  from light DOM would have forced hoveredCategory into public API
1160
1664
  and crossed the component's own encapsulation. cm-mega-menu gets
1161
1665
  the whole tree plus the open category's id (never a resolved node —
1162
- see MegaMenu.ts's doc comment). Its close event resets
1163
- hoveredCategory back to '' — it is the derived openCategory getter
1164
- above, not hoveredCategory itself, that becomes undefined.
1666
+ see MegaMenu.ts's doc comment). Its close event routes through
1667
+ dismissFlyout(), the one dismissal entry point, carrying whether
1668
+ focus should be restored. That resets hoveredCategory back to ''
1669
+ — it is the derived openCategory getter above, not hoveredCategory
1670
+ itself, that becomes undefined.
1165
1671
  -->
1166
- ${e ? t`
1672
+ ${e ? n`
1167
1673
  <cm-mega-menu
1168
1674
  .tree=${this.tree}
1169
1675
  category-id=${e.id}
1170
- @cm-mega-menu-close=${() => this.hoveredCategory = ""}
1676
+ @cm-mega-menu-close=${(i) => {
1677
+ var o;
1678
+ return this.dismissFlyout(((o = i.detail) == null ? void 0 : o.restoreFocus) ?? !1);
1679
+ }}
1171
1680
  ></cm-mega-menu>
1172
1681
  ` : null}
1173
1682
  </nav>
1683
+
1684
+ <!--
1685
+ Floor 5D's mobile variant — a second, always-rendered DOM tree, per the
1686
+ plan's ruling: both variants render and SideNavStyles's
1687
+ @media (max-width: 530px) picks which is displayed. aria-hidden above
1688
+ mirrors that same breakpoint so the inactive tree is hidden from
1689
+ assistive technology too, not just visually — see this file's header.
1690
+ -->
1691
+ <div class="mobile-nav" aria-hidden=${t ? "false" : "true"}>
1692
+ <button
1693
+ class="menu-toggle"
1694
+ @click=${() => this.toggleMobileMenu()}
1695
+ aria-label="Toggle menu"
1696
+ aria-expanded=${this.mobileMenuOpen ? "true" : "false"}
1697
+ >
1698
+ <span class="toggle-mobile-btn">${L}</span>
1699
+ </button>
1700
+
1701
+ ${this.mobileMenuOpen ? n`
1702
+ <div
1703
+ class="mobile-overlay-backdrop"
1704
+ @click=${() => this.dismissMobileMenu(!1)}
1705
+ ></div>
1706
+ <!--
1707
+ Focus is deliberately NOT moved into the overlay here when it
1708
+ first opens. .menu-toggle stays in the DOM and keeps focus,
1709
+ and this overlay renders after the toggle in DOM order, so Tab
1710
+ reaches the list naturally — nothing is lost, so moving focus
1711
+ would be unsolicited. Leaving this note so the next person
1712
+ does not "fix" it.
1713
+ -->
1714
+ <div class="mobile-overlay-menu" @keydown=${this.handleMobileOverlayKeyDown}>
1715
+ ${this.renderMobileOverlayBody()}
1716
+ </div>
1717
+ ` : null}
1718
+ </div>
1174
1719
  `;
1175
1720
  }
1176
1721
  };
1177
- l.styles = [g1];
1178
- g([
1179
- Z()
1722
+ l.styles = [we];
1723
+ c([
1724
+ m()
1180
1725
  ], l.prototype, "hoveredCategory", 2);
1181
- g([
1182
- c({ type: Boolean, reflect: !0 })
1726
+ c([
1727
+ m()
1728
+ ], l.prototype, "mobileMenuOpen", 2);
1729
+ c([
1730
+ m()
1731
+ ], l.prototype, "activeMobileCategoryId", 2);
1732
+ c([
1733
+ m()
1734
+ ], l.prototype, "isNarrowViewport", 2);
1735
+ c([
1736
+ h({ type: Boolean, reflect: !0 })
1183
1737
  ], l.prototype, "collapsed", 2);
1184
- g([
1185
- c({ type: String, attribute: "current-path" })
1738
+ c([
1739
+ h({ type: String, attribute: "current-path" })
1186
1740
  ], l.prototype, "currentPath", 2);
1187
- g([
1188
- c({ attribute: !1 })
1741
+ c([
1742
+ h({ attribute: !1 })
1189
1743
  ], l.prototype, "tree", 2);
1190
- l = g([
1191
- x("cm-side-nav")
1744
+ l = c([
1745
+ y("cm-side-nav")
1192
1746
  ], l);
1193
1747
  export {
1194
- h as MegaMenu,
1748
+ g as MegaMenu,
1195
1749
  l as SideNav,
1196
- f1 as hasIconFor,
1197
- w1 as hasMegaMenuIconFor
1750
+ Ve as hasIconFor,
1751
+ Le as hasMegaMenuIconFor
1198
1752
  };