@keenmate/pure-admin-core 2.3.6 → 2.5.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.
Files changed (47) hide show
  1. package/README.md +23 -29
  2. package/dist/css/main.css +68 -148
  3. package/package.json +1 -5
  4. package/snippets/AUDIT.md +94 -0
  5. package/snippets/alerts.html +264 -89
  6. package/snippets/badges.html +193 -61
  7. package/snippets/buttons.html +178 -0
  8. package/snippets/callouts.html +210 -129
  9. package/snippets/cards.html +383 -200
  10. package/snippets/checkbox-lists.html +199 -65
  11. package/snippets/code.html +55 -11
  12. package/snippets/command-palette.html +401 -111
  13. package/snippets/comparison.html +144 -93
  14. package/snippets/customization.html +311 -104
  15. package/snippets/data-display.html +584 -0
  16. package/snippets/detail-panel.html +470 -138
  17. package/snippets/filter-card.html +246 -0
  18. package/snippets/forms.html +408 -308
  19. package/snippets/grid.html +253 -141
  20. package/snippets/layout.html +379 -480
  21. package/snippets/lists.html +144 -47
  22. package/snippets/loaders.html +64 -39
  23. package/snippets/manifest.json +330 -280
  24. package/snippets/modal-dialogs.html +137 -64
  25. package/snippets/modals.html +221 -151
  26. package/snippets/notifications.html +285 -0
  27. package/snippets/popconfirm.html +213 -19
  28. package/snippets/profile.html +290 -330
  29. package/snippets/statistics.html +247 -0
  30. package/snippets/tables.html +359 -150
  31. package/snippets/tabs.html +129 -45
  32. package/snippets/timeline.html +123 -56
  33. package/snippets/toasts.html +179 -31
  34. package/snippets/tooltips.html +199 -81
  35. package/snippets/typography.html +183 -58
  36. package/snippets/utilities.html +511 -415
  37. package/snippets/virtual-scroll.html +201 -75
  38. package/snippets/web-daterangepicker.html +369 -189
  39. package/snippets/web-multiselect.html +360 -124
  40. package/src/scss/core-components/_alerts.scss +51 -12
  41. package/src/scss/core-components/_pagers.scss +1 -1
  42. package/src/scss/core-components/_popconfirm.scss +35 -13
  43. package/src/scss/core-components/_profile.scss +18 -8
  44. package/src/scss/core-components/_statistics.scss +12 -12
  45. package/src/scss/core-components/_tables.scss +2 -134
  46. package/src/scss/variables/_components.scss +17 -2
  47. package/scripts/download-themes.js +0 -351
@@ -1,122 +1,207 @@
1
1
  <!-- ================================
2
2
  LAYOUT & SIDEBAR SNIPPETS
3
3
  Pure Admin Visual Framework
4
+
5
+ SCSS lives in core-components/layout/ as a subfolder:
6
+ _layout-container.scss .pa-layout, container widths, footer
7
+ _navbar.scss .pa-navbar + header sections
8
+ _navbar-elements.scss burger, brand, nav, dropdowns, title, profile
9
+ _sidebar.scss .pa-layout__sidebar + .pa-sidebar BEM block
10
+ _sidebar-states.scss hidden, icon-collapse, flyouts
11
+ _layout-responsive.scss mobile / tablet media queries
4
12
  ================================ -->
5
13
 
14
+
6
15
  <!-- ================================
7
16
  BASIC LAYOUT STRUCTURE
17
+ The framework expects this outer shell — navbar fixed at top,
18
+ layout below it hosting sidebar + content + footer.
8
19
  ================================ -->
9
20
 
10
- <!-- Navbar (outside layout container) -->
21
+ <!-- Navbar (position: fixed, full width by default) -->
11
22
  <nav class="pa-navbar">
12
23
  <div class="pa-navbar__inner">
13
- <!-- Navbar content uses pa-header__ classes for elements -->
14
- <!-- Burger menu, brand, navigation, page title, profile -->
15
- <!-- See HEADER/NAVBAR section below for complete example -->
24
+ <!-- Header sections go here see NAVBAR section below for a full example -->
16
25
  </div>
17
26
  </nav>
18
27
 
19
- <!-- Layout Container (below navbar) -->
28
+ <!-- Layout wrapper (sits below navbar thanks to margin-top: $header-height) -->
20
29
  <div class="pa-layout">
21
- <!-- Layout Inner: Sidebar + Content -->
30
+ <!-- Inner: sidebar + content (flex row) -->
22
31
  <div class="pa-layout__inner">
23
- <!-- Sidebar -->
24
32
  <aside class="pa-layout__sidebar">
25
33
  <nav class="pa-sidebar__nav">
26
34
  <ul>
27
- <!-- Sidebar menu items here -->
28
- <!-- See SIDEBAR sections below for complete examples -->
35
+ <!-- Sidebar items go here — see SIDEBAR sections below -->
29
36
  </ul>
30
37
  </nav>
31
38
  </aside>
32
39
 
33
- <!-- Layout Content: Main only -->
40
+ <!-- Content wrapper (scrolls in sticky mode) -->
34
41
  <div class="pa-layout__content">
35
- <!-- Main Content -->
42
+ <!-- Main content — sets container-type: inline-size, so
43
+ pa-col-sm-* / -md-* / -lg-* / -xl-* grid responsiveness
44
+ works automatically for any pa-row nested inside. -->
36
45
  <main class="pa-layout__main">
37
- <div class="pa-layout__main__inner">
38
- <!-- Your page content here -->
39
- </div>
46
+ <!-- Your page content here -->
40
47
  </main>
41
48
  </div>
42
49
  </div>
43
50
 
44
- <!-- Footer (outside inner, inside layout) -->
45
- <!-- Three-section layout: Left / Center / Right -->
51
+ <!-- Footer sibling of __inner, inside .pa-layout -->
46
52
  <footer class="pa-layout__footer">
47
- <!-- Left Section (stays anchored left) -->
48
53
  <div class="pa-footer__start">
49
54
  <p>&copy; 2024 Pure Admin Framework</p>
50
55
  </div>
51
-
52
- <!-- Center Section (flexible, fills space) -->
53
56
  <div class="pa-footer__center">
54
- <!-- Optional center content -->
57
+ <!-- Optional centre content; hidden on mobile by default -->
55
58
  </div>
56
-
57
- <!-- Right Section (stays anchored right) -->
58
59
  <div class="pa-footer__end">
59
60
  <span>App version: 1.2.1</span>
60
- <span>Database version: 2.3.1</span>
61
61
  <a href="#">Open Source Licenses</a>
