|
1 | 1 | /* |
2 | | - * Material Symbols Outlined for PropertyWebBuilder |
| 2 | + * SVG Icon System for PropertyWebBuilder |
3 | 3 | * https://fonts.google.com/icons |
4 | 4 | * |
5 | 5 | * This is the ONLY approved icon system for this project. |
6 | 6 | * Use the icon(:name) helper to render icons. |
7 | | - * See: docs/architecture/MATERIAL_ICONS_MIGRATION_PLAN.md |
| 7 | + * |
| 8 | + * Performance: SVG sprite (~60KB) vs font (~3.6MB) = 98% smaller |
| 9 | + * Benefits: No font loading delay, instant rendering, no FOIT/FOUT |
| 10 | + * |
| 11 | + * See: docs/icons/SVG_ICON_SYSTEM.md |
8 | 12 | */ |
9 | 13 |
|
10 | 14 | /* ============================================ |
11 | | - * Font Face Declaration |
12 | | - * ============================================ */ |
13 | | - |
14 | | -@font-face { |
15 | | - font-family: 'Material Symbols Outlined'; |
16 | | - font-style: normal; |
17 | | - font-weight: 100 700; |
18 | | - font-display: swap; |
19 | | - src: url('/fonts/material-symbols/MaterialSymbolsOutlined.woff2') format('woff2'); |
20 | | -} |
21 | | - |
22 | | -/* ============================================ |
23 | | - * Base Icon Styles |
| 15 | + * Base Icon Styles (SVG) |
24 | 16 | * ============================================ */ |
25 | 17 |
|
26 | | -.material-symbols-outlined { |
27 | | - font-family: 'Material Symbols Outlined'; |
28 | | - font-weight: normal; |
29 | | - font-style: normal; |
30 | | - font-size: 24px; |
31 | | - line-height: 1; |
32 | | - letter-spacing: normal; |
33 | | - text-transform: none; |
| 18 | +.icon { |
34 | 19 | display: inline-block; |
35 | | - white-space: nowrap; |
36 | | - word-wrap: normal; |
37 | | - direction: ltr; |
38 | | - vertical-align: middle; |
39 | | - -webkit-font-smoothing: antialiased; |
40 | | - -moz-osx-font-smoothing: grayscale; |
41 | | - text-rendering: optimizeLegibility; |
42 | | - font-feature-settings: 'liga'; |
| 20 | + width: 1em; |
| 21 | + height: 1em; |
| 22 | + vertical-align: -0.125em; /* Align with text baseline */ |
| 23 | + fill: currentColor; |
| 24 | + flex-shrink: 0; |
| 25 | +} |
43 | 26 |
|
44 | | - /* Default: outlined style */ |
45 | | - font-variation-settings: |
46 | | - 'FILL' 0, |
47 | | - 'wght' 400, |
48 | | - 'GRAD' 0, |
49 | | - 'opsz' 24; |
| 27 | +/* Ensure use element inherits fill */ |
| 28 | +.icon use { |
| 29 | + fill: inherit; |
50 | 30 | } |
51 | 31 |
|
52 | 32 | /* ============================================ |
53 | 33 | * Size Variants |
54 | 34 | * ============================================ */ |
55 | 35 |
|
56 | | -.material-symbols-outlined.md-14 { |
| 36 | +.icon-xs { |
| 37 | + width: 14px; |
| 38 | + height: 14px; |
57 | 39 | font-size: 14px; |
58 | | - font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20; |
59 | 40 | } |
60 | 41 |
|
61 | | -.material-symbols-outlined.md-18 { |
| 42 | +.icon-sm { |
| 43 | + width: 18px; |
| 44 | + height: 18px; |
62 | 45 | font-size: 18px; |
63 | | - font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 20; |
64 | 46 | } |
65 | 47 |
|
66 | | -.material-symbols-outlined.md-24 { |
| 48 | +.icon-md { |
| 49 | + width: 24px; |
| 50 | + height: 24px; |
67 | 51 | font-size: 24px; |
68 | | - font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; |
69 | 52 | } |
70 | 53 |
|
71 | | -.material-symbols-outlined.md-36 { |
| 54 | +.icon-lg { |
| 55 | + width: 36px; |
| 56 | + height: 36px; |
72 | 57 | font-size: 36px; |
73 | | - font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 40; |
74 | 58 | } |
75 | 59 |
|
76 | | -.material-symbols-outlined.md-48 { |
| 60 | +.icon-xl { |
| 61 | + width: 48px; |
| 62 | + height: 48px; |
77 | 63 | font-size: 48px; |
78 | | - font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 48; |
79 | 64 | } |
80 | 65 |
|
81 | 66 | /* ============================================ |
82 | 67 | * Style Variants |
83 | 68 | * ============================================ */ |
84 | 69 |
|
85 | | -/* Filled variant */ |
86 | | -.material-symbols-outlined.filled { |
87 | | - font-variation-settings: |
88 | | - 'FILL' 1, |
89 | | - 'wght' 400, |
90 | | - 'GRAD' 0, |
91 | | - 'opsz' 24; |
| 70 | +/* Filled variant - uses CSS filter to simulate filled look */ |
| 71 | +.icon-filled { |
| 72 | + /* Slightly bolder appearance */ |
| 73 | + stroke: currentColor; |
| 74 | + stroke-width: 0.5px; |
92 | 75 | } |
93 | 76 |
|
94 | 77 | /* Bold/emphasized variant */ |
95 | | -.material-symbols-outlined.bold { |
96 | | - font-variation-settings: |
97 | | - 'FILL' 0, |
98 | | - 'wght' 700, |
99 | | - 'GRAD' 0, |
100 | | - 'opsz' 24; |
| 78 | +.icon-bold { |
| 79 | + stroke: currentColor; |
| 80 | + stroke-width: 1px; |
101 | 81 | } |
102 | 82 |
|
103 | 83 | /* Light variant */ |
104 | | -.material-symbols-outlined.light { |
105 | | - font-variation-settings: |
106 | | - 'FILL' 0, |
107 | | - 'wght' 300, |
108 | | - 'GRAD' 0, |
109 | | - 'opsz' 24; |
110 | | -} |
111 | | - |
112 | | -/* Filled + Bold */ |
113 | | -.material-symbols-outlined.filled.bold { |
114 | | - font-variation-settings: |
115 | | - 'FILL' 1, |
116 | | - 'wght' 700, |
117 | | - 'GRAD' 0, |
118 | | - 'opsz' 24; |
| 84 | +.icon-light { |
| 85 | + opacity: 0.7; |
119 | 86 | } |
120 | 87 |
|
121 | 88 | /* ============================================ |
122 | 89 | * Utility Classes |
123 | 90 | * ============================================ */ |
124 | 91 |
|
125 | 92 | /* Fixed width for alignment in lists */ |
126 | | -.material-symbols-outlined.icon-fw { |
| 93 | +.icon-fw { |
127 | 94 | width: 1.5em; |
128 | 95 | text-align: center; |
129 | 96 | } |
130 | 97 |
|
131 | 98 | /* Spin animation for loading states */ |
132 | | -.material-symbols-outlined.icon-spin { |
| 99 | +.icon-spin { |
133 | 100 | animation: icon-spin 1s linear infinite; |
134 | 101 | } |
135 | 102 |
|
|
139 | 106 | } |
140 | 107 |
|
141 | 108 | /* Pulse animation */ |
142 | | -.material-symbols-outlined.icon-pulse { |
| 109 | +.icon-pulse { |
143 | 110 | animation: icon-pulse 1s ease-in-out infinite; |
144 | 111 | } |
145 | 112 |
|
|
148 | 115 | 50% { opacity: 0.5; } |
149 | 116 | } |
150 | 117 |
|
| 118 | +/* Fallback indicator (development) */ |
| 119 | +.icon-fallback { |
| 120 | + color: #f59e0b; /* Amber warning color */ |
| 121 | +} |
| 122 | + |
151 | 123 | /* ============================================ |
152 | 124 | * Icon Button Component |
153 | 125 | * ============================================ */ |
|
236 | 208 |
|
237 | 209 | /* Property feature icons */ |
238 | 210 | .property-feature-icon { |
239 | | - font-size: 20px; |
| 211 | + width: 20px; |
| 212 | + height: 20px; |
240 | 213 | margin-right: 0.25rem; |
241 | 214 | color: var(--text-muted, #6b7280); |
242 | 215 | } |
243 | 216 |
|
244 | 217 | /* Navigation icons */ |
245 | 218 | .nav-icon { |
246 | | - font-size: 20px; |
| 219 | + width: 20px; |
| 220 | + height: 20px; |
247 | 221 | margin-right: 0.5rem; |
248 | 222 | } |
249 | 223 |
|
250 | 224 | /* Action button icons */ |
251 | | -.btn .material-symbols-outlined { |
| 225 | +.btn .icon { |
252 | 226 | margin-right: 0.375rem; |
253 | | - font-size: 1.25em; |
| 227 | + width: 1.25em; |
| 228 | + height: 1.25em; |
254 | 229 | } |
255 | 230 |
|
256 | | -.btn-icon-only .material-symbols-outlined { |
| 231 | +.btn-icon-only .icon { |
257 | 232 | margin-right: 0; |
258 | 233 | } |
259 | 234 |
|
|
265 | 240 | transform: translateY(-50%); |
266 | 241 | color: var(--text-muted, #6b7280); |
267 | 242 | pointer-events: none; |
| 243 | + width: 20px; |
| 244 | + height: 20px; |
268 | 245 | } |
269 | 246 |
|
270 | 247 | .input-with-icon { |
|
276 | 253 | * ============================================ */ |
277 | 254 |
|
278 | 255 | /* Ensure icons don't interfere with screen readers when decorative */ |
279 | | -.material-symbols-outlined[aria-hidden="true"], |
| 256 | +.icon[aria-hidden="true"], |
280 | 257 | .brand-icon[aria-hidden="true"] { |
281 | 258 | speak: never; |
282 | 259 | } |
283 | 260 |
|
284 | 261 | /* High contrast mode support */ |
285 | 262 | @media (forced-colors: active) { |
286 | | - .material-symbols-outlined, |
| 263 | + .icon, |
287 | 264 | .brand-icon { |
288 | 265 | forced-color-adjust: auto; |
289 | 266 | } |
290 | 267 | } |
291 | 268 |
|
292 | 269 | /* Reduced motion preference */ |
293 | 270 | @media (prefers-reduced-motion: reduce) { |
294 | | - .material-symbols-outlined.icon-spin, |
295 | | - .material-symbols-outlined.icon-pulse { |
| 271 | + .icon-spin, |
| 272 | + .icon-pulse { |
296 | 273 | animation: none; |
297 | 274 | } |
298 | 275 | } |
| 276 | + |
| 277 | +/* ============================================ |
| 278 | + * Legacy Support (deprecated - remove after migration) |
| 279 | + * These classes maintain backwards compatibility |
| 280 | + * with any remaining font-based icon usage |
| 281 | + * ============================================ */ |
| 282 | + |
| 283 | +.material-symbols-outlined { |
| 284 | + /* Map to SVG icon styles */ |
| 285 | + display: inline-block; |
| 286 | + width: 24px; |
| 287 | + height: 24px; |
| 288 | + vertical-align: middle; |
| 289 | +} |
| 290 | + |
| 291 | +.material-symbols-outlined.md-14 { width: 14px; height: 14px; } |
| 292 | +.material-symbols-outlined.md-18 { width: 18px; height: 18px; } |
| 293 | +.material-symbols-outlined.md-24 { width: 24px; height: 24px; } |
| 294 | +.material-symbols-outlined.md-36 { width: 36px; height: 36px; } |
| 295 | +.material-symbols-outlined.md-48 { width: 48px; height: 48px; } |
0 commit comments