@campminder/components 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/side-nav.js CHANGED
@@ -1,11 +1,11 @@
1
- import { A as I, b as o, i as f, n as c, a as m, t as b } from "./property-B5JHHBCF.js";
2
- import { r as S } 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 x = (e) => e ?? I, Z = o` <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 x = (e) => e ?? I, Z = o` <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>`, T = o`<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 x = (e) => e ?? I, Z = o` <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> `, E = o`<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 x = (e) => e ?? I, Z = o` <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> `, $ = o`<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 x = (e) => e ?? I, Z = o` <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 = o`<svg
52
+ </svg>`, P = n`<svg
53
53
  width="20"
54
54
  height="20"
55
55
  viewBox="0 0 20 20"
@@ -60,8 +60,7 @@ const x = (e) => e ?? I, Z = o` <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>`;
64
- o`<svg
63
+ </svg>`, $ = n`<svg
65
64
  width="8"
66
65
  height="12"
67
66
  viewBox="0 0 8 12"
@@ -72,8 +71,7 @@ o`<svg
72
71
  d="M1.70687 0L0.296875 1.41L4.87687 6L0.296875 10.59L1.70687 12L7.70687 6L1.70687 0Z"
73
72
  fill="white"
74
73
  />
75
- </svg>`;
76
- const k = (e = "#505050") => o`<svg
74
+ </svg>`, z = (e = "#505050") => n`<svg
77
75
  width="14"
78
76
  height="14"
79
77
  viewBox="0 0 14 14"
@@ -84,7 +82,7 @@ const k = (e = "#505050") => o`<svg
84
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"
85
83
  fill="${e}"
86
84
  />
87
- </svg>`, A = o`<svg
85
+ </svg>`, G = n`<svg
88
86
  width="20"
89
87
  height="20"
90
88
  viewBox="0 0 20 20"
@@ -95,7 +93,7 @@ const k = (e = "#505050") => o`<svg
95
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"
96
94
  fill="white"
97
95
  />
98
- </svg> `, v = o`<svg
96
+ </svg> `, H = n`<svg
99
97
  width="20"
100
98
  height="20"
101
99
  viewBox="0 0 20 20"
@@ -106,7 +104,7 @@ const k = (e = "#505050") => o`<svg
106
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"
107
105
  fill="white"
108
106
  />
109
- </svg> `, N = o`<svg
107
+ </svg> `, U = n`<svg
110
108
  width="20"
111
109
  height="20"
112
110
  viewBox="0 0 20 20"
@@ -117,7 +115,7 @@ const k = (e = "#505050") => o`<svg
117
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"
118
116
  fill="white"
119
117
  />
120
- </svg>`, H = o`<svg
118
+ </svg>`, Z = n`<svg
121
119
  width="20"
122
120
  height="20"
123
121
  viewBox="0 0 20 20"
@@ -128,7 +126,7 @@ const k = (e = "#505050") => o`<svg
128
126
  d="M8.33332 17.0832V12.0832H11.6667V17.0832H15.8333V10.4165H18.3333L9.99999 2.9165L1.66666 10.4165H4.16666V17.0832H8.33332Z"
129
127
  fill="white"
130
128
  />
131
- </svg>`, O = o`<svg
129
+ </svg>`, K = n`<svg
132
130
  width="20"
133
131
  height="20"
134
132
  viewBox="0 0 20 20"
@@ -139,7 +137,7 @@ const k = (e = "#505050") => o`<svg
139
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"
140
138
  fill="white"
141
139
  />
142
- </svg> `, R = o` <svg
140
+ </svg> `, j = n` <svg
143
141
  width="24"
144
142
  height="24"
145
143
  viewBox="0 0 24 24"
@@ -150,7 +148,7 @@ const k = (e = "#505050") => o`<svg
150
148
  d="M3 18H16V16H3V18ZM3 13H13V11H3V13ZM3 6V8H16V6H3ZM21 15.59L17.42 12L21 8.41L19.59 7L14.59 12L19.59 17L21 15.59Z"
151
149
  fill="white"
152
150
  />
153
- </svg>`, z = o`<svg
151
+ </svg>`, L = n`<svg
154
152
  width="24"
155
153
  height="24"
156
154
  viewBox="0 0 24 24"
@@ -158,7 +156,7 @@ const k = (e = "#505050") => o`<svg
158
156
  xmlns="http://www.w3.org/2000/svg"
159
157
  >
160
158
  <path d="M3 18H21V16H3V18ZM3 13H21V11H3V13ZM3 6V8H21V6H3Z" fill="white" />
161
- </svg>`, _ = o`<svg
159
+ </svg>`, q = n`<svg
162
160
  width="20"