62
62
  </div>
63
63
  </footer>
64
64
  </div>
65
65
 
66
+ <!-- Footer end with vertical stack (for many small items) -->
67
+ <div class="pa-footer__end pa-footer__end--vertical">
68
+ <span>Version 1.2.1</span>
69
+ <span>Build 2341</span>
70
+ <a href="#">Licenses</a>
71
+ </div>
72
+
66
73
 
67
74
  <!-- ================================
68
- LAYOUT WIDTH VARIANTS
69
- Width is controlled by body classes, not div classes
75
+ LAYOUT MODES (body-level flags)
76
+ Two orthogonal mode flags applied to <body>:
77
+ pa-layout--sticky — body overflow: hidden; .pa-layout is
78
+ 100vh, content wrapper scrolls internally.
79
+ Good for "app" feel with fixed sidebar.
80
+ (none) — default; body scrolls naturally, footer
81
+ reaches viewport bottom via min-height.
82
+
83
+ Container widths (also body classes — constrain both .pa-navbar
84
+ and .pa-layout max-width):
85
+ pa-container-sm 768px
86
+ pa-container-md 1024px
87
+ pa-container-lg 1280px
88
+ pa-container-xl 1600px
89
+ pa-container-2xl 1920px
90
+ (none) fluid / full width
70
91
  ================================ -->
71
92
 
72
- <!-- Fluid Layout (Full Width) - Default -->
73
- <body>
74
- <div class="pa-layout">
75
- <!-- Content -->
76
- </div>
93
+ <body class="pa-layout--sticky pa-container-lg">
94
+ <!-- Sticky mode, constrained to 1280px -->
77
95
  </body>
78
96
 
79
- <!-- Small Container (768px) -->
80
- <body class="pa-container-sm">
81
- <div class="pa-layout">
82
- <!-- Content -->
83
- </div>
84
- </body>
85
97
 
86
- <!-- Medium Container (1024px) -->
87
- <body class="pa-container-md">
88
- <div class="pa-layout">
89
- <!-- Content -->
90
- </div>
91
- </body>
98
+ <!-- ================================
99
+ NAVBAR / HEADER
100
+ Three-section layout (start / center / end) inside .pa-navbar__inner.
101
+ ================================ -->
92
102
 
93
- <!-- Large Container (1280px) -->
94
- <body class="pa-container-lg">
95
- <div class="pa-layout">
96
- <!-- Content -->
97
- </div>
98
- </body>
103
+ <nav class="pa-navbar">
104
+ <div class="pa-navbar__inner">
105
+ <!-- START: burger, brand, left nav -->
106
+ <div class="pa-header__start">
107
+ <button class="pa-header__burger burger-menu" onclick="toggleSidebar()" aria-label="Toggle sidebar">
108
+ <span></span><span></span><span></span>
109
+ </button>
99
110
 
100
- <!-- Extra Large Container (1600px) -->
101
- <body class="pa-container-xl">
102
- <div class="pa-layout">
103
- <!-- Content -->
104
- </div>
105
- </body>
111
+ <div class="pa-header__brand">
112
+ <h1>Pure Admin</h1>
113
+ </div>
114
+
115
+ <!-- Nav: pa-header__nav auto-styles its direct child <ul> > <li> > <a>.
116
+ No additional classes needed on list items or anchors. -->
117
+ <nav class="pa-header__nav pa-header__nav--start">
118
+ <ul>
119
+ <li><a href="/">Dashboard</a></li>
120
+ <li><a href="/components">Components</a></li>
121
+
122
+ <!-- Hover-triggered dropdown -->
123
+ <li class="pa-header__nav-item pa-header__nav-item--has-dropdown">
124
+ <a href="#" class="pa-header__nav-link">More</a>
125
+ <ul class="pa-header__dropdown">
126
+ <li><a href="/forms">Forms</a></li>
127
+ <li><a href="/tables">Tables</a></li>
128
+
129
+ <!-- Nested dropdown (level 2) -->
130
+ <li class="pa-header__nav-item--has-dropdown">
131
+ <a href="#">Reports ›</a>
132
+ <ul class="pa-header__dropdown pa-header__dropdown--level2">
133
+ <li><a href="/reports/daily">Daily</a></li>
134
+ <li><a href="/reports/weekly">Weekly</a></li>
135
+ </ul>
136
+ </li>
137
+ </ul>
138
+ </li>
139
+ </ul>
140
+ </nav>
141
+ </div>
142
+
143
+ <!-- CENTER: page title (flexes + truncates) -->
144
+ <div class="pa-header__center">
145
+ <div class="pa-header__title">
146
+ <h2>Dashboard</h2>
147
+ </div>
148
+ </div>
149
+
150
+ <!-- END: right nav, notifications, profile -->
151
+ <div class="pa-header__end">
152
+ <nav class="pa-header__nav pa-header__nav--end">
153
+ <ul>
154
+ <li><a href="/alerts">Alerts</a></li>
155
+ </ul>
156
+ </nav>
157
+
158
+ <!-- pa-notifications is defined in _notifications.scss, not
159
+ layout — see the (pending) notifications snippet for
160
+ the full variant set. -->
161
+ <div class="pa-notifications">
162
+ <button class="pa-notifications__btn" onclick="toggleNotifications()" aria-label="Notifications">
163
+ <span class="pa-notifications__icon">🔔</span>
164
+ <span class="pa-notifications__badge">3</span>
165
+ </button>
166
+ </div>
106
167
 
107
- <!-- 2X Large Container (1920px) -->
108
- <body class="pa-container-2xl">
109
- <div class="pa-layout">
110
- <!-- Content -->
168
+ <button class="pa-header__profile-btn" onclick="toggleProfilePanel()" aria-label="User Profile">
169
+ <span class="pa-btn__icon">👤</span>
170
+ <span class="pa-header__profile-name">John Doe</span>
171
+ </button>
172
+ </div>
111
173
  </div>
112
- </body>
174
+ </nav>
175
+
176
+ <!--
177
+ Notes on the navbar:
178
+ - .pa-header__nav--start / --end are organisational placeholders
179
+ (empty SCSS blocks). They let you group nav links by side without
180
+ adding display rules. If you add your own styling, remember these
181
+ classes carry none of their own.
182
+ - .pa-header__nav-item--has-dropdown uses position: static so the
183
+ dropdown positions relative to the navbar, not this specific item.
184
+ - On mobile (max-width: $mobile-breakpoint), .pa-header__nav is hidden
185
+ entirely. Put dropdown-only items in a sidebar nav if they must stay
186
+ reachable below 768px.
187
+ -->
188
+
189
+
190
+ <!-- THEME SWITCHER (helper block in the header) -->
191
+
192
+ <div class="theme-switcher">
193
+ <label for="theme">Theme:</label>
194
+ <select id="theme" onchange="switchTheme(this.value)">
195
+ <option value="corporate">Corporate</option>
196
+ <option value="dark">Dark</option>
197
+ </select>
198
+ </div>
113
199
 
