| 1 | /* ------------------------------------------------------------------ */ |
| 2 | /* Primitives — the components every page composes */ |
| 3 | /* ------------------------------------------------------------------ */ |
| 4 | /* |
| 5 | * Class names are the API. Pages never define a colour, radius, shadow or |
| 6 | * duration; they compose these. Recipes: buttons, page header, sections, |
| 7 | * group cards, definition rows, directory rows, status (a mark and a |
| 8 | * word), segmented choice, tabs, code with copy, plate, figure, callout, |
| 9 | * disclosure rows, empty / loading / error states, data tables, fields, |
| 10 | * prose, steps, the whale's poses, and the horizon. |
| 11 | */ |
| 12 | |
| 13 | /* ---------- icons ---------- */ |
| 14 | /* components/icon.tsx: 24-unit, 1.7 round stroke, currentColor. */ |
| 15 | .icon { display: inline-block; width: 1rem; height: 1rem; flex: none; vertical-align: -0.125em; } |
| 16 | |
| 17 | /* ---------- buttons ---------- */ |
| 18 | /* One primary per view: the logo gradient with white text. Everything else |
| 19 | is secondary (raised), outline, ghost or danger (never filled). */ |
| 20 | .btn, |
| 21 | .portal-button { |
| 22 | display: inline-flex; |
| 23 | align-items: center; |
| 24 | justify-content: center; |
| 25 | gap: 0.375rem; |
| 26 | min-height: 2.25rem; |
| 27 | padding-inline: 0.875rem; |
| 28 | font-family: var(--font-body); |
| 29 | font-size: var(--text-ui); |
| 30 | font-weight: 500; |
| 31 | line-height: 1.25; |
| 32 | color: var(--text); |
| 33 | background: transparent; |
| 34 | border: 1px solid transparent; |
| 35 | border-radius: var(--radius-control); |
| 36 | white-space: nowrap; |
| 37 | text-decoration: none; |
| 38 | cursor: pointer; |
| 39 | transition-property: background-color, border-color, color, box-shadow, opacity; |
| 40 | transition-duration: var(--dur-state); |
| 41 | transition-timing-function: var(--ease-out); |
| 42 | } |
| 43 | .btn svg, |
| 44 | .portal-button svg { width: 1rem; height: 1rem; flex: none; } |
| 45 | .btn:active, |
| 46 | .portal-button:active { opacity: 0.8; } |
| 47 | .btn:disabled, |
| 48 | .btn[aria-disabled="true"], |
| 49 | .portal-button:disabled { opacity: 0.5; cursor: not-allowed; } |
| 50 | .btn[aria-busy="true"], |
| 51 | .portal-button[aria-busy="true"] { cursor: progress; } |
| 52 | |
| 53 | .btn-primary, |
| 54 | .portal-button-primary { |
| 55 | background: var(--brand-fill); |
| 56 | color: var(--on-brand); |
| 57 | font-weight: 600; |
| 58 | } |
| 59 | .btn-primary:hover, |
| 60 | .portal-button-primary:hover { |
| 61 | background: var(--brand-fill-hover); |
| 62 | color: var(--on-brand); |
| 63 | box-shadow: var(--glow-focus); |
| 64 | } |
| 65 | |
| 66 | .btn-secondary, |
| 67 | .portal-button-secondary { |
| 68 | background: var(--panel); |
| 69 | border-color: var(--line); |
| 70 | color: var(--text); |
| 71 | } |
| 72 | .btn-secondary:hover, |
| 73 | .portal-button-secondary:hover { background: var(--hover); } |
| 74 | |
| 75 | .btn-ghost { color: var(--text); } |
| 76 | .btn-ghost:hover { background: var(--hover); } |
| 77 | |
| 78 | .btn-danger { border-color: var(--line-strong); color: var(--danger); } |
| 79 | .btn-danger:hover { background: var(--hover); } |
| 80 | |
| 81 | .btn-sm { min-height: 1.75rem; padding-inline: 0.5rem; font-size: 0.8125rem; } |
| 82 | .btn-lg { min-height: 2.75rem; padding-inline: 1.125rem; font-size: 0.9375rem; } |
| 83 | |
| 84 | @media (pointer: coarse) { |
| 85 | .btn, |
| 86 | .portal-button { min-height: 2.75rem; } |
| 87 | } |
| 88 | |
| 89 | .actions, |
| 90 | .portal-actions { |
| 91 | display: flex; |
| 92 | flex-wrap: wrap; |
| 93 | align-items: center; |
| 94 | gap: var(--space-3); |
| 95 | } |
| 96 | |
| 97 | /* ---------- the whale's poses ---------- */ |
| 98 | /* One character everywhere: the v2 whale's still poses (public/whale). A |
| 99 | pose carries meaning — rest, listen, think, read, search, write, run, |
| 100 | browse, talk, computer, connect, needs you, done, hmm, sleep, busy, and |
| 101 | the pod for parallel agents. Never decorative filler. */ |
| 102 | .whale-pose { |
| 103 | display: block; |
| 104 | flex: none; |
| 105 | width: var(--pose-size, 4rem); |
| 106 | height: var(--pose-size, 4rem); |
| 107 | user-select: none; |
| 108 | } |
| 109 | |
| 110 | /* ---------- page header ---------- */ |
| 111 | /* What the reader knows (the title), why they are here (one lede), what to |
| 112 | do next (the actions). The whale sits beside it, doing the page's job. */ |
| 113 | .page-head { |
| 114 | width: var(--container); |
| 115 | margin-inline: auto; |
| 116 | padding-block: clamp(2.5rem, 6vw, 4.5rem) clamp(1.5rem, 3vw, 2.5rem); |
| 117 | } |
| 118 | |
| 119 | .page-head-inner { |
| 120 | display: grid; |
| 121 | grid-template-columns: minmax(0, 1fr) auto; |
| 122 | align-items: end; |
| 123 | gap: var(--space-5) clamp(1.5rem, 5vw, 4rem); |
| 124 | } |
| 125 | |
| 126 | .page-head-text { display: grid; gap: var(--space-4); min-width: 0; } |
| 127 | |
| 128 | .page-kicker { |
| 129 | display: inline-flex; |
| 130 | align-items: center; |
| 131 | gap: var(--space-2); |
| 132 | color: var(--muted); |
| 133 | font-size: var(--text-ui); |
| 134 | font-weight: 500; |
| 135 | } |
| 136 | .page-kicker svg { width: 1rem; height: 1rem; color: var(--accent); } |
| 137 | |
| 138 | .page-title { max-width: 22ch; font-size: var(--text-display); line-height: 1.08; } |
| 139 | |
| 140 | .page-lede { |
| 141 | max-width: 44rem; |
| 142 | color: var(--muted); |
| 143 | font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem); |
| 144 | line-height: 1.6; |
| 145 | } |
| 146 | |
| 147 | .page-meta { color: var(--muted); font-size: var(--text-ui); } |
| 148 | |
| 149 | .page-head .actions { margin-top: var(--space-2); } |
| 150 | |
| 151 | .page-head-pose { --pose-size: clamp(4.5rem, 10vw, 7.5rem); align-self: center; } |
| 152 | |
| 153 | @media (max-width: 640px) { |
| 154 | .page-head-inner { grid-template-columns: minmax(0, 1fr); } |
| 155 | .page-head-pose { --pose-size: 3.5rem; grid-row: 1; align-self: start; } |
| 156 | } |
| 157 | |
| 158 | /* ---------- page body and sections ---------- */ |
| 159 | .page-body { |
| 160 | width: var(--container); |
| 161 | margin-inline: auto; |
| 162 | padding-bottom: var(--section-gap); |
| 163 | } |
| 164 | .page-body-narrow { max-width: var(--measure-prose); } |
| 165 | |
| 166 | .page-section { padding-top: var(--section-gap); } |
| 167 | .page-section:first-child { padding-top: var(--space-5); } |
| 168 | |
| 169 | .section-head { |
| 170 | display: flex; |
| 171 | flex-wrap: wrap; |
| 172 | align-items: end; |
| 173 | justify-content: space-between; |
| 174 | gap: var(--space-2) var(--space-5); |
| 175 | margin-bottom: var(--space-5); |
| 176 | } |
| 177 | .section-head-text { display: grid; gap: var(--space-3); min-width: 0; max-width: 46rem; } |
| 178 | /* The editorial scale: a section title reads as a heading from across the |
| 179 | room (28-40px), not as a label. */ |
| 180 | .section-title { |
| 181 | max-width: 22ch; |
| 182 | font-size: var(--text-section); |
| 183 | font-weight: 600; |
| 184 | line-height: 1.12; |
| 185 | letter-spacing: -0.025em; |
| 186 | text-wrap: balance; |
| 187 | } |
| 188 | .section-scope { max-width: 40rem; color: var(--muted); font-size: var(--text-body); line-height: 1.6; } |
| 189 | |
| 190 | /* A running head above a section title: "01 / Your terminal", or a seal and |
| 191 | the subject. */ |
| 192 | .section-label { |
| 193 | display: inline-flex; |
| 194 | align-items: center; |
| 195 | gap: var(--space-3); |
| 196 | color: var(--accent); |
| 197 | font-size: var(--text-ui); |
| 198 | font-weight: 500; |
| 199 | font-variant-numeric: tabular-nums; |
| 200 | } |
| 201 | |
| 202 | /* The two-column section form: the title, scope and link on the left; the |
| 203 | content (usually a ruled list) on the right. */ |
| 204 | .section-split { |
| 205 | display: grid; |
| 206 | gap: var(--space-5) clamp(2rem, 6vw, 5rem); |
| 207 | grid-template-columns: minmax(0, 1fr); |
| 208 | } |
| 209 | .section-split-head { min-width: 0; } |
| 210 | .section-split-body { min-width: 0; } |
| 211 | @media (min-width: 900px) { |
| 212 | .section-split { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); align-items: start; } |
| 213 | .section-split-head { position: sticky; top: calc(var(--nav-height, 4rem) + var(--space-5)); } |
| 214 | } |
| 215 | .section-split .section-link { justify-self: start; margin-top: var(--space-2); } |
| 216 | |
| 217 | .section-link { |
| 218 | display: inline-flex; |
| 219 | align-items: center; |
| 220 | gap: var(--space-1); |
| 221 | color: var(--accent); |
| 222 | font-size: var(--text-ui); |
| 223 | font-weight: 500; |
| 224 | border-radius: var(--radius-control); |
| 225 | } |
| 226 | .section-link:hover { text-decoration: underline; text-underline-offset: 0.2em; } |
| 227 | .section-link svg { width: 1rem; height: 1rem; } |
| 228 | |
| 229 | /* Two- and three-up grids for group cards and tiles. */ |
| 230 | .grid-2, |
| 231 | .grid-3 { |
| 232 | display: grid; |
| 233 | gap: var(--space-4); |
| 234 | grid-template-columns: minmax(0, 1fr); |
| 235 | } |
| 236 | @media (min-width: 720px) { |
| 237 | .grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } |
| 238 | .grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } |
| 239 | } |
| 240 | @media (min-width: 1024px) { |
| 241 | .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } |
| 242 | } |
| 243 | |
| 244 | /* A split: a short explanation beside the list it explains. */ |
| 245 | .split { |
| 246 | display: grid; |
| 247 | gap: var(--space-5) clamp(2rem, 6vw, 5rem); |
| 248 | grid-template-columns: minmax(0, 1fr); |
| 249 | } |
| 250 | @media (min-width: 900px) { |
| 251 | .split { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); } |
| 252 | } |
| 253 | |
| 254 | /* ---------- group cards and tiles ---------- */ |
| 255 | /* A raised plate with a hairline edge. A card never sits inside a card. */ |
| 256 | .group-card { |
| 257 | border: 1px solid var(--line); |
| 258 | border-radius: var(--radius-surface); |
| 259 | background: color-mix(in srgb, var(--panel) 72%, transparent); |
| 260 | overflow: hidden; |
| 261 | } |
| 262 | .group-row { padding: var(--space-3) var(--space-4); } |
| 263 | .group-row + .group-row { border-top: 1px solid var(--line); } |
| 264 | |
| 265 | .tile { |
| 266 | display: grid; |
| 267 | align-content: start; |
| 268 | gap: var(--space-2); |
| 269 | padding: var(--space-5); |
| 270 | border: 1px solid var(--line); |
| 271 | border-radius: var(--radius-surface); |
| 272 | background: color-mix(in srgb, var(--panel) 72%, transparent); |
| 273 | } |
| 274 | .tile-icon { |
| 275 | display: inline-grid; |
| 276 | place-items: center; |
| 277 | width: 2.25rem; |
| 278 | height: 2.25rem; |
| 279 | margin-bottom: var(--space-2); |
| 280 | color: var(--accent); |
| 281 | background: color-mix(in srgb, var(--accent) 12%, transparent); |
| 282 | border-radius: var(--radius-control); |
| 283 | } |
| 284 | .tile-icon svg { width: 1.25rem; height: 1.25rem; } |
| 285 | .tile h3 { font-size: var(--text-heading); } |
| 286 | .tile p { color: var(--muted); font-size: var(--text-ui); line-height: 1.6; } |
| 287 | .tile .section-link { margin-top: var(--space-2); } |
| 288 | a.tile { transition: background-color var(--dur-state) var(--ease-out), border-color var(--dur-state) var(--ease-out); } |
| 289 | a.tile:hover { background: var(--hover); border-color: var(--line-strong); } |
| 290 | |
| 291 | /* ---------- ruled lists ---------- */ |
| 292 | /* The editorial list: a hairline between rows, a mono key on the left and |
| 293 | the explanation beside it. No box; the rules carry the structure. Used |
| 294 | wherever a list does not need icons. */ |
| 295 | .ruled-list { border-top: 1px solid var(--line-strong); } |
| 296 | .ruled-list > div { |
| 297 | display: grid; |
| 298 | gap: var(--space-1) var(--space-5); |
| 299 | padding-block: var(--space-4); |
| 300 | border-bottom: 1px solid var(--line); |
| 301 | } |
| 302 | .ruled-list dt { |
| 303 | color: var(--text); |
| 304 | font-family: var(--font-mono); |
| 305 | font-size: var(--text-mono); |
| 306 | line-height: 1.5; |
| 307 | overflow-wrap: anywhere; |
| 308 | } |
| 309 | .ruled-list dd { min-width: 0; color: var(--muted); font-size: var(--text-ui); line-height: 1.6; } |
| 310 | .ruled-list dd strong { color: var(--text); font-weight: 500; } |
| 311 | .ruled-list dd > .status:first-child { display: flex; width: max-content; margin-bottom: var(--space-1); } |
| 312 | .ruled-list dd code { color: var(--text); font-family: var(--font-mono); font-size: var(--text-mono); overflow-wrap: anywhere; } |
| 313 | @media (min-width: 640px) { |
| 314 | .ruled-list > div { grid-template-columns: minmax(8rem, 13rem) minmax(0, 1fr); } |
| 315 | } |
| 316 | |
| 317 | /* Stacked: a heading-like key above its explanation, for statements rather |
| 318 | than facts. */ |
| 319 | .ruled-list.ruled-list-stacked > div { grid-template-columns: minmax(0, 1fr); } |
| 320 | .ruled-list-stacked dt { font-family: var(--font-body); font-size: var(--text-body); font-weight: 600; } |
| 321 | |
| 322 | /* Ruled columns: three short statements divided by hairlines. */ |
| 323 | .ruled-cols { |
| 324 | display: grid; |
| 325 | grid-template-columns: minmax(0, 1fr); |
| 326 | border-top: 1px solid var(--line-strong); |
| 327 | } |
| 328 | .ruled-cols > * { |
| 329 | display: grid; |
| 330 | align-content: start; |
| 331 | gap: var(--space-2); |
| 332 | padding: var(--space-5) 0; |
| 333 | border-bottom: 1px solid var(--line); |
| 334 | } |
| 335 | .ruled-cols h3 { font-size: var(--text-heading); } |
| 336 | .ruled-cols p { color: var(--muted); font-size: var(--text-ui); line-height: 1.6; } |
| 337 | .ruled-cols .ruled-icon { color: var(--accent); } |
| 338 | .ruled-cols .ruled-icon svg { width: 1.25rem; height: 1.25rem; } |
| 339 | @media (min-width: 900px) { |
| 340 | .ruled-cols { grid-template-columns: repeat(3, minmax(0, 1fr)); border-bottom: 1px solid var(--line); } |
| 341 | .ruled-cols > * { padding: var(--space-5) var(--space-5) var(--space-6); border-bottom: 0; } |
| 342 | .ruled-cols > :first-child { padding-inline-start: 0; } |
| 343 | .ruled-cols > * + * { border-inline-start: 1px solid var(--line); } |
| 344 | } |
| 345 | |
| 346 | /* ---------- seals ---------- */ |
| 347 | /* One Han glyph stamped in the logo's ombre (components/seal.tsx). */ |
| 348 | .seal { |
| 349 | display: inline-grid; |
| 350 | place-items: center; |
| 351 | flex: none; |
| 352 | width: 2.5rem; |
| 353 | height: 2.5rem; |
| 354 | color: var(--on-brand); |
| 355 | background: var(--brand-fill); |
| 356 | border-radius: var(--radius-control); |
| 357 | box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.18); |
| 358 | font-family: var(--font-cjk); |
| 359 | font-size: 1.25rem; |
| 360 | font-weight: 700; |
| 361 | line-height: 1; |
| 362 | letter-spacing: 0; |
| 363 | } |
| 364 | .seal-sm { width: 2rem; height: 2rem; font-size: 1rem; } |
| 365 | .seal-lg { width: 3rem; height: 3rem; font-size: 1.5rem; } |
| 366 | @media (forced-colors: active) { |
| 367 | .seal { border: 1px solid CanvasText; } |
| 368 | } |
| 369 | |
| 370 | /* The bilingual Han title: the page's name in the other script, set beside |
| 371 | it in the ombre ink. */ |
| 372 | .page-title-aside { |
| 373 | font-family: var(--font-cjk); |
| 374 | font-size: 0.72em; |
| 375 | font-weight: 600; |
| 376 | letter-spacing: 0; |
| 377 | color: var(--accent); |
| 378 | white-space: nowrap; |
| 379 | } |
| 380 | @supports ((-webkit-background-clip: text) or (background-clip: text)) { |
| 381 | .page-title-aside { |
| 382 | background: var(--ombre-ink); |
| 383 | -webkit-background-clip: text; |
| 384 | background-clip: text; |
| 385 | -webkit-text-fill-color: transparent; |
| 386 | } |
| 387 | } |
| 388 | @media (forced-colors: active) { |
| 389 | .page-title-aside { background: none; -webkit-text-fill-color: currentColor; } |
| 390 | } |
| 391 | |
| 392 | /* ---------- definition rows ---------- */ |
| 393 | .def-rows { |
| 394 | border: 1px solid var(--line); |
| 395 | border-radius: var(--radius-surface); |
| 396 | background: color-mix(in srgb, var(--panel) 72%, transparent); |
| 397 | overflow: hidden; |
| 398 | } |
| 399 | .def-row { |
| 400 | display: grid; |
| 401 | gap: var(--space-1) var(--space-4); |
| 402 | padding: var(--space-3) var(--space-4); |
| 403 | } |
| 404 | .def-row + .def-row { border-top: 1px solid var(--line); } |
| 405 | .def-row dt { color: var(--text); font-size: var(--text-ui); font-weight: 500; } |
| 406 | .def-row dd { color: var(--muted); font-size: var(--text-ui); line-height: 1.6; min-width: 0; } |
| 407 | .def-row dd strong { color: var(--text); font-weight: 500; } |
| 408 | .def-row dd > .status:first-child { display: flex; width: max-content; margin-bottom: var(--space-1); } |
| 409 | @media (min-width: 640px) { |
| 410 | .def-row { grid-template-columns: minmax(8rem, 15rem) minmax(0, 1fr); } |
| 411 | } |
| 412 | |
| 413 | /* ---------- directory rows ---------- */ |
| 414 | /* A link that behaves like a row: a mark, a title and purpose, a status and |
| 415 | an action. Docs topics, integrations, channels, feeds, roadmap items. */ |
| 416 | .dir-list { display: grid; gap: 2px; } |
| 417 | .dir-list-card { |
| 418 | gap: 0; |
| 419 | border: 1px solid var(--line); |
| 420 | border-radius: var(--radius-surface); |
| 421 | background: color-mix(in srgb, var(--panel) 72%, transparent); |
| 422 | overflow: hidden; |
| 423 | } |
| 424 | .dir-list-card > li + li { border-top: 1px solid var(--line); } |
| 425 | |
| 426 | .dir-row { |
| 427 | display: flex; |
| 428 | align-items: center; |
| 429 | gap: var(--space-3); |
| 430 | padding: var(--space-3) var(--space-4); |
| 431 | color: var(--text); |
| 432 | text-decoration: none; |
| 433 | border-radius: var(--radius-control); |
| 434 | transition: background-color var(--dur-state) var(--ease-out); |
| 435 | } |
| 436 | .dir-list-card .dir-row { border-radius: 0; } |
| 437 | a.dir-row:hover { background: var(--hover); } |
| 438 | .dir-row[aria-current="page"] { background: var(--selected); } |
| 439 | |
| 440 | .dir-mark { |
| 441 | display: inline-grid; |
| 442 | place-items: center; |
| 443 | flex: none; |
| 444 | width: 2.25rem; |
| 445 | height: 2.25rem; |
| 446 | color: var(--accent); |
| 447 | background: color-mix(in srgb, var(--accent) 12%, transparent); |
| 448 | border-radius: var(--radius-control); |
| 449 | } |
| 450 | .dir-mark svg { width: 1.125rem; height: 1.125rem; } |
| 451 | |
| 452 | .dir-text { display: grid; gap: 0.125rem; flex: 1; min-width: 0; } |
| 453 | .dir-title { font-size: var(--text-ui); font-weight: 500; } |
| 454 | .dir-purpose { color: var(--muted); font-size: var(--text-ui); line-height: 1.5; } |
| 455 | .dir-meta { color: var(--muted); font-family: var(--font-mono); font-size: var(--text-caption); overflow-wrap: anywhere; } |
| 456 | .dir-action { flex: none; color: var(--muted); } |
| 457 | .dir-action svg { width: 1rem; height: 1rem; } |
| 458 | a.dir-row:hover .dir-action { color: var(--text); } |
| 459 | |
| 460 | /* ---------- status: a mark and a word ---------- */ |
| 461 | .status { |
| 462 | display: inline-flex; |
| 463 | align-items: center; |
| 464 | gap: 0.4rem; |
| 465 | color: var(--text); |
| 466 | font-size: var(--text-caption); |
| 467 | font-weight: 500; |
| 468 | white-space: nowrap; |
| 469 | } |
| 470 | .status-dot { |
| 471 | width: 0.5rem; |
| 472 | height: 0.5rem; |
| 473 | flex: none; |
| 474 | border-radius: var(--radius-pill); |
| 475 | background: currentColor; |
| 476 | color: var(--muted); |
| 477 | } |
| 478 | .status-ready .status-dot, |
| 479 | .status-live .status-dot { color: var(--live); } |
| 480 | .status-live .status-dot { box-shadow: var(--glow); } |
| 481 | .status-attention .status-dot { color: var(--attention); box-shadow: var(--glow); } |
| 482 | .status-accent .status-dot { color: var(--accent); } |
| 483 | .status-idle { color: var(--muted); } |
| 484 | .status-danger, |
| 485 | .status-danger .status-dot { color: var(--danger); } |
| 486 | |
| 487 | /* A one-line health or release statement. */ |
| 488 | .status-line { |
| 489 | display: flex; |
| 490 | flex-wrap: wrap; |
| 491 | align-items: center; |
| 492 | gap: var(--space-2) var(--space-4); |
| 493 | color: var(--muted); |
| 494 | font-size: var(--text-ui); |
| 495 | } |
| 496 | |
| 497 | /* The legacy <StatusBadge> markup, as a mark and a word. */ |
| 498 | .status-badge { |
| 499 | display: inline-flex; |
| 500 | align-items: center; |
| 501 | gap: 0.4rem; |
| 502 | color: var(--text); |
| 503 | font-size: var(--text-caption); |
| 504 | font-weight: 500; |
| 505 | } |
| 506 | .status-badge-dot { width: 0.5rem; height: 0.5rem; border-radius: var(--radius-pill); background: var(--muted); } |
| 507 | .status-badge-experimental .status-badge-dot, |
| 508 | .status-badge-preview .status-badge-dot { background: var(--attention); } |
| 509 | .status-badge-pending .status-badge-dot, |
| 510 | .status-badge-unavailable .status-badge-dot { background: var(--muted); } |
| 511 | |
| 512 | /* ---------- segmented choice ---------- */ |
| 513 | .segmented { |
| 514 | display: inline-flex; |
| 515 | gap: 2px; |
| 516 | padding: 2px; |
| 517 | background: var(--surface); |
| 518 | border: 1px solid var(--line); |
| 519 | border-radius: var(--radius-control); |
| 520 | } |
| 521 | .segmented button { |
| 522 | min-height: 1.75rem; |
| 523 | padding-inline: 0.625rem; |
| 524 | color: var(--muted); |
| 525 | font-size: 0.8125rem; |
| 526 | font-weight: 500; |
| 527 | border-radius: var(--radius-control); |
| 528 | cursor: pointer; |
| 529 | transition: background-color var(--dur-state) var(--ease-out), color var(--dur-state) var(--ease-out); |
| 530 | } |
| 531 | .segmented button:hover { background: var(--hover); color: var(--text); } |
| 532 | .segmented button[aria-pressed="true"] { |
| 533 | background: var(--selected); |
| 534 | color: var(--text); |
| 535 | /* A non-colour mark: the fill alone is under 3:1 against the track. */ |
| 536 | box-shadow: inset 0 0 0 1px var(--line-strong); |
| 537 | } |
| 538 | @media (forced-colors: active) { |
| 539 | .segmented button[aria-pressed="true"] { outline-style: solid; outline-width: 2px; outline-color: Highlight; outline-offset: -2px; } |
| 540 | } |
| 541 | @media (pointer: coarse) { |
| 542 | .segmented button { min-height: 2.5rem; } |
| 543 | } |
| 544 | |
| 545 | /* ---------- nav tabs ---------- */ |
| 546 | .tabs { |
| 547 | display: flex; |
| 548 | flex-wrap: wrap; |
| 549 | gap: var(--space-1); |
| 550 | border-bottom: 1px solid var(--line); |
| 551 | } |
| 552 | .tab { |
| 553 | position: relative; |
| 554 | padding: var(--space-2) var(--space-3); |
| 555 | color: var(--muted); |
| 556 | font-size: var(--text-ui); |
| 557 | font-weight: 500; |
| 558 | border-radius: var(--radius-control) var(--radius-control) 0 0; |
| 559 | transition: background-color var(--dur-state) var(--ease-out), color var(--dur-state) var(--ease-out); |
| 560 | } |
| 561 | .tab:hover { background: var(--hover); color: var(--text); } |
| 562 | .tab[aria-current="page"] { color: var(--text); } |
| 563 | .tab[aria-current="page"]::after { |
| 564 | content: ""; |
| 565 | position: absolute; |
| 566 | inset-inline: var(--space-3); |
| 567 | bottom: -1px; |
| 568 | height: 2px; |
| 569 | background: var(--accent); |
| 570 | } |
| 571 | |
| 572 | /* ---------- code with copy ---------- */ |
| 573 | .code { position: relative; min-width: 0; } |
| 574 | .code pre.code-block { padding-right: 6.5rem; } |
| 575 | /* A long command scrolls under the button, so the button sits flush with the |
| 576 | block's edge and a short fade on its leading side hides the text beneath |
| 577 | it instead of letting a sliver show on either side. Commands are always |
| 578 | left to right (see base.css), so the button is on the physical right. */ |
| 579 | .code .code-copy { |
| 580 | position: absolute; |
| 581 | background: var(--surface); |
| 582 | top: 50%; |
| 583 | right: 0.25rem; |
| 584 | transform: translateY(-50%); |
| 585 | color: var(--muted); |
| 586 | box-shadow: -0.75rem 0 0.5rem -0.25rem var(--surface); |
| 587 | } |
| 588 | .code .code-copy:focus-visible { box-shadow: var(--glow-focus); } |
| 589 | .code .code-copy:hover { background: var(--hover); color: var(--text); } |
| 590 | .code-copy[data-copied="true"] { color: var(--live); } |
| 591 | |
| 592 | /* ---------- plate ---------- */ |
| 593 | /* The install plate: a raised sheet that holds a choice, a command and its |
| 594 | copy button. */ |
| 595 | .plate { |
| 596 | display: grid; |
| 597 | gap: var(--space-3); |
| 598 | padding: var(--space-3); |
| 599 | background: color-mix(in srgb, var(--panel) 88%, transparent); |
| 600 | border: 1px solid var(--line); |
| 601 | border-radius: var(--radius-sheet); |
| 602 | transition: border-color var(--dur-state) var(--ease-out); |
| 603 | } |
| 604 | .plate:focus-within { border-color: var(--line-strong); } |
| 605 | .plate pre.code-block { background: var(--surface); } |
| 606 | |
| 607 | /* ---------- a live terminal capture ---------- */ |
| 608 | /* components/terminal-capture.tsx: real PTY cells as text. 100 columns stay |
| 609 | 100 columns; a narrow screen scrolls the frame, never shrinks it past |
| 610 | legibility. */ |
| 611 | /* The capture scales to its frame: the whole terminal is always visible, |
| 612 | sized from the frame's width and the grid's column count (--cols, set by |
| 613 | components/terminal-capture.tsx). 0.61em is a monospace advance with a |
| 614 | little room for the fallback fonts. #0a1e33 and #f6f2e8 are the captured |
| 615 | terminal's own defaults, not site colours. */ |
| 616 | .term-capture-scroll { |
| 617 | container-type: inline-size; |
| 618 | overflow: hidden; |
| 619 | background: #0a1e33; |
| 620 | } |
| 621 | .term-capture { |
| 622 | display: block; |
| 623 | width: 100%; |
| 624 | margin: 0; |
| 625 | padding: 1.6em 1.8em; |
| 626 | color: #f6f2e8; |
| 627 | font-family: var(--font-mono); |
| 628 | font-size: calc(100cqi / (var(--cols, 100) * 0.61 + 3.6)); |
| 629 | line-height: 1.25; |
| 630 | white-space: pre; |
| 631 | font-variant-ligatures: none; |
| 632 | tab-size: 8; |
| 633 | } |
| 634 | /* A row is one terminal line; each run fills the whole line box, so row |
| 635 | backgrounds meet without seams. */ |
| 636 | .term-capture-row { display: block; height: 1.25em; } |
| 637 | .term-capture-row > span { display: inline-block; height: 100%; vertical-align: top; } |
| 638 | .term-capture-cell { display: inline-block; width: 1ch; overflow: hidden; vertical-align: top; } |
| 639 | |
| 640 | /* ---------- figure ---------- */ |
| 641 | .figure { display: grid; gap: var(--space-3); min-width: 0; } |
| 642 | .figure-frame { |
| 643 | background: var(--surface); |
| 644 | border: 1px solid var(--line); |
| 645 | border-radius: var(--radius-surface); |
| 646 | overflow: hidden; |
| 647 | } |
| 648 | .figure-frame img { display: block; width: 100%; height: auto; } |
| 649 | .figure-caption { color: var(--muted); font-size: var(--text-caption); line-height: 1.5; } |
| 650 | |
| 651 | /* ---------- callout ---------- */ |
| 652 | .callout { |
| 653 | display: grid; |
| 654 | gap: var(--space-2); |
| 655 | padding: var(--space-4) var(--space-5); |
| 656 | background: color-mix(in srgb, var(--panel) 72%, transparent); |
| 657 | border: 1px solid var(--line); |
| 658 | border-radius: var(--radius-surface); |
| 659 | } |
| 660 | .callout-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); font-weight: 500; } |
| 661 | .callout p:not(.callout-title) { color: var(--muted); font-size: var(--text-ui); line-height: 1.6; } |
| 662 | |
| 663 | /* ---------- disclosure rows (FAQ) ---------- */ |
| 664 | .disclosure-row > summary { |
| 665 | display: flex; |
| 666 | align-items: center; |
| 667 | gap: var(--space-3); |
| 668 | min-height: 3rem; |
| 669 | padding: var(--space-3) var(--space-4); |
| 670 | color: var(--text); |
| 671 | font-size: var(--text-body); |
| 672 | font-weight: 500; |
| 673 | list-style: none; |
| 674 | cursor: pointer; |
| 675 | transition: background-color var(--dur-state) var(--ease-out); |
| 676 | } |
| 677 | .disclosure-row > summary::-webkit-details-marker { display: none; } |
| 678 | .disclosure-row > summary:hover { background: var(--hover); } |
| 679 | .disclosure-row > summary .disclosure-chevron { |
| 680 | width: 1rem; |
| 681 | height: 1rem; |
| 682 | margin-inline-start: auto; |
| 683 | flex: none; |
| 684 | color: var(--muted); |
| 685 | transition: transform var(--dur-state) var(--ease-out); |
| 686 | } |
| 687 | .disclosure-row[open] > summary .disclosure-chevron { transform: rotate(180deg); } |
| 688 | .disclosure-row + .disclosure-row { border-top: 1px solid var(--line); } |
| 689 | .disclosure-body { padding: 0 var(--space-4) var(--space-4); } |
| 690 | |
| 691 | /* ---------- empty / loading / error ---------- */ |
| 692 | /* A statement, never a placeholder: the whale's pose says what is going on, |
| 693 | the title says it in words, one action recovers. */ |
| 694 | .empty-state, |
| 695 | .state-block { |
| 696 | display: grid; |
| 697 | justify-items: center; |
| 698 | gap: var(--space-3); |
| 699 | max-width: 36rem; |
| 700 | margin-inline: auto; |
| 701 | padding-block: clamp(3rem, 8vw, 4.5rem); |
| 702 | text-align: center; |
| 703 | } |
| 704 | .empty-state .whale-pose { --pose-size: 6rem; margin-bottom: var(--space-2); } |
| 705 | .empty-state-title, |
| 706 | .state-title { font-size: var(--text-title); font-weight: 600; line-height: 1.25; } |
| 707 | h1.empty-state-title, |
| 708 | h1.state-title { font-size: var(--text-display); } |
| 709 | .empty-state-reason, |
| 710 | .state-body { max-width: 30rem; color: var(--muted); font-size: var(--text-body); line-height: 1.6; } |
| 711 | .empty-state-actions, |
| 712 | .state-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-3); margin-top: var(--space-2); } |
| 713 | |
| 714 | .state-block-compact, |
| 715 | .empty-state-compact { |
| 716 | justify-items: start; |
| 717 | max-width: none; |
| 718 | margin: 0; |
| 719 | padding: var(--space-4) var(--space-5); |
| 720 | text-align: start; |
| 721 | border: 1px solid var(--line); |
| 722 | border-radius: var(--radius-surface); |
| 723 | background: color-mix(in srgb, var(--panel) 72%, transparent); |
| 724 | } |
| 725 | .state-block-compact .state-title, |
| 726 | .empty-state-compact .empty-state-title { font-size: var(--text-ui); font-weight: 500; } |
| 727 | .state-block-compact .whale-pose, |
| 728 | .empty-state-compact .whale-pose { --pose-size: 2.5rem; margin: 0; } |
| 729 | .state-block-compact .state-actions, |
| 730 | .empty-state-compact .empty-state-actions { justify-content: flex-start; } |
| 731 | |
| 732 | .state-block-error .state-title { color: var(--danger); } |
| 733 | |
| 734 | .state-skeleton, |
| 735 | .skeleton { display: grid; gap: var(--space-2); width: min(100%, 24rem); } |
| 736 | .state-skeleton span { |
| 737 | display: block; |
| 738 | height: 0.75rem; |
| 739 | background: var(--surface); |
| 740 | border-radius: var(--radius-control); |
| 741 | } |
| 742 | |
| 743 | /* The working spinner: a sonar sweep. Motion that shows work; reduced motion |
| 744 | shows the still ring. */ |
| 745 | .spinner { |
| 746 | display: inline-block; |
| 747 | width: 1.25rem; |
| 748 | height: 1.25rem; |
| 749 | border: 2px solid color-mix(in srgb, var(--accent) 25%, transparent); |
| 750 | border-top-color: var(--accent); |
| 751 | border-radius: var(--radius-pill); |
| 752 | } |
| 753 | @media (prefers-reduced-motion: no-preference) { |
| 754 | .spinner { animation: spin var(--dur-spin) linear infinite; } |
| 755 | } |
| 756 | @keyframes spin { to { transform: rotate(360deg); } } |
| 757 | |
| 758 | /* ---------- data table ---------- */ |
| 759 | .data-table-wrap { |
| 760 | overflow-x: auto; |
| 761 | border: 1px solid var(--line); |
| 762 | border-radius: var(--radius-surface); |
| 763 | background: color-mix(in srgb, var(--panel) 72%, transparent); |
| 764 | } |
| 765 | .data-table { width: 100%; border-collapse: collapse; font-size: var(--text-ui); } |
| 766 | .data-table th, |
| 767 | .data-table td { padding: var(--space-3) var(--space-4); text-align: start; vertical-align: top; } |
| 768 | .data-table thead th { |
| 769 | color: var(--muted); |
| 770 | font-size: var(--text-caption); |
| 771 | font-weight: 500; |
| 772 | border-bottom: 1px solid var(--line); |
| 773 | white-space: nowrap; |
| 774 | } |
| 775 | .data-table tbody tr + tr > * { border-top: 1px solid var(--line); } |
| 776 | .data-table tbody th { font-weight: 500; } |
| 777 | .data-table td { color: var(--muted); } |
| 778 | .data-table code { font-family: var(--font-mono); font-size: var(--text-mono); color: var(--text); overflow-wrap: anywhere; } |
| 779 | .data-table-sort { |
| 780 | display: inline-flex; |
| 781 | align-items: center; |
| 782 | gap: var(--space-1); |
| 783 | margin: -0.25rem -0.375rem; |
| 784 | padding: 0.25rem 0.375rem; |
| 785 | color: inherit; |
| 786 | font: inherit; |
| 787 | border-radius: var(--radius-control); |
| 788 | cursor: pointer; |
| 789 | } |
| 790 | .data-table-sort:hover { background: var(--hover); color: var(--text); } |
| 791 | .data-table-sort svg { width: 0.875rem; height: 0.875rem; transition: transform var(--dur-state) var(--ease-out); } |
| 792 | .data-table-sort[data-dir="asc"] svg { transform: rotate(180deg); } |
| 793 | .data-table-sort[data-dir="none"] svg { opacity: 0.45; } |
| 794 | th[aria-sort="ascending"] .data-table-sort, |
| 795 | th[aria-sort="descending"] .data-table-sort { color: var(--text); } |
| 796 | |
| 797 | /* ---------- fields ---------- */ |
| 798 | .field { display: grid; gap: var(--space-2); } |
| 799 | .field-label { font-size: var(--text-ui); font-weight: 500; } |
| 800 | .field-input { |
| 801 | width: 100%; |
| 802 | min-height: 2.75rem; |
| 803 | padding-inline: var(--space-3); |
| 804 | font: inherit; |
| 805 | font-size: var(--text-body); |
| 806 | color: var(--text); |
| 807 | background: var(--surface); |
| 808 | border: 1px solid var(--line-strong); |
| 809 | border-radius: var(--radius-control); |
| 810 | transition: border-color var(--dur-state) var(--ease-out); |
| 811 | } |
| 812 | .field-input:focus-visible { border-color: var(--ring); } |
| 813 | .field-hint { color: var(--muted); font-size: var(--text-caption); } |
| 814 | .field-hint-error { color: var(--danger); } |
| 815 | |
| 816 | /* ---------- prose ---------- */ |
| 817 | .prose { |
| 818 | max-width: var(--measure-prose); |
| 819 | color: var(--text); |
| 820 | font-size: var(--text-prose); |
| 821 | line-height: var(--leading-prose); |
| 822 | } |
| 823 | .prose p, |
| 824 | .prose li { max-width: var(--measure-text); } |
| 825 | .prose > * + * { margin-top: var(--space-4); } |
| 826 | .prose h2 { margin-top: var(--space-7); font-size: var(--text-title); line-height: 1.25; } |
| 827 | .prose h3 { margin-top: var(--space-6); font-size: var(--text-heading); } |
| 828 | .prose h2 + *, |
| 829 | .prose h3 + * { margin-top: var(--space-2); } |
| 830 | .prose ul, |
| 831 | .prose ol { padding-inline-start: 1.25rem; } |
| 832 | .prose ul { list-style: disc; } |
| 833 | .prose ol { list-style: decimal; } |
| 834 | .prose li + li { margin-top: var(--space-2); } |
| 835 | .prose ::marker { color: var(--muted); } |
| 836 | .prose strong { font-weight: 600; } |
| 837 | .prose blockquote { border-inline-start: 2px solid var(--line-strong); padding-inline-start: var(--space-4); color: var(--muted); } |
| 838 | .prose hr { border: 0; border-top: 1px solid var(--line); } |
| 839 | .prose table { width: 100%; border-collapse: collapse; font-size: var(--text-ui); } |
| 840 | .prose th, |
| 841 | .prose td { padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--line); text-align: start; vertical-align: top; } |
| 842 | .prose th { color: var(--muted); font-weight: 500; } |
| 843 | html[lang="zh"] .prose, |
| 844 | html[lang="ja"] .prose, |
| 845 | html[lang="ko"] .prose { line-height: 1.8; letter-spacing: 0; } |
| 846 | |
| 847 | /* ---------- steps (the shared getting-started path) ---------- */ |
| 848 | .gs-steps { |
| 849 | display: grid; |
| 850 | grid-template-columns: repeat(4, minmax(0, 1fr)); |
| 851 | gap: 0 var(--space-6); |
| 852 | margin: 0; |
| 853 | padding: 0; |
| 854 | list-style: none; |
| 855 | } |
| 856 | /* A sequence on paper: a rule above each step and its numeral, no box. */ |
| 857 | .gs-steps li { |
| 858 | display: grid; |
| 859 | align-content: start; |
| 860 | gap: var(--space-2); |
| 861 | min-width: 0; |
| 862 | padding-top: var(--space-4); |
| 863 | border-top: 1px solid var(--line-strong); |
| 864 | } |
| 865 | .gs-step-index { |
| 866 | color: var(--accent); |
| 867 | font-size: var(--text-title); |
| 868 | font-weight: 600; |
| 869 | line-height: 1; |
| 870 | font-variant-numeric: tabular-nums; |
| 871 | } |
| 872 | .gs-steps .gs-step-title { margin-top: var(--space-2); font-size: var(--text-heading); } |
| 873 | .gs-steps p { color: var(--muted); font-size: var(--text-ui); line-height: 1.6; } |
| 874 | pre.gs-step-commands { margin-top: var(--space-1); font-size: var(--text-caption); white-space: pre-wrap; overflow-wrap: anywhere; } |
| 875 | .gs-step-link { |
| 876 | display: inline-flex; |
| 877 | align-items: center; |
| 878 | gap: var(--space-1); |
| 879 | margin-top: var(--space-1); |
| 880 | color: var(--accent); |
| 881 | font-size: var(--text-ui); |
| 882 | font-weight: 500; |
| 883 | } |
| 884 | .gs-step-link:hover { text-decoration: underline; text-underline-offset: 0.2em; } |
| 885 | .docs-content .gs-steps { grid-template-columns: minmax(0, 1fr); } |
| 886 | .docs-content .gs-steps { gap: var(--space-5); } |
| 887 | |
| 888 | @media (max-width: 760px) { |
| 889 | .gs-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-6); } |
| 890 | } |
| 891 | @media (max-width: 520px) { |
| 892 | .gs-steps { grid-template-columns: 1fr; gap: var(--space-5); } |
| 893 | } |
| 894 | |
| 895 | /* Any other numbered list of steps: as many columns as fit, divided by |
| 896 | 1px of the line colour showing through the gaps. */ |
| 897 | .steps { |
| 898 | display: grid; |
| 899 | grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); |
| 900 | gap: 1px; |
| 901 | margin: 0; |
| 902 | padding: 0; |
| 903 | list-style: none; |
| 904 | background: var(--line); |
| 905 | border: 1px solid var(--line); |
| 906 | border-radius: var(--radius-surface); |
| 907 | overflow: hidden; |
| 908 | } |
| 909 | .steps > li { |
| 910 | display: grid; |
| 911 | align-content: start; |
| 912 | gap: var(--space-2); |
| 913 | min-width: 0; |
| 914 | padding: var(--space-5); |
| 915 | background: var(--panel); |
| 916 | } |
| 917 | .steps h3 { margin-top: var(--space-2); font-size: var(--text-heading); } |
| 918 | .steps p { color: var(--muted); font-size: var(--text-ui); line-height: 1.6; } |
| 919 | |
| 920 | .stack { display: grid; align-content: start; gap: var(--space-4); min-width: 0; } |
| 921 | |
| 922 | /* ---------- session media (docs guide) ---------- */ |
| 923 | .session-media { border: 1px solid var(--line); border-radius: var(--radius-surface); overflow: hidden; } |
| 924 | .session-media video { display: block; width: 100%; height: auto; background: var(--ocean-abyss); } |
| 925 | .session-media-stage { |
| 926 | display: flex; |
| 927 | flex-direction: column; |
| 928 | align-items: flex-start; |
| 929 | gap: var(--space-3); |
| 930 | padding: clamp(1.5rem, 4vw, 2.5rem); |
| 931 | border-bottom: 1px solid var(--line); |
| 932 | background: var(--surface); |
| 933 | } |
| 934 | .session-media-pending-note { max-width: 44rem; margin: 0; color: var(--muted); font-size: var(--text-ui); line-height: 1.7; } |
| 935 | .session-media-caption { display: grid; gap: var(--space-2); padding: var(--space-4) var(--space-5); color: var(--muted); font-size: var(--text-ui); line-height: 1.6; } |
| 936 | .session-media-caption strong { color: var(--text); font-size: var(--text-body); } |
| 937 | .session-media-caption a { color: var(--accent); font-size: var(--text-caption); } |
| 938 | |
| 939 | /* ---------- the horizon ---------- */ |
| 940 | /* One calm, empty horizon per page: a straight line where the sky meets the |
| 941 | sea. Nothing stands on it but the whale. The sea below is the stage. */ |
| 942 | .horizon { |
| 943 | position: relative; |
| 944 | height: 1px; |
| 945 | background: var(--horizon-light); |
| 946 | } |
| 947 | |
| 948 | .sea { background: var(--sea), var(--ocean-abyss); } |
| 949 | |
| 950 | @media (forced-colors: active) { |
| 951 | .horizon { background: CanvasText; } |
| 952 | } |
| 953 | |
| 954 | /* ---------- search field ---------- */ |
| 955 | .search-field { position: relative; } |
| 956 | .search-field .search-input { padding-inline: 2.5rem 3rem; } |
| 957 | .search-field-icon { |
| 958 | position: absolute; |
| 959 | inset-inline-start: 0.875rem; |
| 960 | top: 50%; |
| 961 | width: 1rem; |
| 962 | height: 1rem; |
| 963 | color: var(--muted); |
| 964 | transform: translateY(-50%); |
| 965 | pointer-events: none; |
| 966 | } |
| 967 | .search-field .search-field-clear, |
| 968 | .search-field .search-field-kbd { |
| 969 | position: absolute; |
| 970 | inset-inline-end: 0.375rem; |
| 971 | top: 50%; |
| 972 | transform: translateY(-50%); |
| 973 | } |
| 974 | .search-field .search-field-kbd { inset-inline-end: 0.75rem; } |
| 975 |