163
161
  height="20"
164
162
  viewBox="0 0 20 20"
@@ -169,7 +167,7 @@ const k = (e = "#505050") => o`<svg
169
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"
170
168
  fill="white"
171
169
  />
172
- </svg>`, G = o`<svg
170
+ </svg>`, Y = n`<svg
173
171
  width="20"
174
172
  height="20"
175
173
  viewBox="0 0 20 20"
@@ -180,7 +178,7 @@ const k = (e = "#505050") => o`<svg
180
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"
181
179
  fill="white"
182
180
  />
183
- </svg> `, P = o`<svg
181
+ </svg> `, Q = n`<svg
184
182
  width="20"
185
183
  height="20"
186
184
  viewBox="0 0 20 20"
@@ -191,7 +189,7 @@ const k = (e = "#505050") => o`<svg
191
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"
192
190
  fill="white"
193
191
  />
194
- </svg> `, D = o`<svg
192
+ </svg> `, W = n`<svg
195
193
  width="20"
196
194
  height="20"
197
195
  viewBox="0 0 20 20"
@@ -202,7 +200,183 @@ const k = (e = "#505050") => o`<svg
202
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"
203
201
  fill="white"
204
202
  />
205
- </svg> `, F = o`<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
206
380
  width="24"
207
381
  height="24"
208
382
  viewBox="0 0 24 24"
@@ -213,7 +387,7 @@ const k = (e = "#505050") => o`<svg
213
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"
214
388
  fill="#505050"
215
389
  />
216
- </svg>`, U = o`<svg
390
+ </svg>`, ee = n`<svg
217
391
  width="24"
218
392
  height="24"
219
393
  viewBox="0 0 24 24"
@@ -224,7 +398,7 @@ const k = (e = "#505050") => o`<svg
224
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"
225
399
  fill="#505050"
226
400
  />
227
- </svg>`, j = o`<svg
401
+ </svg>`, te = n`<svg
228
402
  width="24"
229
403
  height="24"
230
404
  viewBox="0 0 24 24"
@@ -235,7 +409,7 @@ const k = (e = "#505050") => o`<svg
235
409
  d="M5 13.18V17.18L12 21L19 17.18V13.18L12 17L5 13.18ZM12 3L1 9L12 15L21 10.09V17H23V9L12 3Z"
236
410
  fill="#505050"
237
411
  />
238
- </svg>`, K = o`<svg
412
+ </svg>`, oe = n`<svg
239
413
  width="24"
240
414
  height="24"
241
415
  viewBox="0 0 24 24"
@@ -246,7 +420,7 @@ const k = (e = "#505050") => o`<svg
246
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"
247
421
  fill="#505050"
248
422
  />
249
- </svg>`, Y = o`<svg
423
+ </svg>`, ie = n`<svg
250
424
  width="20"
251
425
  height="20"
252
426
  viewBox="0 0 20 20"
@@ -257,7 +431,7 @@ const k = (e = "#505050") => o`<svg
257
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"
258
432
  fill="#505050"
259
433
  />
260
- </svg>`, q = o`<svg
434
+ </svg>`, ne = n`<svg
261
435
  width="24"
262
436
  height="24"
263
437
  viewBox="0 0 24 24"
@@ -268,7 +442,7 @@ const k = (e = "#505050") => o`<svg
268
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"
269
443
  fill="#505050"
270
444
  />
271
- </svg> `, p = o`<svg
445
+ </svg> `, V = n`<svg
272
446
  width="24"
273
447
  height="24"
274
448
  viewBox="0 0 24 24"
@@ -279,7 +453,7 @@ const k = (e = "#505050") => o`<svg
279
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"
280
454
  fill="#505050"
281
455
  />
282
- </svg>`, W = o`<svg
456
+ </svg>`, ae = n`<svg
283
457
  width="24"
284
458
  height="24"
285
459
  viewBox="0 0 24 24"
@@ -290,7 +464,7 @@ const k = (e = "#505050") => o`<svg
290
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"
291
465
  fill="#505050"
292
466
  />
293
- </svg> `, X = o`<svg
467
+ </svg> `, se = n`<svg
294
468
  width="24"
295
469
  height="24"
296
470
  viewBox="0 0 24 24"
@@ -301,7 +475,7 @@ const k = (e = "#505050") => o`<svg
301
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"
302
476
  fill="#505050"
303
477
  />
304
- </svg> `, w = o`<svg
478
+ </svg> `, I = n`<svg
305
479
  width="16"
306
480
  height="16"
307
481
  viewBox="0 0 16 16"
@@ -312,7 +486,7 @@ const k = (e = "#505050") => o`<svg
312
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"
313
487
  fill="#282828"