114
200
 
115
201
  <!-- ================================
116
- SIDEBAR - BASIC MENU
202
+ SIDEBAR BASIC MENU
117
203
  ================================ -->
118
204
 
119
- <!-- Sidebar with Simple Links -->
120
205
  <aside class="pa-layout__sidebar">
121
206
  <nav class="pa-sidebar__nav">
122
207
  <ul>
@@ -126,74 +211,33 @@
126
211
  <span class="pa-sidebar__label">Dashboard</span>
127
212
  </a>
128
213
  </li>
129
-
130
214
  <li class="pa-sidebar__item">
131
215
  <a href="/components" class="pa-sidebar__link">
132
216
  <span class="pa-sidebar__icon">🧩</span>
133
217
  <span class="pa-sidebar__label">Components</span>
134
218
  </a>
135
219
  </li>
136
-
137
220
  <li class="pa-sidebar__item">
138
221
  <a href="/forms" class="pa-sidebar__link">
139
222
  <span class="pa-sidebar__icon">📝</span>
140
223
  <span class="pa-sidebar__label">Forms</span>
141
224
  </a>
142
225
  </li>
143
-
144
- <li class="pa-sidebar__item">
145
- <a href="/tables" class="pa-sidebar__link">
146
- <span class="pa-sidebar__icon">📋</span>
147
- <span class="pa-sidebar__label">Tables</span>
148
- </a>
149
- </li>
150
- </ul>
151
- </nav>
152
- </aside>
153
-
154
-
155
- <!-- ================================
156
- SIDEBAR - WITH FONT AWESOME ICONS
157
- ================================ -->
158
-
159
- <!-- Sidebar with Font Awesome Icons -->
160
- <aside class="pa-layout__sidebar">
161
- <nav class="pa-sidebar__nav">
162
- <ul>
163
- <li class="pa-sidebar__item">
164
- <a href="/" class="pa-sidebar__link pa-sidebar__link--active">
165
- <span class="pa-sidebar__icon"><i class="fa-solid fa-chart-line"></i></span>
166
- <span class="pa-sidebar__label">Dashboard</span>
167
- </a>
168
- </li>
169
-
170
- <li class="pa-sidebar__item">
171
- <a href="/users" class="pa-sidebar__link">
172
- <span class="pa-sidebar__icon"><i class="fa-solid fa-users"></i></span>
173
- <span class="pa-sidebar__label">Users</span>
174
- </a>
175
- </li>
176
-
177
- <li class="pa-sidebar__item">
178
- <a href="/settings" class="pa-sidebar__link">
179
- <span class="pa-sidebar__icon"><i class="fa-solid fa-gear"></i></span>
180
- <span class="pa-sidebar__label">Settings</span>
181
- </a>
182
- </li>
183
226
  </ul>
184
227
  </nav>
185
228
  </aside>
186
229
 
187
230
 
188
231
  <!-- ================================
189
- SIDEBAR - WITH COLLAPSIBLE SUBMENU
232
+ SIDEBAR WITH COLLAPSIBLE SUBMENU
233
+ Use <button class="pa-sidebar__toggle"> for collapsible parents and
234
+ <a class="pa-sidebar__link"> for leaves. Submenu opens when the
235
+ parent <li> gets --open and the <ul> gets --open.
190
236
  ================================ -->
191
237
 
192
- <!-- Sidebar with Submenu (Two Levels) -->
193
238
  <aside class="pa-layout__sidebar">
194
239
  <nav class="pa-sidebar__nav">
195
240
  <ul>
196
- <!-- Regular link -->
197
241
  <li class="pa-sidebar__item">
198
242
  <a href="/" class="pa-sidebar__link">
199
243
  <span class="pa-sidebar__icon">📊</span>
@@ -201,7 +245,7 @@
201
245
  </a>
202
246
  </li>
203
247
 
204
- <!-- Collapsible submenu -->
248
+ <!-- Collapsible (parent is a button, not a link) -->
205
249
  <li class="pa-sidebar__item">
206
250
  <button class="pa-sidebar__toggle" onclick="toggleSubmenu(this)">
207
251
  <span class="pa-sidebar__icon">📋</span>
@@ -211,13 +255,13 @@
211
255
  <ul class="pa-sidebar__submenu">
212
256
  <li class="pa-sidebar__item">
213
257
  <a href="/tables" class="pa-sidebar__link">
214
- <span class="pa-sidebar__icon">📊</span>
215
- <span class="pa-sidebar__label">Standard Tables</span>
258
+ <span class="pa-sidebar__icon">•</span>
259
+ <span class="pa-sidebar__label">Standard</span>
216
260
  </a>
217
261
  </li>
218
262
  <li class="pa-sidebar__item">
219
263
  <a href="/tables-lazy" class="pa-sidebar__link">
220
- <span class="pa-sidebar__icon">⚡</span>
264
+ <span class="pa-sidebar__icon">•</span>
221
265
  <span class="pa-sidebar__label">Lazy Loading</span>
222
266
  </a>
223
267
  </li>
@@ -229,10 +273,12 @@
229
273
 
230
274
 
231
275
  <!-- ================================
232
- SIDEBAR - THREE-LEVEL NESTED MENU
276
+ SIDEBAR THREE-LEVEL NESTING
277
+ Level 2 and level 3 items get progressively indented via
278
+ padding-inline-start so the hierarchy reads at a glance. All
279
+ indentation is RTL-aware.
233
280
  ================================ -->
234
281
 
235
- <!-- Sidebar with Three-Level Nesting -->
236
282
  <aside class="pa-layout__sidebar">
237
283
  <nav class="pa-sidebar__nav">
238
284
  <ul>
@@ -259,12 +305,6 @@
259
305
  <span class="pa-sidebar__label">Security</span>
260
306
  </a>
261
307
  </li>
262
- <li class="pa-sidebar__item">
263
- <a href="/settings/advanced/performance" class="pa-sidebar__link">
264
- <span class="pa-sidebar__icon">•</span>
265
- <span class="pa-sidebar__label">Performance</span>
266
- </a>
267
- </li>
268
308
  </ul>
