about.css (7114B)
1 /* 2 * The about page is a terminal: one font-size, one line-height, every row 3 * exactly one line (1.5em) tall, no gaps between a prompt and its output, and 4 * exactly one blank row between sections. Nothing below may add vertical padding, 5 * margins or a different line-height, or rows fall off the grid. 6 */ 7 .about-layout { 8 --row: 1.5em; 9 width: 100%; 10 height: 100%; 11 /* same gap on every side: one text row */ 12 padding: var(--row); 13 overflow-y: auto; 14 display: flex; 15 flex-direction: column; 16 gap: var(--row); 17 font-size: var(--fs-14); 18 line-height: 1.5; 19 } 20 21 .shell-prompt { 22 color: var(--fg-dim); 23 font-size: inherit; 24 line-height: inherit; 25 margin: 0; 26 } 27 28 .shell-user { 29 color: var(--green); 30 } 31 32 .shell-dollar { 33 color: var(--green); 34 } 35 36 .shell-host { 37 color: var(--accent); 38 } 39 40 .shell-path { 41 color: var(--cyan); 42 } 43 44 .shell-cmd { 45 color: var(--fg); 46 } 47 48 .section { 49 flex-shrink: 0; 50 display: flex; 51 flex-direction: column; 52 gap: 0; 53 } 54 55 .section .bio { 56 color: var(--fg); 57 font-size: inherit; 58 line-height: inherit; 59 margin: 0; 60 } 61 62 /* chips: one cell of horizontal padding, zero vertical, so each is one row */ 63 .tags { 64 display: flex; 65 flex-wrap: wrap; 66 gap: 0 1ch; 67 } 68 69 .about-layout .tag { 70 display: inline-block; 71 font-size: inherit; 72 line-height: inherit; 73 height: var(--row); 74 padding: 0 1ch; 75 } 76 77 /* fastfetch: logo width and gap in ch so the text column starts on a cell */ 78 /* the logo is 24ch x 10 rows so whatever follows stays on the row grid */ 79 .fetch { 80 display: flex; 81 align-items: flex-start; 82 gap: 3ch; 83 margin: 0; 84 font-size: var(--fs-14); 85 line-height: 1.5; 86 } 87 88 .fetch-logo { 89 display: block; 90 width: 24ch; 91 height: 15em; /* 10 rows of 1.5em */ 92 object-fit: cover; 93 flex-shrink: 0; 94 border: 1px solid var(--border); 95 filter: saturate(0.85); 96 } 97 98 /* the portrait draws in one text row (1.5em) at a time, like a terminal 99 printing it, instead of the browser's pixel-row jpeg decode */ 100 .fetch-logo.rows-pending { 101 visibility: hidden; 102 } 103 104 .fetch-logo.rows-in { 105 animation: logoRows 320ms steps(10, start) both; 106 } 107 108 @keyframes logoRows { 109 from { clip-path: inset(0 0 100% 0); } 110 to { clip-path: inset(0 0 0 0); } 111 } 112 113 @media (prefers-reduced-motion: reduce) { 114 .fetch-logo.rows-pending { visibility: visible; } 115 .fetch-logo.rows-in { animation: none; } 116 } 117 118 .fetch-info { 119 min-width: 0; 120 } 121 122 .fetch-rule { 123 color: var(--fg-dim); 124 } 125 126 .fetch-row { 127 overflow-wrap: anywhere; 128 } 129 130 .fetch-key { 131 color: var(--accent); 132 } 133 134 /* i5 firing order: 1-2-4-5-3. hover swaps the label for the engine block */ 135 .i5-host { 136 position: relative; 137 outline: none; 138 cursor: default; 139 } 140 141 .i5-host:focus-visible { 142 outline: 1px solid var(--accent); 143 outline-offset: 2px; 144 } 145 146 .i5 { 147 position: absolute; 148 inset: 0; 149 display: none; 150 align-items: center; 151 justify-content: center; 152 gap: 5px; 153 } 154 155 .i5 i { 156 width: 8px; 157 height: 8px; 158 border-radius: 50%; 159 border: 1.5px solid currentColor; 160 box-sizing: border-box; 161 } 162 163 .i5-host:hover .i5-label, 164 .i5-host:focus-visible .i5-label, 165 .i5-host:active .i5-label { 166 visibility: hidden; 167 } 168 169 .i5-host:hover .i5, 170 .i5-host:focus-visible .i5, 171 .i5-host:active .i5 { 172 display: flex; 173 } 174 175 .i5-host:hover .i5 i, 176 .i5-host:focus-visible .i5 i, 177 .i5-host:active .i5 i { 178 animation: fire 750ms steps(1) infinite; 179 animation-delay: calc(var(--fire) * 150ms); 180 } 181 182 @keyframes fire { 183 0% { background: currentColor; } 184 20% { background: transparent; } 185 } 186 187 @media (prefers-reduced-motion: reduce) { 188 .i5-host .i5 i { 189 animation: none !important; 190 } 191 } 192 193 @media (max-width: 700px) { 194 .about-layout { 195 padding: var(--row); 196 } 197 198 .fetch { 199 flex-direction: column; 200 gap: 1.5em; 201 } 202 203 .fetch-logo { 204 width: 14ch; 205 height: 9em; /* 6 rows */ 206 } 207 208 .fetch-logo.rows-in { 209 animation-timing-function: steps(6, start); 210 } 211 } 212 213 /* interactive prompt (modules/shell.js) 214 * Everything in the shell (prompt, typed text, cursor, output) shares one 215 * font-size and line-height so it all sits on the same character grid. */ 216 .shell { 217 cursor: text; 218 font-size: var(--fs-14); 219 line-height: 1.5; 220 font-weight: 400; 221 letter-spacing: 0; 222 word-spacing: 0; 223 tab-size: 8; 224 font-kerning: none; 225 font-variant-ligatures: none; 226 font-feature-settings: "liga" 0, "calt" 0; 227 font-synthesis: none; 228 } 229 230 .shell .shell-prompt, 231 .shell .shell-out, 232 .shell .shell-line, 233 .shell .shell-cmd, 234 .shell .shell-cursor { 235 font: inherit; 236 line-height: inherit; 237 } 238 239 .shell-live { 240 position: relative; 241 display: block; 242 cursor: text; 243 } 244 245 .shell-live[hidden] { 246 display: none; 247 } 248 249 /* the real input stays invisible; the spans around .shell-cursor draw it */ 250 .shell-input { 251 position: absolute; 252 left: 0; 253 top: 0; 254 width: 1px; 255 height: 100%; 256 padding: 0; 257 border: 0; 258 opacity: 0; 259 font-size: 16px; /* keeps iOS from zooming in on focus */ 260 caret-color: transparent; 261 pointer-events: none; 262 } 263 264 .shell-line { 265 white-space: pre-wrap; 266 word-break: break-all; 267 } 268 269 .shell-history { 270 display: flex; 271 flex-direction: column; 272 } 273 274 .shell-history:empty { 275 display: none; 276 } 277 278 .shell-out { 279 color: var(--fg); 280 font-size: var(--fs-14); 281 line-height: 1.5; 282 white-space: pre-wrap; 283 overflow-wrap: anywhere; 284 } 285 286 /* inside the shell, lines stack with no extra gaps: a strict row grid */ 287 .shell .shell-prompt, 288 .shell .shell-out { 289 margin: 0; 290 } 291 292 /* echoed command lines keep their exact spacing, like the live line */ 293 .shell .shell-prompt { 294 white-space: pre-wrap; 295 word-break: break-all; 296 } 297 298 /* streamed output: one div per line, no gap between them */ 299 .shell-stream { 300 margin-bottom: 0; 301 } 302 303 /* while a command runs the prompt goes away; typeahead still shows */ 304 .shell-live.busy .shell-ps1 { 305 display: none; 306 } 307 308 .shell-match { 309 color: var(--red); 310 font-weight: 700; 311 } 312 313 .shell-grep-file { 314 color: var(--magenta); 315 } 316 317 .shell-err { 318 color: var(--red); 319 } 320 321 .shell-dim { 322 color: var(--fg-dim); 323 } 324 325 .shell-dir { 326 color: var(--blue); 327 font-weight: 700; 328 } 329 330 .shell-reconnect { 331 font: inherit; 332 color: var(--accent); 333 background: none; 334 border: 0; 335 padding: 0; 336 cursor: pointer; 337 } 338 339 .shell-reconnect:hover, 340 .shell-reconnect:focus-visible { 341 color: var(--fg); 342 outline: none; 343 text-decoration: underline; 344 } 345 346 /* clear / ctrl+l hides the intro, like the TUI */ 347 .about-layout.shell-cleared > .section:not(.shell) { 348 display: none; 349 } 350 351 /* trailing prompt */ 352 .shell-cursor { 353 /* inline nbsp with a background = exactly one monospace cell, sits on the text baseline */ 354 display: inline; 355 background: var(--fg); 356 color: var(--bg); 357 animation: cursorBlink 1.1s steps(1) infinite; 358 } 359 @keyframes cursorBlink { 50% { background: transparent; color: inherit; } } 360 /* solid while typing (blink restarts after a pause, like xterm/Ghostty) */ 361 .shell-cursor.solid { animation: none; } 362 /* unfocused terminal: hollow block, no blink */ 363 .shell:not(:focus-within) .shell-cursor { 364 animation: none; 365 background: transparent; 366 color: inherit; 367 box-shadow: inset 0 0 0 1px var(--fg); 368 } 369 370 @media (prefers-reduced-motion: reduce) { 371 .shell-cursor { animation: none !important; } 372 } 373 374 /* fetch output inside the shell */ 375 .shell-fetch { 376 margin: 0; 377 padding: 0 0 1.5em; 378 white-space: normal; 379 }