314
488
  />
315
- </svg> `, J = o`<svg
489
+ </svg> `, re = n`<svg
316
490
  width="24"
317
491
  height="24"
318
492
  viewBox="0 0 24 24"
@@ -323,7 +497,7 @@ const k = (e = "#505050") => o`<svg
323
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"
324
498
  fill="#505050"
325
499
  />
326
- </svg> `, Q = o`<svg
500
+ </svg> `, le = n`<svg
327
501
  width="24"
328
502
  height="24"
329
503
  viewBox="0 0 24 24"
@@ -334,7 +508,7 @@ const k = (e = "#505050") => o`<svg
334
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"
335
509
  fill="#505050"
336
510
  />
337
- </svg> `, e1 = o`<svg
511
+ </svg> `, ce = n`<svg
338
512
  width="24"
339
513
  height="24"
340
514
  viewBox="0 0 24 24"
@@ -345,7 +519,7 @@ const k = (e = "#505050") => o`<svg
345
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"
346
520
  fill="#505050"
347
521
  />
348
- </svg> `, t1 = o`<svg
522
+ </svg> `, he = n`<svg
349
523
  width="24"
350
524
  height="24"
351
525
  viewBox="0 0 24 24"
@@ -356,122 +530,275 @@ const k = (e = "#505050") => o`<svg
356
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"
357
531
  fill="#505050"
358
532
  />