269
309
  </li>
270
310
  </ul>
@@ -275,272 +315,126 @@
275
315
 
276
316
 
277
317
  <!-- ================================
278
- SIDEBAR - COMPLETE EXAMPLE
279
- ================================ -->
280
-
281
- <!-- Full Sidebar with Mixed Links and Submenus -->
282
- <aside class="pa-layout__sidebar">
283
- <nav class="pa-sidebar__nav">
284
- <ul>
285
- <li class="pa-sidebar__item">
286
- <a href="/" class="pa-sidebar__link pa-sidebar__link--active">
287
- <span class="pa-sidebar__icon">📊</span>
288
- <span class="pa-sidebar__label">Dashboard</span>
289
- </a>
290
- </li>
291
-
292
- <li class="pa-sidebar__item">
293
- <a href="/components" class="pa-sidebar__link">
294
- <span class="pa-sidebar__icon">🧩</span>
295
- <span class="pa-sidebar__label">Components</span>
296
- </a>
297
- </li>
298
-
299
- <li class="pa-sidebar__item">
300
- <a href="/forms" class="pa-sidebar__link">
301
- <span class="pa-sidebar__icon">📝</span>
302
- <span class="pa-sidebar__label">Forms</span>
303
- </a>
304
- </li>
305
-
306
- <li class="pa-sidebar__item">
307
- <a href="/buttons" class="pa-sidebar__link">
308
- <span class="pa-sidebar__icon">🔘</span>
309
- <span class="pa-sidebar__label">Buttons</span>
310
- </a>
311
- </li>
312
-
313
- <li class="pa-sidebar__item">
314
- <a href="/cards" class="pa-sidebar__link">
315
- <span class="pa-sidebar__icon">🃏</span>
316
- <span class="pa-sidebar__label">Cards</span>
317
- </a>
318
- </li>
319
-
320
- <li class="pa-sidebar__item">
321
- <a href="/badges" class="pa-sidebar__link">
322
- <span class="pa-sidebar__icon">🏷️</span>
323
- <span class="pa-sidebar__label">Badges</span>
324
- </a>
325
- </li>
318
+ SIDEBAR MODES
319
+ Only one real modifier class exists on the sidebar element:
320
+ --icon-collapse (for the icon-only collapsed state).
326
321
 
327
- <li class="pa-sidebar__item">
328
- <a href="/modals" class="pa-sidebar__link">
329
- <span class="pa-sidebar__icon">🪟</span>
330
- <span class="pa-sidebar__label">Modals</span>
331
- </a>
332
- </li>
322
+ Hidden vs visible is controlled by body classes:
323
+ .sidebar-hidden — desktop: sidebar collapses (or hides)
324
+ .sidebar-visible — mobile: sidebar overlays the content
325
+ ================================ -->
333
326
 
334
- <li class="pa-sidebar__item">
335
- <a href="/alerts" class="pa-sidebar__link">
336
- <span class="pa-sidebar__icon">⚠️</span>
337
- <span class="pa-sidebar__label">Alerts</span>
338
- </a>
339
- </li>
327
+ <!-- Icon-collapse sidebar: hidden state shows a narrow icon bar with
328
+ hover flyouts for labels and submenus. When not hidden, renders
329
+ at normal width with labels visible. -->
330
+ <aside class="pa-layout__sidebar pa-layout__sidebar--icon-collapse">
331
+ <!-- Same pa-sidebar__nav markup as above. No content changes needed —
332
+ the CSS handles the collapse/flyout behaviour automatically. -->
333
+ </aside>
340
334
 
341
- <!-- Tables submenu -->
342
- <li class="pa-sidebar__item">
343
- <button class="pa-sidebar__toggle" onclick="toggleSubmenu(this)">
344
- <span class="pa-sidebar__icon">📋</span>
345
- <span class="pa-sidebar__label">Tables</span>
346
- <span class="pa-sidebar__chevron">›</span>
347
- </button>
348
- <ul class="pa-sidebar__submenu">
349
- <li class="pa-sidebar__item">
350
- <a href="/tables" class="pa-sidebar__link">
351
- <span class="pa-sidebar__icon">📊</span>
352
- <span class="pa-sidebar__label">Standard Tables</span>
353
- </a>
354
- </li>
355
- <li class="pa-sidebar__item">
356
- <a href="/tables-lazy" class="pa-sidebar__link">
357
- <span class="pa-sidebar__icon">⚡</span>
358
- <span class="pa-sidebar__label">Lazy Loading</span>
359
- </a>
360
- </li>
361
- </ul>
362
- </li>
363
- </ul>
364
- </nav>
335
+ <!-- Default sidebar with no modifier: hides entirely under .sidebar-hidden,
336
+ shows fully otherwise. -->
337
+ <aside class="pa-layout__sidebar">
338
+ <!-- nav -->
365
339
  </aside>
366
340
 
367
341
 
368
342
  <!-- ================================
369
- SIDEBAR MODES
370
- ================================ -->
343
+ SIDEBAR WIDTH / RESIZING
344
+ The sidebar reads its width from a CSS custom property:
371
345
 
372
- <!-- Sticky Sidebar (stays fixed while content scrolls) -->
373
- <aside class="pa-layout__sidebar pa-layout__sidebar--sticky">
374
- <!-- Nav content -->
375
- </aside>
346
+ :root { --pa-local-sidebar-width: 28.8rem; } /* default */
347
+ :where(.pa-layout__sidebar) { width: var(--pa-local-sidebar-width); }
376
348
 
377
- <!-- Icon-collapse Sidebar (collapses to icon bar instead of hiding) -->
378
- <aside class="pa-layout__sidebar pa-layout__sidebar--icon-collapse">
379
- <!-- Nav content -->
380
- </aside>
349
+ :where() gives the rule zero specificity, so any utility class
350
+ (.wr-*, .minwr-*, .maxwr-*) on the same element wins.
381
351
 
352
+ To make the sidebar drag-resizable, include a .pa-sidebar-resize
353
+ handle inside it and wire up JS that:
354
+ 1. On mousedown: add body.pa-sidebar-resizing (locks selection)
355
+ + .pa-sidebar-resize--active (visual feedback)
356
+ 2. On mousemove: update --pa-local-sidebar-width on :root or html
357
+ 3. On mouseup: remove both classes; optionally persist width to
358
+ localStorage.
382
359
 
383
- <!-- ================================
384
- SIDEBAR WIDTH CONTROL
360
+ There is NO pa-layout__sidebar--resizable or --sticky modifier.
361
+ Earlier docs claimed these; they never existed in SCSS.
385
362
  ================================ -->
386
363
 
387
- <!-- Default width (28.8rem / 288px from CSS variable) -->
388
- <aside class="pa-layout__sidebar">
389
- <!-- Nav content -->
390
- </aside>
391
-
392
- <!-- Resizable sidebar (opt-in, drag right edge to resize) -->
393
- <aside class="pa-layout__sidebar pa-layout__sidebar--resizable">
394
- <!-- Nav content -->
395
- <!-- Drag handle appears on right edge -->
396
- <!-- Width saved to localStorage -->
397
- <!-- Double-click handle to reset to default -->
398
- </aside>
399
-
400
- <!-- Custom fixed width using utility class (overrides default and resize) -->
364
+ <!-- Fixed width via rem utility overrides the CSS variable default -->
401
365
  <aside class="pa-layout__sidebar wr-25">
402
- <!-- Fixed 25rem (250px) width -->
403
- <!-- wr-* sets exact width, blocks resize -->
366
+ <!-- 25rem (250px) utility class wins because :where() has 0 specificity -->
404
367
  </aside>
405
368
 
406
- <!-- Custom minimum width using utility class (allows resize above minimum) -->
407
- <aside class="pa-layout__sidebar pa-layout__sidebar--resizable minwr-20">
408
- <!-- Minimum 20rem (200px) width -->
409
- <!-- minwr-* sets floor, resize still works above it -->
369
+ <!-- Resizable sidebar user-drag-to-resize via handle + JS -->
370
+ <aside class="pa-layout__sidebar">
371
+ <nav class="pa-sidebar__nav">
372
+ <!-- nav items -->
373
+ </nav>
374
+ <!-- Handle element; styled absolute on inline-end edge -->
375
+ <div class="pa-sidebar-resize"></div>
410
376
  </aside>
411
377
 
378
+ <!-- Width bounds set by the CSS variables below — JS should respect these: -->
412
379
  <!--
413
- SIDEBAR WIDTH OPTIONS:
414
- 1. Default: Uses CSS variable --pa-local-sidebar-width (28.8rem)
415
- 2. Resizable: Add --resizable class, user can drag to resize (180-500px range)
416
- 3. Fixed width: Add wr-* utility class (e.g., wr-20, wr-25, wr-30)
417
- 4. Minimum width: Add minwr-* utility class (e.g., minwr-15, minwr-20)
418
-
419
- WIDTH UTILITY CLASSES (rem-based, 10px = 1rem):
420
- - .wr-15 to .wr-25 - Fixed width (15rem to 25rem)
421
- - .minwr-15 to .minwr-25 - Minimum width (allows resize above)
422
- - .maxwr-15 to .maxwr-25 - Maximum width (limits resize)
423
-
424
- NOTE: Fixed width (.wr-*) overrides both default and resizable width.
425
- Use .minwr-* with --resizable to set a floor while allowing resize.
380
+ :root {
381
+ --pa-local-sidebar-width: 28.8rem; /* default */
382
+ --pa-local-sidebar-min-width: 18rem; /* floor */
383
+ --pa-local-sidebar-max-width: 50rem; /* ceiling */
384
+ }
426
385
  -->
427
386
 
428
387
 
429
388
  <!-- ================================
430
- NAVBAR/HEADER (with burger menu and navigation)
431
- Three-section layout: Left / Center / Right
389
+ BURGER MENU
390
+ Three <span>s stacked vertically; add .active to animate into an X.
391
+ RTL-aware — the translation direction flips under [dir="rtl"].
432
392
  ================================ -->
433
393
 
434
- <!-- Complete Navbar Example (hybrid: pa-navbar wrapper, pa-header__ elements) -->
435
- <nav class="pa-navbar">
436
- <div class="pa-navbar__inner">
437
- <!-- Left Section: Burger, Brand, Left Nav (stays anchored left) -->
438
- <div class="pa-header__start">
439
- <!-- Hamburger Menu (burger) -->
440
- <button class="pa-header__burger burger-menu" onclick="toggleSidebar()" aria-label="Toggle sidebar">
441
- <span></span>
442
- <span></span>
443
- <span></span>
444
- </button>
445
-
446
- <!-- Brand -->
447
- <div class="pa-header__brand">
448
- <h1>Pure Admin</h1>
449
- </div>
450
-
451
- <!-- Left Navigation Links -->
452
- <nav class="pa-header__nav pa-header__nav--start">
453
- <ul>
454
- <li><a href="/">Dashboard</a></li>
455
- <li><a href="/components">Components</a></li>
456
- <li><a href="/forms">Forms</a></li>
457
- </ul>
458
- </nav>
459
- </div>
394
+ <button class="burger-menu" onclick="toggleSidebar()" aria-label="Toggle sidebar">
395
+ <span></span>
396
+ <span></span>
397
+ <span></span>
398
+ </button>
460
399
 
461
- <!-- Center Section: Page Title (flexible, fills space between left/right) -->
462
- <div class="pa-header__center">
463
- <div class="pa-header__title">
464
- <h2>Dashboard</h2>
465
- </div>
466
- </div>
467
-
468
- <!-- Right Section: Right Nav, Notifications, Profile (stays anchored right) -->
469
- <div class="pa-header__end">
470
- <!-- Right Navigation Links -->
471
- <nav class="pa-header__nav pa-header__nav--end">
472
- <ul>
473
- <li><a href="/alerts">Alerts</a></li>
474
- <li><a href="/tables">Tables</a></li>
475
- </ul>
476
- </nav>
477
-
478
- <!-- Notification Bell -->
479
- <div class="pa-notifications">
480
- <button class="pa-notifications__btn" onclick="toggleNotifications()" aria-label="Notifications">
481
- <span class="pa-notifications__icon">🔔</span>
482
- <span class="pa-notifications__badge">3</span>
483
- </button>
484
- </div>
485
-
486
- <!-- Profile Button -->
487
- <button class="pa-header__profile-btn" onclick="toggleProfilePanel()" aria-label="User Profile">
488
- <span class="pa-btn__icon">👤</span>
489
- <span class="pa-header__profile-name">John Doe</span>
490
- </button>
491
- </div>
492
- </div>
493
- </nav>
400
+ <!--
401
+ - burger-menu (no .active) → three bars (☰) — sidebar visible / shown
402
+ - burger-menu.active → X shape — sidebar hidden / closed
403
+ Animation: ~150ms ease-out. Top/bottom bars rotate; middle bar fades.
404
+ The class .pa-header__burger is just a layout-position helper; the
405
+ visual animation lives on .burger-menu.
406
+ -->
494
407
 