359
- </svg>`, M = 248, y = 16, o1 = f`
360
- /* ===== HOST-LEVEL CUSTOM PROPERTIES ===== */
361
- :host {
362
- /* '--cm-side-nav-width' is set on 'campminder-app-shell''s ':host'
363
- * (packages/campminder/src/layout.ts is the source of truth) and
364
- * pierces the shadow boundary, so it's readable here even though this
365
- * package is portal-agnostic. It also switches to the collapsed
366
- * width, which a literal '168px' can't — the fallback below is only
367
- * for standalone rendering with no shell present.
368
- * '100vw' is correct for production, where the shell fills the
369
- * viewport and the nav starts at x=0; it reads over-wide in this
370
- * harness only because the harness page has a 24px inset the shell
371
- * doesn't have — a harness-geometry artifact, not a formula bug. */
372
- --cm-mega-menu-max-width: calc(100vw - var(--cm-side-nav-width, 168px));
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`
723
+ :host {
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};
373
730
  }
374
731
 
375
- /* ===== CSS RESET ===== */
376
732
  * {
377
733
  margin: 0;
378
734
  padding: 0;
379
735
  box-sizing: border-box;
380
736
  }
381
737
 
382
- /* ===== ANIMATIONS ===== */
383
- @keyframes fadeIn {
384
- from {
385
- opacity: 0;
386
- }
387
- to {
388
- opacity: 1;
389
- }
390
- }
391
-
392
- /* ===== MEGA MENU CONTAINER ===== */
393
- .mega-menu {
394
- position: absolute;
395
- left: 100%;
396
- top: 0;
397
- max-width: var(--cm-mega-menu-max-width);
738
+ .mega-menu-mobile {
398
739
  height: 100%;
399
- border-radius: 4px;
740
+ display: flex;
741
+ flex-direction: column;
400
742
  background: #fff;
401
- box-shadow: 0px 2px 16px 0px rgba(0, 0, 0, 0.12);
402
- animation: fadeIn 0.5s ease;
403
743
  }
404
744
 
405
- /* ===== HEADER SECTION ===== */
406
745
  .header {
407
746
  display: flex;
408
747
  align-items: center;
409
- justify-content: space-between;
748
+ gap: 8px;
410
749
  color: #505050;
411
750
  border-bottom: 1px solid rgba(160, 160, 160, 1);
412
- margin: 0 16px;
751
+ padding: 0 16px;
413
752
  height: 56px;
753
+ flex-shrink: 0;
414
754
  }
415
755
 
416
- .header-left {
417
- display: flex;
418
- align-items: center;
419
- }
420
-
421
- .header-title {
422
- display: grid;
423
- place-content: center;
424
- }
425
-
426
- .header-icon {
427
- margin-right: 8px;
428
- display: flex;
429
- justify-content: center;
430
- align-items: center;
431
- }
432
-
433
- /* ===== CLOSE BUTTON ===== */
434
- .close-button {
756
+ .back-button {
435
757
  display: flex;
436
758
  width: 24px;
437
759
  height: 24px;
438
760
  justify-content: center;
439
761
  align-items: center;
762
+ border: none;
763
+ background: transparent;
440
764
  border-radius: 4px;
441
765
  cursor: pointer;
442
766
  transition: background 0.2s ease;
443
767
  }
444
768
 
445
- .close-button:hover {
769
+ .back-button:hover,
770
+ .back-button:focus-visible {
446
771
  background: rgba(119, 61, 189, 0.12);
447
772
  }
448
773
 
449
- /* ===== 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
+
450
784
  .title-text {
451
785
  color: #505050;
452
- font-family: 'Inter', sans-serif;
786
+ font-family: var(--font-family);
453
787
  font-size: 16px;
454
788
  font-weight: 600;
455
789
  line-height: 24px;
456
790
  letter-spacing: 0.0025em;
457
791
  }
458
792
 
459
- /* ===== MENU ITEMS CONTAINER ===== */
460
793
  .menu-items {
461
- height: calc(100% - 56px);
462
- max-width: var(--cm-mega-menu-max-width);
463
- display: flex;
464
- flex-flow: column wrap;
465
- padding: 10px 16px 10px 0px;
794
+ flex: 1;
466
795
  overflow: auto;
796
+ padding: 10px 16px;
467
797
  }
468
798
 
469
- /* ===== MENU ITEM ===== */
470
799
  .menu-item {
471
- width: ${M}px;
472
- margin-left: ${y}px;
473
800
  margin-bottom: 12px;
474
- font-family: 'Inter', sans-serif;
801
+ font-family: var(--font-family);
475
802
  font-size: 14px;
476
803
  font-weight: 400;
477
804
  line-height: 20px;
@@ -480,17 +807,19 @@ const k = (e = "#505050") => o`<svg
480
807
 
481
808
  .menu-title {
482
809
  display: flex;
483
- width: 248px;
484
- padding: 4px 12px;
810
+ width: 100%;
811
+ padding: 8px 12px;
485
812
  align-items: center;
486
813
  gap: 8px;
814
+ background: var(--color-section-bg, rgba(0, 0, 0, 0.04));
815
+ border-radius: 4px;
816
+ margin-bottom: 4px;
487
817
  }
488
818
 
489
- /* ===== MENU LINKS ===== */
490
819
  .menu-url {
491
820
  display: flex;
492
821
  align-items: center;
493
- width: 248px;
822
+ width: 100%;
494
823
  min-height: 32px;
495
824
  padding: 6px 12px;
496
825
  border-radius: 4px;
@@ -511,74 +840,23 @@ const k = (e = "#505050") => o`<svg
511
840
  display: grid;
512
841
  place-content: center;
513
842
  }
514
-
515
- /* ===== RESPONSIVE ===== */
516
- @media (max-width: 1150px) {
517
- .menu-items {
518
- flex-wrap: nowrap;
519
- }
520
- }
521
- `, V = {
522
- AccountsSvgIcon: F,
523
- AdminSvgIcon: U,
524
- AlumniSvgIcon: j,
525
- CamperSvgIcon: K,
526
- CommunicationSvgIcon: q,
527
- CampInTouchSvgIcon: Y,
528
- FinancialSvgIcon: W,
529
- MedicalSvgIcon: X,
530
- ReportingSvgIcon: J,
531
- SchedulingSvgIcon: Q,
532
- StaffSvgIcon: e1,
533
- TravelSvgIcon: t1
534
- };
535
- function i1(e) {
536
- return e ? e.id === "home" ? H : V[`${e.label}SvgIcon`] ?? p : p;
537
- }
538
- function p1(e) {
539
- return e ? e.id === "home" ? !0 : `${e.label}SvgIcon` in V : !1;
540
- }
541
- function d(e) {
542
- return e.startsWith("http") ? new URL(e).pathname + new URL(e).search : e;
543
- }
544
- function n1(e, t) {
545
- const i = d(t);
546
- for (const n of e) {
547
- if (n.href && d(n.href) === i)
548
- return n.id;
549
- for (const s of n.subCategories)
550
- if (s.href && d(s.href) === i || s.items.find((a) => d(a.href) === i)) return n.id;
551
- }
552
- }
553
- function s1(e) {
554
- return e.items.length > 0 || !!e.href;
555
- }
556
- function C(e) {
557
- return e.subCategories.filter(s1);
558
- }
559
- function r1(e, t) {
560
- const i = e.find((n) => n.id === t);
561
- return !!i && C(i).length > 0;
562
- }
563
- function a1(e, t) {
564
- return t === "/" ? "home" : n1(e, t) ?? "";
565
- }
566
- var l1 = Object.defineProperty, h1 = Object.getOwnPropertyDescriptor, u = (e, t, i, n) => {
567
- for (var s = n > 1 ? void 0 : n ? h1(t, i) : t, r = e.length - 1, a; r >= 0; r--)
568
- (a = e[r]) && (s = (n ? a(t, i, s) : a(s)) || s);
569
- return n && s && l1(t, i, s), s;
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;
570
848
  };
571
- let h = class extends m {
849
+ let u = class extends w {
572
850
  constructor() {
573
851
  super(...arguments), this.tree = [], this.categoryId = "", this.handleKeyDown = (e) => {
574
852
  var t, i;
575
853
  if (e.key === "Escape")
576
- this.handleCloseMegaMenu(!0);
854
+ e.stopPropagation(), this.handleBack();
577
855
  else if (e.key === "Tab") {
578
- const n = (t = this.shadowRoot) == null ? void 0 : t.querySelectorAll("a.menu-title, .menu-url");
579
- if (!n || n.length === 0) return;
580
- const s = (i = this.shadowRoot) == null ? void 0 : i.activeElement;
581
- e.shiftKey && s === n[0] ? (e.preventDefault(), this.handleCloseMegaMenu(!0)) : !e.shiftKey && s === n[n.length - 1] && (e.preventDefault(), n[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());
582
860
  }
583
861
  };
584
862
  }
@@ -592,108 +870,43 @@ let h = class extends m {
592
870
  return this.tree.find((e) => e.id === this.categoryId);
593
871
  }
594
872
  /**
595
- * The close event keeps its name, `bubbles` and `composed` flags; `detail` is
596
- * new and carries the caller's focus intent onward to `<cm-side-nav>`'s
597
- * `dismissFlyout()`, which is the one place the focus rule is applied. Both
598
- * keyboard paths ask for restoration — they are the paths where focus is inside
599
- * the flyout and would otherwise be dropped on the document body. The close
600
- * button asks too; it is harmless when focus is not inside, because
601
- * `dismissFlyout` only moves focus that actually sits in the flyout.
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).
602
876
  */
603
- handleCloseMegaMenu(e = !0) {
877
+ handleBack() {
604
878
  this.dispatchEvent(
605
- new CustomEvent("cm-mega-menu-close", {
606
- detail: { restoreFocus: e },
879
+ new CustomEvent("cm-mega-menu-mobile-back", {
607
880
  bubbles: !0,
608
- composed: !0,
609
- cancelable: !0
881
+ composed: !0
610
882
  })
611
883
  );
612
884
  }
613
885
  /**
614
- * Packs menu items into as many 248px columns as the container's own
615
- * measured height allows. The `getBoundingClientRect()` calls below are
616
- * this component measuring its own shadow root, not a sibling, so they
617
- * don't trip the one rule. The `window.innerWidth <= 1150` gate is a
618
- * different thing and does not get the same pass: it's a page-viewport
619
- * read uncorrelated with this component's actual available width, kept
620
- * only because it's what upstream gated on. `window.innerWidth` is 1024
621
- * under jsdom, so this early return fires on every test run and the
622
- * packing logic below it was, until the test added for this floor,
623
- * 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.
624
889
  */
625
- setMenuItemsContainerWidth() {
626
- var s;
627
- const e = (s = this.shadowRoot) == null ? void 0 : s.querySelector(".menu-items");
628
- if (!e || window.innerWidth <= 1150) return;
629
- const t = e.getBoundingClientRect().height - 20;
630
- let i = 1, n = 0;
631
- for (const r of e.children)
632
- n + r.getBoundingClientRect().height + 12 > // 12 for bottom margin on item
633
- t && (i += 1, n = 0), n += r.getBoundingClientRect().height + 12;
634
- e.style.width = `${i * M + (i + 1) * y}px`;
635
- }
636
- updated(e) {
637
- super.updated(e), this.setMenuItemsContainerWidth();
638
- }
639
- // 2026-09-04: `label` may carry an unresolved `{{Bunk:Proper:Default}}`-style
640
- // terminology token, on both a sub-category header and a leaf. Rendered
641
- // verbatim below on purpose — see AGENTS.md's "Never resolve a terminology
642
- // token."
643
- renderLeaf(e) {
644
- return e.popup ? o`
645
- <a
646
- class="menu-url"
647
- href="#nowhere"
648
- @click=${() => {
649
- const t = window.open(e.href, "", e.popupProperties);
650
- return t && (t.opener = null), !1;
651
- }}
652
- target="_top"
653
- >
654
- ${e.label}
655
- <span class="new-tab-icon">${w}</span>
656
- </a>
657
- ` : o`
658
- <a
659
- class="menu-url"
660
- href="${e.href}"
661
- target=${e.newTab ? "_blank" : "_self"}
662
- rel=${x(e.newTab ? "noopener noreferrer" : void 0)}
663
- >
664
- ${e.label}
665
- ${e.newTab ? o`<span class="new-tab-icon">${w}</span>` : null}
666
- </a>
667
- `;
890
+ firstUpdated() {
891
+ var e, t;
892
+ (t = (e = this.shadowRoot) == null ? void 0 : e.querySelector(".back-button")) == null || t.focus();
668
893
  }
669
894
  render() {
670
- const e = this.categoryData, t = e ? C(e) : [];
671
- return !e || t.length === 0 ? null : o`
672
- <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">
673
898
  <div class="header">
674
- <div class="header-left">
675
- <div class="header-icon">${i1(e)}</div>
676
- <p class="header-title title-text">${e.label}</p>
677
- </div>
678
- <p class="close-button" @click=${() => this.handleCloseMegaMenu(!0)}>
679
- ${k()}
680
- </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>
681
903
  </div>
682
904
  <div class="menu-items">
683
905
  ${t.map(
684
- (i) => o`
906
+ (i) => n`
685
907
  <div class="menu-item">
686
- ${// Deliberate addition, not upstream parity — core-js's
687
- // `sub_categories[]` never carried a `url`, so there's no parity to
688
- // break. `MenuSubCategory.href?` lets a sub-category be a direct
689
- // link, and `isRenderableSubCategory` (`Utils/helpers.ts`) already
690
- // keeps such a node alive when it has no items. Rendering only
691
- // `sub.items` left that node's header going nowhere — no live case
692
- // in `campminder.json` today, but Floor 6's visibility filter can
693
- // produce one: an `href`-bearing sub-category whose every leaf is
694
- // gated off for the viewer.
695
- i.href ? o`<a class="title-text menu-title" href="${i.href}">${i.label}</a>` : o`<p class="title-text menu-title">${i.label}</p>`}
696
- ${i.items.map((n) => this.renderLeaf(n))}
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))}
697
910
  </div>
698
911
  `
699
912
  )}
@@ -702,17 +915,17 @@ let h = class extends m {
702
915
  `;
703
916
  }
704
917
  };
705
- h.styles = [o1];
706
- u([
707
- c({ attribute: !1 })
708
- ], h.prototype, "tree", 2);
709
- u([
710
- c({ type: String, attribute: "category-id" })
711
- ], h.prototype, "categoryId", 2);
712
- h = u([
713
- b("cm-mega-menu")
714
- ], h);
715
- const c1 = 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`
716
929
  /* ===== CSS CUSTOM PROPERTIES (DESIGN TOKENS) ===== */
717
930
  :host {
718
931
  display: block;
@@ -746,7 +959,12 @@ const c1 = f`
746
959
  --easing-exit: cubic-bezier(0.4, 0, 0.2, 1);
747
960
 
748
961
  /* Typography tokens */
749
- --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};
750
968
  --font-size-base: 14px;
751
969
  --font-size-medium: 15px;
752
970
  --font-size-large: 16px;
@@ -778,13 +996,13 @@ const c1 = f`
778
996
  box-sizing: border-box;
779
997
  }
780
998
 
781
- /* ===== MENU TOGGLE BUTTON (mobile; unused until Floor 5D, kept for parity) ===== */
999
+ /* ===== MENU TOGGLE BUTTON (mobile) ===== */
782
1000
  .menu-toggle {
783
1001
  width: var(--sidebar-header-height);
784
1002
  height: var(--sidebar-header-height);
785
1003
  cursor: pointer;
786
1004
  display: none;
787
- background: white;
1005
+ background: var(--color-bg-gradient);
788
1006
  border: none;
789
1007
  border-bottom: 1px solid var(--color-border-gray);
790
1008
  justify-content: center;
@@ -796,6 +1014,74 @@ const c1 = f`
796
1014
  height: var(--icon-size-base);
797
1015
  }
798
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
+
799
1085
  /* ===== NAVIGATION CONTAINER ===== */
800
1086
  .nav-container {
801
1087
  display: flex;
@@ -990,9 +1276,10 @@ const c1 = f`
990
1276
  text-align: left;
991
1277
  }
992
1278
 
993
- /* Unused on desktop: upstream gates the chevron behind deviceCSS.isMobile,
994
- and the mobile menu is deferred to AB#26231 (Floor 5D). Kept so that
995
- work does not have to re-derive this rule. */
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. */
996
1283
  .chevron-right {
997
1284
  margin-left: auto;
998
1285
  display: flex;
@@ -1008,35 +1295,62 @@ const c1 = f`
1008
1295
  animation-iteration-count: 1 !important;
1009
1296
  }
1010
1297
  }
1011
- `, L = {
1012
- AccountsSvgIcon: Z,
1013
- AdminSvgIcon: T,
1014
- AlumniSvgIcon: E,
1015
- CamperSvgIcon: $,
1016
- CommunicationSvgIcon: A,
1017
- CampInTouchSvgIcon: B,
1018
- FinancialSvgIcon: N,
1019
- HomeSvgIcon: H,
1020
- MedicalSvgIcon: O,
1021
- ReportingSvgIcon: _,
1022
- SchedulingSvgIcon: G,
1023
- StaffSvgIcon: P,
1024
- TravelSvgIcon: D
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
1025
1337
  };
1026
- function g1(e) {
1027
- return e ? L[`${e}SvgIcon`] ?? v : v;
1338
+ function k(e) {
1339
+ return e ? N[`${e}SvgIcon`] ?? H : H;
1028
1340
  }
1029
- function w1(e) {
1030
- return !!e && `${e}SvgIcon` in L;
1341
+ function Ve(e) {
1342
+ return !!e && `${e}SvgIcon` in N;
1031
1343
  }
1032
- var d1 = Object.defineProperty, C1 = Object.getOwnPropertyDescriptor, g = (e, t, i, n) => {
1033
- for (var s = n > 1 ? void 0 : n ? C1(t, i) : t, r = e.length - 1, a; r >= 0; r--)
1034
- (a = e[r]) && (s = (n ? a(t, i, s) : a(s)) || s);
1035
- return n && s && d1(t, i, 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;
1036
1348
  };
1037
- let l = class extends m {
1349
+ let l = class extends w {
1038
1350
  constructor() {
1039
- 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 = () => {
1040
1354
  this.dispatchEvent(
1041
1355
  new CustomEvent("cm-side-nav-toggle", {
1042
1356
  detail: { collapsed: !this.collapsed },
@@ -1044,6 +1358,18 @@ let l = class extends m {
1044
1358
  composed: !0
1045
1359
  })
1046
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
+ }
1047
1373
  };
1048
1374
  }
1049
1375
  /**
@@ -1056,10 +1382,24 @@ let l = class extends m {
1056
1382
  * getter needs to cache.
1057
1383
  */
1058
1384
  get selectedCategory() {
1059
- return a1(this.tree, this.currentPath);
1385
+ return pe(this.tree, this.currentPath);
1386
+ }
1387
+ connectedCallback() {
1388
+ super.connectedCallback(), this.initMobileMediaQuery();
1060
1389
  }
1061
1390
  disconnectedCallback() {
1062
- 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;
1063
1403
  }
1064
1404
  setSelectedCategory(e) {
1065
1405
  this.handleMenuItemHover(e);
@@ -1116,7 +1456,7 @@ let l = class extends m {
1116
1456
  }
1117
1457
  // Utility Methods
1118
1458
  get hamburgerIcon() {
1119
- return this.collapsed ? z : R;
1459
+ return this.collapsed ? L : j;
1120
1460
  }
1121
1461
  /**
1122
1462
  * The category the mega-menu flyout is open for, or `undefined` when none
@@ -1128,61 +1468,173 @@ let l = class extends m {
1128
1468
  */
1129
1469
  get openCategory() {
1130
1470
  const e = this.tree.find((t) => t.id === this.hoveredCategory);
1131
- if (!(!e || C(e).length === 0))
1471
+ if (!(!e || d(e).length === 0))
1132
1472
  return e;
1133
1473
  }
1134
1474
  buildCategoryClass(e) {
1135
1475
  const t = ["category"];
1136
1476
  return e.id === this.selectedCategory && t.push("selected"), e.id === this.hoveredCategory && t.push("category-hovered"), t.join(" ");
1137
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();
1588
+ }
1138
1589
  // 2026-09-02: `category.label` may still carry an unresolved `{{Bunk:Proper:Default}}`-style
1139
1590
  // terminology token — per-client substitution is a host concern, deferred by the plan (see
1140
1591
  // AGENTS.md's "Never resolve a terminology token"). Rendered verbatim below on purpose. A
1141
1592
  // future truncation, tooltip reformat, or `.trim()`/regex touch-up to `category.label` must
1142
1593
  // not assume it is plain text.
1143
1594
  getCategoryHtml(e) {
1144
- const t = this.buildCategoryClass(e), i = r1(this.tree, e.id), n = g1(e.label);
1145
- return i ? o`
1595
+ const t = this.buildCategoryClass(e), i = S(this.tree, e.id), o = k(e.label);
1596
+ return i ? n`
1146
1597
  <button
1147
1598
  class="${t}"
1148
1599
  @mouseenter=${() => this.handleMouseEnter(e.id)}
1149
1600
  @mouseleave=${() => this.handleMouseLeave()}
1150
1601
  @click=${() => this.handleMenuItemHover(e.id)}
1151
1602
  >
1152
- <div class="category-icon">${n}</div>
1603
+ <div class="category-icon">${o}</div>
1153
1604
  <div class="category-name">${e.label}</div>
1154
1605
  </button>
1155
- ` : o`
1606
+ ` : n`
1156
1607
  <a
1157
1608
  class="${t}"
1158
1609
  @mouseenter=${() => this.handleMouseEnter(e.id)}
1159
1610
  @mouseleave=${() => this.handleMouseLeave()}
1160
1611
  @click=${() => this.setSelectedCategory(e.id)}
1161
- href="${x(e.href)}"
1612
+ href="${v(e.href)}"
1162
1613
  >
1163
- <div class="category-icon">${n}</div>
1614
+ <div class="category-icon">${o}</div>
1164
1615
  <div class="category-name">${e.label}</div>
1165
1616
  </a>
1166
1617
  `;
1167
1618
  }
1168
1619
  renderMainMenu() {
1169
- return o`
1620
+ return n`
1170
1621
  <nav class="categories-container" role="navigation" aria-label="Main categories">
1171
1622
  <ul class="categories-list" role="list">
1172
1623
  ${this.tree.map(
1173
- (e) => o` <li role="listitem">${this.getCategoryHtml(e)}</li> `
1624
+ (e) => n` <li role="listitem">${this.getCategoryHtml(e)}</li> `
1174
1625
  )}
1175
1626
  </ul>
1176
1627
  </nav>
1177
1628
  `;
1178
1629
  }
1179
1630
  render() {
1180
- const e = this.openCategory;
1181
- return o`
1631
+ const e = this.openCategory, t = this.isNarrowViewport;
1632
+ return n`
1182
1633
  <nav
1183
1634
  class="nav-container"
1184
1635
  role="navigation"
1185
1636
  aria-label="Main navigation"
1637
+ aria-hidden=${t ? "true" : "false"}
1186
1638
  @mouseleave=${() => this.dismissFlyout(!1)}
1187
1639
  >
1188
1640
  <aside
@@ -1217,39 +1669,84 @@ let l = class extends m {
1217
1669
  — it is the derived openCategory getter above, not hoveredCategory
1218
1670
  itself, that becomes undefined.
1219
1671
  -->
1220
- ${e ? o`
1672
+ ${e ? n`
1221
1673
  <cm-mega-menu
1222
1674
  .tree=${this.tree}
1223
1675
  category-id=${e.id}
1224
- @cm-mega-menu-close=${(t) => {
1225
- var i;
1226
- return this.dismissFlyout(((i = t.detail) == null ? void 0 : i.restoreFocus) ?? !1);
1676
+ @cm-mega-menu-close=${(i) => {
1677
+ var o;
1678
+ return this.dismissFlyout(((o = i.detail) == null ? void 0 : o.restoreFocus) ?? !1);
1227
1679
  }}
1228
1680
  ></cm-mega-menu>
1229
1681
  ` : null}
1230
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>
1231
1719
  `;
1232
1720
  }
1233
1721
  };
1234
- l.styles = [c1];
1235
- g([
1236
- S()
1722
+ l.styles = [we];
1723
+ c([
1724
+ m()
1237
1725
  ], l.prototype, "hoveredCategory", 2);
1238
- g([
1239
- 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 })
1240
1737
  ], l.prototype, "collapsed", 2);
1241
- g([
1242
- c({ type: String, attribute: "current-path" })
1738
+ c([
1739
+ h({ type: String, attribute: "current-path" })
1243
1740
  ], l.prototype, "currentPath", 2);
1244
- g([
1245
- c({ attribute: !1 })
1741
+ c([
1742
+ h({ attribute: !1 })
1246
1743
  ], l.prototype, "tree", 2);
1247
- l = g([
1248
- b("cm-side-nav")
1744
+ l = c([
1745
+ y("cm-side-nav")
1249
1746
  ], l);
1250
1747
  export {
1251
- h as MegaMenu,
1748
+ g as MegaMenu,
1252
1749
  l as SideNav,
1253
- w1 as hasIconFor,
1254
- p1 as hasMegaMenuIconFor
1750
+ Ve as hasIconFor,
1751
+ Le as hasMegaMenuIconFor
1255
1752
  };