495
408
 
496
409
  <!-- ================================
497
- JAVASCRIPT - BURGER MENU TOGGLE
410
+ JAVASCRIPT SIDEBAR TOGGLE + SUBMENU
498
411
  ================================ -->
499
412
 
500
413
  <script>
501
- /**
502
- * Toggle sidebar visibility (burger menu)
503
- */
414
+ // Toggle sidebar: mobile uses .sidebar-visible (overlay); desktop uses
415
+ // .sidebar-hidden (collapse / hide depending on --icon-collapse).
504
416
  function toggleSidebar() {
505
417
  const body = document.body;
506
- const burgerMenu = document.querySelector('.burger-menu');
418
+ const burger = document.querySelector('.burger-menu');
507
419
  const isMobile = window.innerWidth <= 768;
508
420
 
509
421
  if (isMobile) {
510
- // Mobile: Toggle sidebar visibility
511
422
  body.classList.toggle('sidebar-visible');
512
- burgerMenu.classList.toggle('active');
423
+ burger.classList.toggle('active');
513
424
  } else {
514
- // Desktop: Toggle sidebar hidden state
515
425
  body.classList.toggle('sidebar-hidden');
516
- burgerMenu.classList.toggle('active');
517
- const isHidden = body.classList.contains('sidebar-hidden');
518
- localStorage.setItem('sidebar-hidden', isHidden);
426
+ burger.classList.toggle('active');
427
+ localStorage.setItem('sidebar-hidden', body.classList.contains('sidebar-hidden'));
519
428
  }
520
429
  }
521
- </script>
522
430
 
523
-
524
- <!-- ================================
525
- JAVASCRIPT - SUBMENU TOGGLE
526
- ================================ -->
527
-
528
- <script>
529
- /**
530
- * Toggle sidebar submenu open/closed
531
- * Saves state to localStorage for persistence
532
- *
533
- * @param {HTMLElement} button - The .pa-sidebar__toggle button element
534
- */
431
+ // Toggle collapsible submenu — flips --open on the parent item + the <ul>.
535
432
  function toggleSubmenu(button) {
536
433
  const parentItem = button.closest('.pa-sidebar__item');
537
434
  const submenu = parentItem.querySelector('.pa-sidebar__submenu');
538
-
539
435
  if (!submenu) return;
540
436
 
541
437
  const isOpen = parentItem.classList.contains('pa-sidebar__item--open');
542
-
543
- // Toggle current submenu
544
438
  if (isOpen) {
545
439
  parentItem.classList.remove('pa-sidebar__item--open');
546
440
  submenu.classList.remove('pa-sidebar__submenu--open');
@@ -549,157 +443,162 @@ function toggleSubmenu(button) {
549
443
  submenu.classList.add('pa-sidebar__submenu--open');
550
444
  }
551
445
 
552
- // Save state to localStorage (optional)
553
- const submenuId = button.querySelector('.pa-sidebar__label').textContent.toLowerCase().replace(/\s+/g, '-');
554
- localStorage.setItem(`submenu-${submenuId}`, !isOpen ? 'open' : 'closed');
446
+ // Optional: persist per-menu open state
447
+ const id = button.querySelector('.pa-sidebar__label').textContent.toLowerCase().replace(/\s+/g, '-');
448
+ localStorage.setItem(`submenu-${id}`, !isOpen ? 'open' : 'closed');
555
449
  }
556
-
557
- /**
558
- * Restore submenu states from localStorage on page load (optional)
559
- */
560
- document.addEventListener('DOMContentLoaded', function() {
561
- document.querySelectorAll('.pa-sidebar__toggle').forEach(button => {
562
- const label = button.querySelector('.pa-sidebar__label');
563
- if (!label) return;
564
-
565
- const submenuId = label.textContent.toLowerCase().replace(/\s+/g, '-');
566
- const savedState = localStorage.getItem(`submenu-${submenuId}`);
567
-
568
- if (savedState === 'open') {
569
- const parentItem = button.closest('.pa-sidebar__item');
570
- const submenu = parentItem.querySelector('.pa-sidebar__submenu');
571
- if (submenu) {
572
- parentItem.classList.add('pa-sidebar__item--open');
573
- submenu.classList.add('pa-sidebar__submenu--open');
574
- }
575
- }
576
- });
577
- });
578
450
  </script>
579
451
 
580
452
 
581
453
  <!-- ================================
582
- USAGE NOTES
454
+ COMPONENT REFERENCE
583
455
  ================================ -->
584
456
 
585
457
  <!--
586
- LAYOUT STRUCTURE (HYBRID NAMING):
587
- The framework uses a hybrid naming approach:
588
- - Navbar wrapper: .pa-navbar + .pa-navbar__inner
589
- - Navbar elements inside use: .pa-header__ classes (burger, brand, nav, title, profile)
590
- - Layout wrapper: .pa-layout + .pa-layout__inner
591
- - Sidebar container: .pa-layout__sidebar
592
- - Sidebar nav elements use: .pa-sidebar__ classes
593
-
594
- NAVBAR CLASSES:
595
- - .pa-navbar - Navbar outer wrapper (outside layout container)
596
- - .pa-navbar__inner - Navbar inner container
597
-
598
- HEADER SECTION CONTAINERS (inside pa-navbar__inner):
599
- - .pa-header__start - Start section (burger, brand, nav--start) - stays anchored to start
600
- - .pa-header__center - Center section (title) - flexible, fills space
601
- - .pa-header__end - End section (nav--end, notifications, profile) - stays anchored to end
602
-
603
- HEADER/NAVBAR ELEMENT CLASSES (inside section containers):
604
- - .pa-header__burger - Burger menu button
605
- - .burger-menu - Burger menu class (same as __burger)
606
- - .pa-header__brand - Brand/logo area
607
- - .pa-header__nav - Navigation container
608
- - .pa-header__nav--start/right - Navigation alignment
609
- - .pa-header__title - Page title area (flexible, with ellipsis)
610
- - .pa-notifications - Notification bell container
611
- - .pa-header__profile-btn - Profile button
612
- - .pa-header__profile-name - Profile name text
613
-
614
- LAYOUT CLASSES:
615
- - .pa-layout - Main layout wrapper (below navbar)
616
- - .pa-layout__inner - Inner wrapper for sidebar + content
617
- - .pa-layout__sidebar - Sidebar container
618
- - .pa-layout__content - Content wrapper
619
- - .pa-layout__main - Main content area
620
- - .pa-layout__main__inner - Main content inner wrapper
621
- - .pa-layout__footer - Footer container
622
-
623
- FOOTER SECTION CONTAINERS (inside pa-layout__footer):
624
- - .pa-footer__start - Start section (copyright, etc.) - stays anchored to start
625
- - .pa-footer__center - Center section (optional) - flexible, fills space
626
- - .pa-footer__end - End section (version info, links) - stays anchored to end
627
-
628
- LAYOUT WIDTH VARIANTS (applied to body tag):
629
- - No class - Fluid layout (full width)
630
- - .pa-container-sm - Small (768px)
631
- - .pa-container-md - Medium (1024px)
632
- - .pa-container-lg - Large (1280px)
633
- - .pa-container-xl - Extra Large (1600px)
634
- - .pa-container-2xl - 2X Large (1920px)
635
-
636
- SIDEBAR STRUCTURE:
637
- - .pa-layout__sidebar - Sidebar container
638
- - .pa-sidebar__nav - Navigation wrapper
639
- - .pa-sidebar__item - Menu item container
640
- - .pa-sidebar__link - Regular menu link
641
- - .pa-sidebar__toggle - Collapsible menu toggle button
642
- - .pa-sidebar__icon - Icon container (fixed width)
643
- - .pa-sidebar__label - Text label
644
- - .pa-sidebar__chevron - Expand/collapse indicator
645
- - .pa-sidebar__submenu - Submenu container
646
- - .pa-sidebar__link--active - Active link state
647
- - .pa-sidebar__item--open - Open submenu state
648
- - .pa-sidebar__submenu--open - Open submenu state
649
-
650
- SIDEBAR MODES (modifiers on .pa-layout__sidebar):
651
- - Default - Sidebar scrolls with content
652
- - .pa-layout__sidebar--sticky - Sidebar stays fixed while content scrolls
653
- - .pa-layout__sidebar--icon-collapse - Sidebar collapses to icon bar instead of hiding
654
- - .pa-layout__sidebar--resizable - Drag right edge to resize (opt-in)
655
-
656
- SIDEBAR WIDTH CONTROL:
657
- - Default width: 28.8rem (288px) via CSS variable --pa-local-sidebar-width
658
- - Resizable: Add --resizable class for drag-to-resize (180-500px range)
659
- - Fixed width: Add .wr-* utility class (e.g., wr-25 = 250px) - overrides resize
660
- - Min width: Add .minwr-* utility class (e.g., minwr-20) - sets floor for resize
661
- - Max width: Add .maxwr-* utility class (e.g., maxwr-40) - sets ceiling for resize
662
-
663
- BURGER MENU:
664
- - .burger-menu - Burger menu button (same as .pa-header__burger)
665
- - Three <span> elements inside for the three lines
666
- - .active - Active state (X shape when clicked)
667
-
668
- BURGER MENU ANIMATION:
669
- - NO .active class (3 bars) → Sidebar is visible
670
- - WITH .active class → ✕ (X shape) Sidebar is hidden
671
- - JavaScript toggles .active class on click
672
- - CSS animates the transition in 150ms (ease-out)
673
- - Animation details:
674
- - Top bar: Rotates 45° and translates down/right
675
- - Middle bar: Fades out (opacity: 0)
676
- - Bottom bar: Rotates -45° and translates up/right
677
- - Customizable via SCSS variables:
678
- - $burger-width: 1.5rem
679
- - $burger-height: 1.5rem
680
- - $burger-bar-height: 2px
681
- - $burger-transform-offset: 3px
682
- - $transition-normal: 0.15s
683
- - $easing-snappy: ease-out
684
-
685
- BODY CLASSES (for sidebar state):
686
- - .sidebar-hidden - Desktop: Sidebar is hidden
687
- - .sidebar-visible - Mobile: Sidebar is visible (overlay)
688
-
689
- JAVASCRIPT:
690
- - toggleSidebar() - Toggle sidebar visibility (burger menu)
691
- - toggleSubmenu(button) - Toggle submenu open/closed
692
- - Stores state in localStorage for persistence across page loads
693
-
694
- PROFILE PANEL WIDTH CONTROL:
695
- - Default width: 20vw via CSS variable --pa-local-profile-panel-width
696
- - Default max-width: 48rem (480px) via CSS variable --pa-local-profile-panel-max-width
697
- - Override with utility classes: Add .wr-* to .pa-profile-panel__content
698
- - Examples:
699
- - .wr-30 = fixed 30rem (300px) width
700
- - .wr-40 = fixed 40rem (400px) width
701
- - .minwr-25 = minimum 25rem width
702
- - .maxwr-50 = maximum 50rem width
703
- - Uses low specificity (:where) so utility classes can override
704
- - Available: wr-1 to wr-10, then 15, 20, 25, 30, 35, 40, 45, 50 (same for minwr/maxwr)
458
+ LAYOUT SHELL:
459
+ - .pa-navbar Fixed top bar (position: fixed, z-index $z-index-header).
460
+ - .pa-navbar__inner Inner flex container (padding, gap).
461
+ - .pa-layout Below navbar (margin-top: $header-height);
462
+ flex column, max-width 100%.
463
+ - .pa-layout__inner Flex row hosting sidebar + content.
464
+ - .pa-layout__content Wraps <main>; overflow-y: auto so the
465
+ content area is always scrollable.
466
+ - .pa-layout__main Main content region. Sets
467
+ container-type: inline-size this is
468
+ WHY responsive grid classes
469
+ (pa-col-sm-*, -md-*, etc.) work inside
470
+ the layout automatically.
471
+ - .pa-layout__footer Page footer; flex row with start/center/end
472
+ sections (responsive center hidden on mobile).
473
+
474
+ FOOTER SECTIONS:
475
+ - .pa-footer__start Anchored to inline-start (copyright, etc.)
476
+ - .pa-footer__center Flexible middle
477
+ - .pa-footer__end Anchored to inline-end (version info, links)
478
+ - .pa-footer__end--vertical Stack end items vertically (flex-column)
479
+
480
+ BODY-LEVEL FLAGS (orthogonal any combination is valid):
481
+ - .pa-layout--sticky Fixed-viewport mode: body overflow: hidden;
482
+ .pa-layout is 100vh; content wrapper scrolls.
483
+ - .pa-container-sm / -md / -lg / -xl / -2xl
484
+ Constrains .pa-navbar AND .pa-layout max-width
485
+ to 768 / 1024 / 1280 / 1600 / 1920 px
486
+ respectively. Navbar and layout both get
487
+ margin-inline: auto to stay centred.
488
+ - .sidebar-hidden Desktop sidebar collapse / hide state.
489
+ - .sidebar-visible Mobile sidebar overlay visible.
490
+ - .pa-sidebar-resizing Set by the resize JS during drag (locks
491
+ text selection, forces ew-resize cursor).
492
+
493
+ NAVBAR HEADER SECTIONS (inside .pa-navbar__inner):
494
+ - .pa-header__start Start-anchored section; flex, gap.
495
+ - .pa-header__center Flexible middle (flex: 1; min-width: 0).
496
+ - .pa-header__end End-anchored section; margin-inline-start: auto.
497
+
498
+ NAVBAR ELEMENTS (inside header sections):
499
+ - .pa-header__burger Wrapper for the burger-menu button.
500
+ - .burger-menu The animated three-bar button itself.
501
+ - .burger-menu.active X-shape state (bars rotate + middle fades).
502
+ - .pa-header__brand Logo / brand area; h1 styled automatically.
503
+ - .pa-header__nav Nav container; auto-styles direct
504
+ ul > li > a descendants (no classes needed
505
+ on list items / anchors).
506
+ - .pa-header__nav--start Organisational placeholder (empty SCSS block).
507
+ - .pa-header__nav--end Organisational placeholder (empty SCSS block).
508
+ - .pa-header__nav-item Explicit li class (same behaviour as bare <li>).
509
+ - .pa-header__nav-item--has-dropdown
510
+ Parent li that reveals a child .pa-header__dropdown
511
+ on hover. Uses position: static so the
512
+ dropdown positions relative to the navbar.
513
+ - .pa-header__nav-link Optional anchor class (flex + gap for icon+text).
514
+ - .pa-header__dropdown Hover-dropdown <ul> (absolute; card-bg;
515
+ box-shadow; z-index 1100).
516
+ - .pa-header__dropdown--level2 Nested dropdown shifted to the side.
517
+ - .pa-header__title Centre-section page title with ellipsis h2.
518
+ - .pa-header__profile-btn Right-side profile button (flex-shrink: 0).
519
+ - .theme-switcher Inline label + select styled for the header.
520
+
521
+ SIDEBAR:
522
+ - .pa-layout__sidebar Sidebar column; width comes from
523
+ --pa-local-sidebar-width via :where()
524
+ so utility classes override it.
525
+ - .pa-layout__sidebar--icon-collapse Collapses to a narrow icon bar under
526
+ .sidebar-hidden; hover reveals labels
527
+ + submenus as flyouts.
528
+ (Expanded when NOT .sidebar-hidden.)
529
+
530
+ SIDEBAR BEM BLOCK:
531
+ - .pa-sidebar__nav <nav> wrapper for the menu ul.
532
+ - .pa-sidebar__item <li> menu item.
533
+ - .pa-sidebar__item--open Submenu-open state set by JS when
534
+ toggling a .pa-sidebar__toggle parent.
535
+ Rotates the chevron 90° (−90° in RTL).
536
+ - .pa-sidebar__link Leaf link (flex: icon + label, optional hover).
537
+ - .pa-sidebar__link--active Active leaf state accent colour +
538
+ accent border-inline-end accent bar.
539
+ - .pa-sidebar__toggle Collapsible parent (<button>, not <a>).
540
+ - .pa-sidebar__toggle--active Active collapsible state (kept open manually).
541
+ - .pa-sidebar__icon Fixed-width icon slot ($sidebar-icon-size).
542
+ - .pa-sidebar__label Text label (flex: 1; ellipsis on overflow).
543
+ - .pa-sidebar__chevron Right-pointing indicator; rotates on --open.
544
+ - .pa-sidebar__submenu Nested <ul>; hidden by default.
545
+ - .pa-sidebar__submenu--open Visible state.
546
+
547
+ RESIZE MECHANISM:
548
+ - .pa-sidebar-resize Handle element inside the sidebar
549
+ (absolute-positioned on the inline-end edge).
550
+ - .pa-sidebar-resize--active Active state (highlighted during drag).
551
+ - --pa-local-sidebar-width runtime width; JS rewrites this on drag.
552
+ - --pa-local-sidebar-min-width floor (default 18rem).
553
+ - --pa-local-sidebar-max-width ceiling (default 50rem).
554
+ - body.pa-sidebar-resizing set by JS during drag to disable text
555
+ selection + force ew-resize cursor.
556
+ (NO .pa-layout__sidebar--resizable or --sticky — these were never in
557
+ SCSS. The older snippet advertised them; the real knobs are the CSS
558
+ variable + handle element above.)
559
+
560
+ RESPONSIVE BEHAVIOUR (built in):
561
+ - Below $mobile-breakpoint (768px):
562
+ - .pa-header__nav hides entirely.
563
+ - Theme-switcher label hides.
564
+ - body:not(.sidebar-visible) hides the sidebar (width: 0).
565
+ - .sidebar-visible renders sidebar as a fixed-position overlay
566
+ ($mobile-sidebar-width) with a backdrop::before.
567
+ - Footer wraps, centre section hidden.
568
+ - Between $tablet-breakpoint-min and $tablet-breakpoint:
569
+ - Sidebar width shrinks to $sidebar-width-tablet.
570
+ - Sidebar link padding tightens.
571
+
572
+ STRUCTURE PATTERNS:
573
+
574
+ Minimal app shell:
575
+ <body class="pa-layout--sticky">
576
+ <nav class="pa-navbar"><div class="pa-navbar__inner">
577
+ <div class="pa-header__start">…</div>
578
+ <div class="pa-header__center"><div class="pa-header__title"><h2>Page</h2></div></div>
579
+ <div class="pa-header__end">…</div>
580
+ </div></nav>
581
+
582
+ <div class="pa-layout">
583
+ <div class="pa-layout__inner">
584
+ <aside class="pa-layout__sidebar">…</aside>
585
+ <div class="pa-layout__content">
586
+ <main class="pa-layout__main">…</main>
587
+ </div>
588
+ </div>
589
+ <footer class="pa-layout__footer">…</footer>
590
+ </div>
591
+ </body>
592
+
593
+ Constrained-width layout:
594
+ <body class="pa-container-lg">
595
+ …navbar + layout… (both limited to 1280px, centred)
596
+ </body>
597
+
598
+ Resizable sidebar:
599
+ <aside class="pa-layout__sidebar">
600
+ <nav class="pa-sidebar__nav">…</nav>
601
+ <div class="pa-sidebar-resize"></div>
602
+ </aside>
603
+ <!-- + JS that updates --pa-local-sidebar-width on drag -->
705
604
  -->