Spaces:
Running
Running
| /* ========================================================================== | |
| AI PLAYGROUND — COMPONENTS | |
| Reusable parts: navigation, buttons, cards, controls, panels, states, | |
| dialogs, visualisation chrome. Composed by both the homepage and the labs. | |
| ========================================================================== */ | |
| /* ========================================================================== | |
| 01 — NAVIGATION | |
| ========================================================================== */ | |
| .site-nav { | |
| position: sticky; | |
| top: 0; | |
| z-index: var(--z-nav); | |
| background: color-mix(in srgb, var(--paper) 88%, transparent); | |
| backdrop-filter: saturate(160%) blur(14px); | |
| -webkit-backdrop-filter: saturate(160%) blur(14px); | |
| border-bottom: var(--rule) solid var(--line); | |
| transition: border-color var(--dur-2) var(--ease), | |
| background-color var(--dur-2) var(--ease); | |
| } | |
| @supports not (backdrop-filter: blur(1px)) { | |
| .site-nav { background: var(--paper); } | |
| } | |
| .site-nav__inner { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--sp-5); | |
| height: 4.25rem; | |
| } | |
| /* --- Wordmark ---------------------------------------------------------- */ | |
| .wordmark { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: var(--sp-3); | |
| flex: none; | |
| padding-block: var(--sp-2); | |
| } | |
| .wordmark__mark { | |
| width: 1.375rem; | |
| height: 1.375rem; | |
| flex: none; | |
| overflow: visible; | |
| } | |
| .wordmark__text { | |
| font-family: var(--font-sans); | |
| font-size: var(--t-16); | |
| font-weight: var(--fw-semi); | |
| letter-spacing: var(--tr-tight); | |
| white-space: nowrap; | |
| } | |
| .wordmark__text span { color: var(--ink-muted); font-weight: var(--fw-regular); } | |
| .wordmark:hover .wordmark__mark { animation: spin 8s linear infinite; } | |
| /* --- Links ------------------------------------------------------------- */ | |
| .nav-links { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--sp-1); | |
| } | |
| .nav-link { | |
| position: relative; | |
| display: inline-block; | |
| padding: var(--sp-2) var(--sp-3); | |
| font-size: var(--t-14); | |
| font-weight: var(--fw-medium); | |
| letter-spacing: var(--tr-mid); | |
| color: var(--ink-secondary); | |
| border-radius: var(--r-1); | |
| transition: color var(--dur-2) var(--ease); | |
| } | |
| .nav-link::after { | |
| content: ""; | |
| position: absolute; | |
| left: var(--sp-3); | |
| right: var(--sp-3); | |
| bottom: 0.25rem; | |
| height: var(--rule); | |
| background: currentColor; | |
| transform: scaleX(0); | |
| transform-origin: left; | |
| transition: transform var(--dur-2) var(--ease); | |
| } | |
| .nav-link:hover { color: var(--ink); } | |
| .nav-link:hover::after { transform: scaleX(1); } | |
| .nav-link[aria-current="page"] { color: var(--ink); } | |
| .nav-link[aria-current="page"]::after { | |
| transform: scaleX(1); | |
| background: var(--accent); | |
| height: var(--rule-thick); | |
| } | |
| .nav-actions { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--sp-2); | |
| margin-left: auto; | |
| } | |
| /* --- Icon buttons ------------------------------------------------------ */ | |
| .icon-btn { | |
| display: inline-grid; | |
| place-items: center; | |
| width: 2.25rem; | |
| height: 2.25rem; | |
| border-radius: var(--r-2); | |
| color: var(--ink-secondary); | |
| border: var(--rule) solid transparent; | |
| transition: color var(--dur-2) var(--ease), | |
| background-color var(--dur-2) var(--ease), | |
| border-color var(--dur-2) var(--ease); | |
| } | |
| .icon-btn:hover { | |
| color: var(--ink); | |
| background: var(--paper-sunk); | |
| border-color: var(--line); | |
| } | |
| .icon-btn svg { width: 1.125rem; height: 1.125rem; } | |
| /* Theme toggle swaps icons by theme, both present for no-JS resilience */ | |
| [data-theme="dark"] .icon-moon, | |
| .icon-sun { display: none; } | |
| [data-theme="dark"] .icon-sun { display: block; } | |
| .icon-moon { display: block; } | |
| .nav-toggle { display: none; } | |
| @media (max-width: 1000px) { | |
| .nav-links { display: none; } | |
| .nav-toggle { display: inline-grid; } | |
| .nav-actions .btn--nav { display: none; } | |
| } | |
| /* --- Mobile drawer ----------------------------------------------------- */ | |
| .drawer { | |
| position: fixed; | |
| inset: 0; | |
| z-index: var(--z-drawer); | |
| visibility: hidden; | |
| pointer-events: none; | |
| } | |
| .drawer.is-open { visibility: visible; pointer-events: auto; } | |
| .drawer__scrim { | |
| position: absolute; | |
| inset: 0; | |
| background: var(--scrim); | |
| opacity: 0; | |
| transition: opacity var(--dur-3) var(--ease); | |
| } | |
| .drawer.is-open .drawer__scrim { opacity: 1; } | |
| .drawer__panel { | |
| position: absolute; | |
| inset-block: 0; | |
| right: 0; | |
| width: min(26rem, 100%); | |
| background: var(--paper); | |
| border-left: var(--rule) solid var(--line); | |
| display: flex; | |
| flex-direction: column; | |
| transform: translateX(100%); | |
| transition: transform var(--dur-3) var(--ease); | |
| overflow-y: auto; | |
| overscroll-behavior: contain; | |
| } | |
| .drawer.is-open .drawer__panel { transform: none; } | |
| .drawer__head { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| height: 4.25rem; | |
| padding-inline: var(--sp-5); | |
| border-bottom: var(--rule) solid var(--line); | |
| flex: none; | |
| } | |
| .drawer__body { padding: var(--sp-6) var(--sp-5) var(--sp-8); } | |
| .drawer__group + .drawer__group { margin-top: var(--sp-7); } | |
| .drawer__group-label { | |
| display: block; | |
| margin-bottom: var(--sp-4); | |
| padding-bottom: var(--sp-3); | |
| border-bottom: var(--rule) solid var(--line); | |
| } | |
| .drawer__link { | |
| display: flex; | |
| align-items: baseline; | |
| gap: var(--sp-4); | |
| padding: var(--sp-4) 0; | |
| border-bottom: var(--rule) solid var(--line); | |
| font-size: var(--t-21); | |
| font-family: var(--font-display); | |
| letter-spacing: var(--tr-mid); | |
| transition: padding-left var(--dur-2) var(--ease), | |
| color var(--dur-2) var(--ease); | |
| } | |
| .drawer__link:hover, | |
| .drawer__link:focus-visible { | |
| padding-left: var(--sp-3); | |
| color: var(--accent-ink); | |
| } | |
| .drawer__link .mono { color: var(--ink-faint); flex: none; } | |
| .drawer__link .drawer__meta { | |
| margin-left: auto; | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| letter-spacing: var(--tr-label); | |
| text-transform: uppercase; | |
| color: var(--ink-faint); | |
| } | |
| /* ========================================================================== | |
| 02 — BUTTONS | |
| ========================================================================== */ | |
| .btn { | |
| --btn-pad-y: 0.7rem; | |
| --btn-pad-x: 1.25rem; | |
| position: relative; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: var(--sp-2); | |
| padding: var(--btn-pad-y) var(--btn-pad-x); | |
| font-family: var(--font-sans); | |
| font-size: var(--t-14); | |
| font-weight: var(--fw-medium); | |
| letter-spacing: var(--tr-mid); | |
| line-height: 1.15; | |
| border: var(--rule) solid transparent; | |
| border-radius: var(--r-2); | |
| cursor: pointer; | |
| text-align: center; | |
| white-space: nowrap; | |
| min-height: 2.75rem; /* comfortable touch target */ | |
| transition: background-color var(--dur-2) var(--ease), | |
| color var(--dur-2) var(--ease), | |
| border-color var(--dur-2) var(--ease), | |
| transform var(--dur-1) var(--ease); | |
| } | |
| .btn:active { transform: translateY(1px); } | |
| .btn svg { width: 1rem; height: 1rem; flex: none; } | |
| .btn--primary { | |
| background: var(--ink); | |
| color: var(--ink-inverse); | |
| border-color: var(--ink); | |
| } | |
| .btn--primary:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-on); } | |
| .btn--accent { | |
| background: var(--accent); | |
| color: var(--accent-on); | |
| border-color: var(--accent); | |
| } | |
| .btn--accent:hover { filter: brightness(1.1); } | |
| .btn--outline { | |
| background: transparent; | |
| color: var(--ink); | |
| border-color: var(--line-strong); | |
| } | |
| .btn--outline:hover { border-color: var(--ink); background: var(--paper-sunk); } | |
| .btn--ghost { | |
| background: transparent; | |
| color: var(--ink-secondary); | |
| border-color: transparent; | |
| } | |
| .btn--ghost:hover { color: var(--ink); background: var(--paper-sunk); } | |
| .btn--sm { | |
| --btn-pad-y: 0.45rem; | |
| --btn-pad-x: 0.85rem; | |
| font-size: var(--t-12); | |
| min-height: 2.25rem; | |
| } | |
| .btn--lg { | |
| --btn-pad-y: 0.95rem; | |
| --btn-pad-x: 1.75rem; | |
| font-size: var(--t-16); | |
| min-height: 3.25rem; | |
| } | |
| .btn--block { width: 100%; } | |
| .btn[disabled], | |
| .btn[aria-disabled="true"] { | |
| opacity: 0.4; | |
| cursor: not-allowed; | |
| pointer-events: none; | |
| } | |
| /* Arrow that slides on hover — the one flourish on primary CTAs */ | |
| .btn__arrow { transition: transform var(--dur-2) var(--ease); } | |
| .btn:hover .btn__arrow { transform: translateX(3px); } | |
| /* Busy state: a hairline sweep along the bottom edge */ | |
| .btn.is-busy { pointer-events: none; opacity: 0.75; } | |
| .btn.is-busy::after { | |
| content: ""; | |
| position: absolute; | |
| left: 0; right: 0; bottom: 0; | |
| height: 2px; | |
| overflow: hidden; | |
| background: | |
| linear-gradient(90deg, transparent, currentColor, transparent) ; | |
| background-size: 40% 100%; | |
| background-repeat: no-repeat; | |
| animation: btn-sweep 1.1s linear infinite; | |
| } | |
| @keyframes btn-sweep { | |
| from { background-position: -50% 0; } | |
| to { background-position: 150% 0; } | |
| } | |
| /* ========================================================================== | |
| 03 — TAGS, CHIPS, PILLS | |
| ========================================================================== */ | |
| .tag { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: var(--sp-2); | |
| padding: 0.3rem 0.55rem; | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| font-weight: var(--fw-medium); | |
| letter-spacing: var(--tr-label); | |
| text-transform: uppercase; | |
| line-height: 1; | |
| border: var(--rule) solid var(--line); | |
| border-radius: var(--r-1); | |
| color: var(--ink-secondary); | |
| white-space: nowrap; | |
| } | |
| .tag--accent { | |
| border-color: var(--accent-line); | |
| background: var(--accent-wash); | |
| color: var(--accent-ink); | |
| } | |
| .tag--fill { | |
| background: var(--accent); | |
| border-color: var(--accent); | |
| color: var(--accent-on); | |
| } | |
| .tag--dot::before { | |
| content: ""; | |
| width: 0.4rem; height: 0.4rem; | |
| border-radius: 50%; | |
| background: var(--accent); | |
| flex: none; | |
| } | |
| /* Live/offline status */ | |
| .status-dot { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: var(--sp-2); | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| letter-spacing: var(--tr-label); | |
| text-transform: uppercase; | |
| color: var(--ink-muted); | |
| } | |
| .status-dot::before { | |
| content: ""; | |
| width: 0.4rem; height: 0.4rem; | |
| border-radius: 50%; | |
| background: var(--green-700); | |
| flex: none; | |
| } | |
| .status-dot[data-status="offline"]::before { background: var(--ink-faint); } | |
| .status-dot[data-status="degraded"]::before { background: var(--orange-600); } | |
| .status-dot[data-status="live"]::before { animation: pulse-soft 2.4s ease-in-out infinite; } | |
| /* Filter chip */ | |
| .chip { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: var(--sp-2); | |
| padding: 0.5rem 0.85rem; | |
| min-height: 2.25rem; | |
| font-size: var(--t-12); | |
| font-weight: var(--fw-medium); | |
| letter-spacing: var(--tr-none); | |
| border: var(--rule) solid var(--line); | |
| border-radius: var(--r-pill); | |
| color: var(--ink-secondary); | |
| background: transparent; | |
| cursor: pointer; | |
| transition: all var(--dur-2) var(--ease); | |
| } | |
| .chip:hover { border-color: var(--ink); color: var(--ink); } | |
| .chip[aria-pressed="true"], | |
| .chip.is-active { | |
| background: var(--ink); | |
| border-color: var(--ink); | |
| color: var(--ink-inverse); | |
| } | |
| .chip__count { | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| opacity: 0.6; | |
| } | |
| /* ========================================================================== | |
| 04 — LAB CARD (grid + list views) | |
| ========================================================================== */ | |
| .lab-card { | |
| position: relative; | |
| display: flex; | |
| flex-direction: column; | |
| background: var(--paper-raised); | |
| border: var(--rule) solid var(--line); | |
| border-radius: var(--r-2); | |
| overflow: hidden; | |
| transition: border-color var(--dur-2) var(--ease), | |
| transform var(--dur-3) var(--ease), | |
| box-shadow var(--dur-3) var(--ease); | |
| } | |
| .lab-card:hover, | |
| .lab-card:focus-within { | |
| border-color: var(--accent); | |
| transform: translateY(-3px); | |
| box-shadow: var(--shadow-md); | |
| } | |
| /* Whole card is clickable; the CTA carries the accessible name */ | |
| .lab-card__link::after { | |
| content: ""; | |
| position: absolute; | |
| inset: 0; | |
| } | |
| .lab-card__thumb { | |
| position: relative; | |
| aspect-ratio: 16 / 10; | |
| background: var(--accent-wash); | |
| border-bottom: var(--rule) solid var(--line); | |
| overflow: hidden; | |
| display: grid; | |
| place-items: center; | |
| } | |
| .lab-card__thumb canvas, | |
| .lab-card__thumb svg { width: 100%; height: 100%; display: block; } | |
| .lab-card__num { | |
| position: absolute; | |
| top: var(--sp-3); | |
| left: var(--sp-4); | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| letter-spacing: var(--tr-label); | |
| color: var(--accent-ink); | |
| z-index: 2; | |
| } | |
| .lab-card__body { | |
| padding: var(--sp-5); | |
| display: flex; | |
| flex-direction: column; | |
| gap: var(--sp-3); | |
| flex: 1; | |
| } | |
| .lab-card__title { | |
| font-family: var(--font-display); | |
| font-size: var(--t-28); | |
| line-height: var(--lh-tight); | |
| letter-spacing: var(--tr-tight); | |
| } | |
| .lab-card__desc { | |
| font-size: var(--t-14); | |
| line-height: var(--lh-prose); | |
| color: var(--ink-secondary); | |
| text-wrap: pretty; | |
| } | |
| .lab-card__meta { | |
| margin-top: auto; | |
| padding-top: var(--sp-4); | |
| border-top: var(--rule) solid var(--line); | |
| display: grid; | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| gap: var(--sp-3) var(--sp-4); | |
| } | |
| .meta-pair { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; } | |
| .meta-pair dt { | |
| font-family: var(--font-mono); | |
| font-size: var(--t-9); | |
| letter-spacing: var(--tr-caps); | |
| text-transform: uppercase; | |
| color: var(--ink-faint); | |
| } | |
| .meta-pair dd { | |
| font-size: var(--t-12); | |
| font-weight: var(--fw-medium); | |
| color: var(--ink); | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| white-space: nowrap; | |
| } | |
| .lab-card__cta { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: var(--sp-2); | |
| font-size: var(--t-13, 0.8125rem); | |
| font-weight: var(--fw-semi); | |
| color: var(--accent-ink); | |
| letter-spacing: var(--tr-mid); | |
| } | |
| .lab-card:hover .lab-card__cta .btn__arrow { transform: translateX(4px); } | |
| /* List view: same markup, editorial row layout */ | |
| .lab-grid[data-view="list"] { | |
| display: block; | |
| border-top: var(--rule) solid var(--line-ink); | |
| } | |
| .lab-grid[data-view="list"] .lab-card { | |
| display: grid; | |
| grid-template-columns: 3.5rem minmax(0, 1.1fr) minmax(0, 1.4fr) auto; | |
| align-items: center; | |
| gap: var(--sp-5); | |
| border: none; | |
| border-bottom: var(--rule) solid var(--line); | |
| border-radius: 0; | |
| padding: var(--sp-5) var(--sp-2); | |
| transform: none; | |
| box-shadow: none; | |
| background: transparent; | |
| } | |
| .lab-grid[data-view="list"] .lab-card:hover { | |
| background: var(--accent-wash); | |
| transform: none; | |
| } | |
| .lab-grid[data-view="list"] .lab-card__thumb { display: none; } | |
| .lab-grid[data-view="list"] .lab-card__body { | |
| display: contents; | |
| } | |
| .lab-grid[data-view="list"] .lab-card__num { | |
| position: static; | |
| align-self: center; | |
| } | |
| .lab-grid[data-view="list"] .lab-card__title { font-size: var(--t-24); } | |
| .lab-grid[data-view="list"] .lab-card__tags { display: none; } | |
| .lab-grid[data-view="list"] .lab-card__desc { | |
| font-size: var(--t-14); | |
| margin: 0; | |
| } | |
| .lab-grid[data-view="list"] .lab-card__meta { | |
| border: none; | |
| padding: 0; | |
| margin: 0; | |
| grid-template-columns: repeat(4, minmax(0, 1fr)); | |
| gap: var(--sp-4); | |
| } | |
| @media (max-width: 900px) { | |
| .lab-grid[data-view="list"] .lab-card { | |
| grid-template-columns: 2.5rem minmax(0, 1fr); | |
| gap: var(--sp-3); | |
| } | |
| .lab-grid[data-view="list"] .lab-card__meta { grid-template-columns: repeat(2, 1fr); } | |
| } | |
| /* View switcher */ | |
| .view-switch { | |
| display: inline-flex; | |
| border: var(--rule) solid var(--line); | |
| border-radius: var(--r-2); | |
| overflow: hidden; | |
| } | |
| .view-switch button { | |
| display: grid; | |
| place-items: center; | |
| width: 2.4rem; | |
| height: 2.25rem; | |
| color: var(--ink-muted); | |
| transition: all var(--dur-2) var(--ease); | |
| } | |
| .view-switch button + button { border-left: var(--rule) solid var(--line); } | |
| .view-switch button[aria-pressed="true"] { | |
| background: var(--ink); | |
| color: var(--ink-inverse); | |
| } | |
| .view-switch svg { width: 1rem; height: 1rem; } | |
| /* ========================================================================== | |
| 05 — PANELS | |
| ========================================================================== */ | |
| .panel { | |
| border: var(--rule) solid var(--line); | |
| border-radius: var(--r-2); | |
| background: var(--paper-raised); | |
| overflow: hidden; | |
| } | |
| .panel--flush { border-radius: 0; border-inline: none; } | |
| .panel--wash { background: var(--accent-wash); border-color: var(--accent-line); } | |
| .panel__head { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--sp-3); | |
| padding: var(--sp-4) var(--sp-5); | |
| border-bottom: var(--rule) solid var(--line); | |
| } | |
| .panel__body { padding: var(--sp-5); } | |
| .panel__foot { | |
| padding: var(--sp-4) var(--sp-5); | |
| border-top: var(--rule) solid var(--line); | |
| background: var(--paper-sunk); | |
| } | |
| /* Disclosure panel — "How it works", "What to notice", technical toggles */ | |
| .disclosure { | |
| border-top: var(--rule) solid var(--line); | |
| } | |
| .disclosure:last-of-type { border-bottom: var(--rule) solid var(--line); } | |
| .disclosure__trigger { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--sp-4); | |
| width: 100%; | |
| padding: var(--sp-4) 0; | |
| text-align: left; | |
| font-size: var(--t-14); | |
| font-weight: var(--fw-semi); | |
| letter-spacing: var(--tr-mid); | |
| color: var(--ink); | |
| transition: color var(--dur-2) var(--ease); | |
| } | |
| .disclosure__trigger:hover { color: var(--accent-ink); } | |
| .disclosure__trigger .mono { color: var(--ink-faint); flex: none; } | |
| .disclosure__icon { | |
| margin-left: auto; | |
| width: 0.875rem; height: 0.875rem; | |
| flex: none; | |
| transition: transform var(--dur-3) var(--ease); | |
| } | |
| .disclosure__trigger[aria-expanded="true"] .disclosure__icon { | |
| transform: rotate(45deg); | |
| } | |
| .disclosure__content { | |
| display: grid; | |
| grid-template-rows: 0fr; | |
| transition: grid-template-rows var(--dur-3) var(--ease); | |
| } | |
| .disclosure__content > div { overflow: hidden; } | |
| .disclosure.is-open .disclosure__content { grid-template-rows: 1fr; } | |
| .disclosure__inner { padding-bottom: var(--sp-5); } | |
| /* Educational callout */ | |
| .callout { | |
| border-left: var(--rule-thick) solid var(--accent); | |
| background: var(--accent-wash); | |
| padding: var(--sp-4) var(--sp-5); | |
| border-radius: 0 var(--r-2) var(--r-2) 0; | |
| } | |
| .callout__label { | |
| display: block; | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| letter-spacing: var(--tr-caps); | |
| text-transform: uppercase; | |
| color: var(--accent-ink); | |
| margin-bottom: var(--sp-2); | |
| } | |
| .callout p { | |
| font-size: var(--t-14); | |
| line-height: var(--lh-prose); | |
| color: var(--ink-secondary); | |
| } | |
| /* Notice list — "What to notice" bullets, numbered and hairline separated */ | |
| .notice-list { counter-reset: notice; } | |
| .notice-list li { | |
| counter-increment: notice; | |
| display: grid; | |
| grid-template-columns: 2rem minmax(0, 1fr); | |
| gap: var(--sp-3); | |
| padding: var(--sp-4) 0; | |
| border-top: var(--rule) solid var(--line); | |
| font-size: var(--t-14); | |
| line-height: var(--lh-prose); | |
| color: var(--ink-secondary); | |
| } | |
| .notice-list li::before { | |
| content: counter(notice, decimal-leading-zero); | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| letter-spacing: var(--tr-label); | |
| color: var(--accent-ink); | |
| padding-top: 0.25rem; | |
| } | |
| /* ========================================================================== | |
| 06 — FORM CONTROLS | |
| ========================================================================== */ | |
| .field { display: flex; flex-direction: column; gap: var(--sp-2); } | |
| .field__label { | |
| display: flex; | |
| align-items: baseline; | |
| gap: var(--sp-2); | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| letter-spacing: var(--tr-caps); | |
| text-transform: uppercase; | |
| color: var(--ink-muted); | |
| } | |
| .field__value { | |
| margin-left: auto; | |
| font-family: var(--font-mono); | |
| font-size: var(--t-11); | |
| color: var(--accent-ink); | |
| font-variant-numeric: tabular-nums; | |
| } | |
| .field__hint { | |
| font-size: var(--t-12); | |
| line-height: var(--lh-prose); | |
| color: var(--ink-faint); | |
| } | |
| .input, | |
| .textarea, | |
| .select { | |
| width: 100%; | |
| padding: 0.7rem 0.875rem; | |
| min-height: 2.75rem; | |
| background: var(--field); | |
| color: var(--ink); | |
| border: var(--rule) solid var(--field-line); | |
| border-radius: var(--r-2); | |
| font-size: var(--t-14); | |
| line-height: var(--lh-body); | |
| transition: border-color var(--dur-2) var(--ease), | |
| box-shadow var(--dur-2) var(--ease); | |
| } | |
| .input:hover, .textarea:hover, .select:hover { border-color: var(--line-strong); } | |
| .input:focus, .textarea:focus, .select:focus { | |
| border-color: var(--accent); | |
| box-shadow: 0 0 0 3px var(--accent-wash); | |
| outline: none; | |
| } | |
| .input::placeholder, .textarea::placeholder { color: var(--ink-faint); } | |
| .textarea { | |
| resize: vertical; | |
| min-height: 6.5rem; | |
| font-family: var(--font-sans); | |
| } | |
| .textarea--mono { font-family: var(--font-mono); font-size: var(--t-13, 0.8125rem); } | |
| .select { | |
| appearance: none; | |
| padding-right: 2.25rem; | |
| background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%23747474' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E"); | |
| background-repeat: no-repeat; | |
| background-position: right 0.875rem center; | |
| background-size: 0.7rem; | |
| cursor: pointer; | |
| } | |
| /* --- Range ------------------------------------------------------------- */ | |
| .range { | |
| -webkit-appearance: none; | |
| appearance: none; | |
| width: 100%; | |
| height: 2rem; /* generous hit area for touch */ | |
| background: transparent; | |
| cursor: pointer; | |
| } | |
| .range::-webkit-slider-runnable-track { | |
| height: 2px; | |
| background: var(--line-strong); | |
| border-radius: var(--r-pill); | |
| } | |
| .range::-moz-range-track { | |
| height: 2px; | |
| background: var(--line-strong); | |
| border-radius: var(--r-pill); | |
| } | |
| .range::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| width: 1.05rem; height: 1.05rem; | |
| margin-top: -0.5rem; | |
| border-radius: 50%; | |
| background: var(--accent); | |
| border: 2px solid var(--paper); | |
| box-shadow: 0 0 0 1px var(--accent); | |
| transition: transform var(--dur-1) var(--ease); | |
| } | |
| .range::-moz-range-thumb { | |
| width: 1.05rem; height: 1.05rem; | |
| border-radius: 50%; | |
| background: var(--accent); | |
| border: 2px solid var(--paper); | |
| box-shadow: 0 0 0 1px var(--accent); | |
| } | |
| .range:hover::-webkit-slider-thumb { transform: scale(1.15); } | |
| .range:active::-webkit-slider-thumb { transform: scale(0.95); } | |
| /* --- Segmented control ------------------------------------------------- */ | |
| .segmented { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0; | |
| border: var(--rule) solid var(--line); | |
| border-radius: var(--r-2); | |
| overflow: hidden; | |
| } | |
| .segmented button { | |
| flex: 1 1 auto; | |
| padding: 0.55rem 0.75rem; | |
| min-height: 2.5rem; | |
| font-size: var(--t-12); | |
| font-weight: var(--fw-medium); | |
| color: var(--ink-secondary); | |
| background: transparent; | |
| transition: all var(--dur-2) var(--ease); | |
| white-space: nowrap; | |
| } | |
| .segmented button + button { border-left: var(--rule) solid var(--line); } | |
| .segmented button:hover { background: var(--paper-sunk); color: var(--ink); } | |
| .segmented button[aria-pressed="true"] { | |
| background: var(--accent); | |
| color: var(--accent-on); | |
| } | |
| /* --- Option cards (persona, style, journey) ---------------------------- */ | |
| .option-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(min(8.5rem, 100%), 1fr)); | |
| gap: var(--sp-2); | |
| } | |
| .option { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.35rem; | |
| padding: var(--sp-3) var(--sp-4); | |
| min-height: 3.5rem; | |
| text-align: left; | |
| border: var(--rule) solid var(--line); | |
| border-radius: var(--r-2); | |
| background: transparent; | |
| color: var(--ink-secondary); | |
| cursor: pointer; | |
| transition: all var(--dur-2) var(--ease); | |
| } | |
| .option:hover { border-color: var(--ink); color: var(--ink); } | |
| .option[aria-pressed="true"] { | |
| border-color: var(--accent); | |
| background: var(--accent-wash); | |
| color: var(--ink); | |
| } | |
| .option__name { | |
| font-size: var(--t-14); | |
| font-weight: var(--fw-semi); | |
| letter-spacing: var(--tr-mid); | |
| } | |
| .option__desc { font-size: var(--t-11); color: var(--ink-faint); line-height: 1.35; } | |
| /* --- Dropzone ---------------------------------------------------------- */ | |
| .dropzone { | |
| position: relative; | |
| display: grid; | |
| place-items: center; | |
| gap: var(--sp-3); | |
| padding: var(--sp-8) var(--sp-5); | |
| min-height: 12rem; | |
| text-align: center; | |
| border: var(--rule) dashed var(--line-strong); | |
| border-radius: var(--r-2); | |
| background: var(--paper-sunk); | |
| cursor: pointer; | |
| transition: all var(--dur-2) var(--ease); | |
| } | |
| .dropzone:hover { border-color: var(--accent); background: var(--accent-wash); } | |
| .dropzone.is-dragging { | |
| border-color: var(--accent); | |
| border-style: solid; | |
| background: var(--accent-wash); | |
| transform: scale(1.005); | |
| } | |
| .dropzone__icon { width: 1.75rem; height: 1.75rem; color: var(--ink-faint); } | |
| .dropzone.is-dragging .dropzone__icon { color: var(--accent-ink); } | |
| .dropzone__title { font-size: var(--t-14); font-weight: var(--fw-semi); } | |
| .dropzone__hint { font-size: var(--t-12); color: var(--ink-faint); } | |
| .dropzone input[type="file"] { | |
| position: absolute; | |
| inset: 0; | |
| opacity: 0; | |
| cursor: pointer; | |
| } | |
| /* Sample thumbnails so the labs are usable without an upload */ | |
| .samples { display: flex; gap: var(--sp-2); flex-wrap: wrap; } | |
| .sample { | |
| width: 3.25rem; height: 3.25rem; | |
| border: var(--rule) solid var(--line); | |
| border-radius: var(--r-2); | |
| overflow: hidden; | |
| cursor: pointer; | |
| padding: 0; | |
| transition: all var(--dur-2) var(--ease); | |
| } | |
| .sample:hover { border-color: var(--accent); transform: translateY(-2px); } | |
| .sample canvas, .sample img { width: 100%; height: 100%; object-fit: cover; } | |
| /* ========================================================================== | |
| 07 — STATES: loading, empty, error, timeout | |
| ========================================================================== */ | |
| .state { | |
| display: grid; | |
| place-items: center; | |
| gap: var(--sp-4); | |
| padding: var(--sp-8) var(--sp-5); | |
| text-align: center; | |
| min-height: 14rem; | |
| } | |
| .state__icon { width: 2rem; height: 2rem; color: var(--ink-faint); } | |
| .state__title { font-size: var(--t-16); font-weight: var(--fw-semi); } | |
| .state__text { | |
| font-size: var(--t-14); | |
| line-height: var(--lh-prose); | |
| color: var(--ink-muted); | |
| max-width: 26rem; | |
| text-wrap: pretty; | |
| } | |
| .state--error .state__icon { color: var(--red-800); } | |
| [data-theme="dark"] .state--error .state__icon { color: var(--red-500); } | |
| /* Indeterminate hairline progress */ | |
| .progress-line { | |
| position: relative; | |
| height: 2px; | |
| width: min(20rem, 100%); | |
| background: var(--line); | |
| overflow: hidden; | |
| } | |
| .progress-line::after { | |
| content: ""; | |
| position: absolute; | |
| inset-block: 0; | |
| width: 33%; | |
| background: var(--accent); | |
| animation: sweep 1.4s var(--ease-in-out) infinite; | |
| } | |
| .progress-line[data-determinate]::after { | |
| animation: none; | |
| width: var(--progress, 0%); | |
| transition: width var(--dur-3) var(--ease); | |
| } | |
| /* Skeleton */ | |
| .skeleton { | |
| background: linear-gradient(90deg, | |
| var(--paper-sunk) 25%, | |
| color-mix(in srgb, var(--paper-sunk) 60%, var(--line)) 37%, | |
| var(--paper-sunk) 63%); | |
| background-size: 400% 100%; | |
| animation: skeleton 1.4s ease infinite; | |
| border-radius: var(--r-2); | |
| } | |
| @keyframes skeleton { | |
| from { background-position: 100% 50%; } | |
| to { background-position: 0 50%; } | |
| } | |
| /* Step ticker — shows what the pipeline is doing, not just that it is busy */ | |
| .steps { display: flex; flex-direction: column; gap: var(--sp-2); text-align: left; } | |
| .step { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--sp-3); | |
| font-family: var(--font-mono); | |
| font-size: var(--t-11); | |
| letter-spacing: var(--tr-label); | |
| text-transform: uppercase; | |
| color: var(--ink-faint); | |
| transition: color var(--dur-2) var(--ease); | |
| } | |
| .step::before { | |
| content: ""; | |
| width: 0.4rem; height: 0.4rem; | |
| border-radius: 50%; | |
| background: currentColor; | |
| flex: none; | |
| } | |
| .step.is-active { color: var(--accent-ink); } | |
| .step.is-active::before { animation: pulse-soft 1.2s ease-in-out infinite; } | |
| .step.is-done { color: var(--ink-secondary); } | |
| /* ========================================================================== | |
| 08 — VISUALISATION CHROME | |
| ========================================================================== */ | |
| /* Before/after comparison slider */ | |
| .compare { | |
| position: relative; | |
| overflow: hidden; | |
| border-radius: var(--r-2); | |
| background: var(--paper-sunk); | |
| touch-action: pan-y; /* horizontal drag belongs to the handle */ | |
| user-select: none; | |
| cursor: ew-resize; | |
| } | |
| .compare img, | |
| .compare canvas { | |
| display: block; | |
| width: 100%; | |
| height: auto; | |
| -webkit-user-drag: none; | |
| user-select: none; | |
| } | |
| .compare__after { | |
| position: absolute; | |
| inset: 0; | |
| overflow: hidden; | |
| width: var(--pos, 50%); | |
| } | |
| .compare__after img, | |
| .compare__after canvas { | |
| position: absolute; | |
| top: 0; left: 0; | |
| width: var(--frame-w, 100%); | |
| height: 100%; | |
| max-width: none; | |
| object-fit: cover; | |
| } | |
| .compare__handle { | |
| position: absolute; | |
| top: 0; bottom: 0; | |
| left: var(--pos, 50%); | |
| width: 2px; | |
| background: var(--paper); | |
| transform: translateX(-1px); | |
| box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25); | |
| z-index: 3; | |
| } | |
| .compare__grip { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| width: 2.5rem; height: 2.5rem; | |
| border-radius: 50%; | |
| background: var(--paper); | |
| border: var(--rule) solid var(--line-strong); | |
| display: grid; | |
| place-items: center; | |
| color: var(--ink); | |
| cursor: ew-resize; | |
| box-shadow: var(--shadow-md); | |
| } | |
| .compare__grip svg { width: 1rem; height: 1rem; } | |
| .compare__tag { | |
| position: absolute; | |
| top: var(--sp-3); | |
| padding: 0.25rem 0.5rem; | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| letter-spacing: var(--tr-label); | |
| text-transform: uppercase; | |
| background: rgba(0, 0, 0, 0.72); | |
| color: #fff; | |
| border-radius: var(--r-1); | |
| z-index: 2; | |
| pointer-events: none; | |
| } | |
| .compare__tag--before { left: var(--sp-3); } | |
| .compare__tag--after { right: var(--sp-3); } | |
| /* Confidence bar */ | |
| .conf-row { | |
| display: grid; | |
| grid-template-columns: minmax(0, 1fr) 3.25rem; | |
| align-items: center; | |
| gap: var(--sp-3); | |
| padding: var(--sp-3) 0; | |
| border-top: var(--rule) solid var(--line); | |
| cursor: default; | |
| } | |
| .conf-row:first-child { border-top: none; } | |
| .conf-row.is-hot { background: var(--accent-wash); } | |
| .conf-row__label { | |
| font-size: var(--t-13, 0.8125rem); | |
| font-weight: var(--fw-medium); | |
| margin-bottom: var(--sp-2); | |
| display: flex; | |
| align-items: center; | |
| gap: var(--sp-2); | |
| } | |
| .conf-row__swatch { | |
| width: 0.55rem; height: 0.55rem; | |
| border-radius: 2px; | |
| flex: none; | |
| } | |
| .conf-bar { | |
| height: 4px; | |
| background: var(--paper-sunk); | |
| border-radius: var(--r-pill); | |
| overflow: hidden; | |
| } | |
| .conf-bar__fill { | |
| height: 100%; | |
| width: 0; | |
| background: var(--accent); | |
| border-radius: inherit; | |
| transition: width var(--dur-4) var(--ease); | |
| } | |
| .conf-row__value { | |
| font-family: var(--font-mono); | |
| font-size: var(--t-12); | |
| font-variant-numeric: tabular-nums; | |
| text-align: right; | |
| color: var(--ink); | |
| } | |
| /* Overlay canvas for bounding boxes */ | |
| .overlay-frame { | |
| position: relative; | |
| display: inline-block; | |
| width: 100%; | |
| line-height: 0; | |
| border-radius: var(--r-2); | |
| overflow: hidden; | |
| background: var(--paper-sunk); | |
| } | |
| .overlay-frame img { width: 100%; height: auto; } | |
| .overlay-frame canvas { | |
| position: absolute; | |
| inset: 0; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| /* Legend */ | |
| .legend { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--sp-3); | |
| flex-wrap: wrap; | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| letter-spacing: var(--tr-label); | |
| text-transform: uppercase; | |
| color: var(--ink-muted); | |
| } | |
| .legend__scale { | |
| flex: 1 1 8rem; | |
| height: 0.5rem; | |
| border-radius: var(--r-pill); | |
| border: var(--rule) solid var(--line); | |
| } | |
| /* Metric readouts under a result */ | |
| .metrics { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr)); | |
| gap: var(--sp-4); | |
| padding-top: var(--sp-4); | |
| border-top: var(--rule) solid var(--line); | |
| } | |
| .metric { display: flex; flex-direction: column; gap: 0.2rem; } | |
| .metric__value { | |
| font-family: var(--font-mono); | |
| font-size: var(--t-21); | |
| font-variant-numeric: tabular-nums; | |
| letter-spacing: var(--tr-tight); | |
| color: var(--ink); | |
| } | |
| .metric__label { | |
| font-family: var(--font-mono); | |
| font-size: var(--t-9); | |
| letter-spacing: var(--tr-caps); | |
| text-transform: uppercase; | |
| color: var(--ink-faint); | |
| } | |
| /* ========================================================================== | |
| 09 — EXPLAIN MODE | |
| Annotations that only appear when the user turns explanations on. | |
| ========================================================================== */ | |
| .explain { display: none; } | |
| [data-explain="on"] .explain { display: block; } | |
| [data-explain="on"] .explain--inline { display: inline; } | |
| [data-explain="on"] .explain--flex { display: flex; } | |
| .explain-note { | |
| position: relative; | |
| margin-top: var(--sp-3); | |
| padding: var(--sp-3) var(--sp-4); | |
| border: var(--rule) dashed var(--accent-line); | |
| border-radius: var(--r-2); | |
| background: var(--accent-wash); | |
| font-size: var(--t-12); | |
| line-height: var(--lh-prose); | |
| color: var(--ink-secondary); | |
| animation: rise var(--dur-3) var(--ease); | |
| } | |
| .explain-note__label { | |
| display: block; | |
| font-family: var(--font-mono); | |
| font-size: var(--t-9); | |
| letter-spacing: var(--tr-caps); | |
| text-transform: uppercase; | |
| color: var(--accent-ink); | |
| margin-bottom: var(--sp-1); | |
| } | |
| /* Explain toggle in the nav */ | |
| .explain-toggle { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: var(--sp-2); | |
| padding: 0.4rem 0.7rem; | |
| min-height: 2.25rem; | |
| border: var(--rule) solid var(--line); | |
| border-radius: var(--r-pill); | |
| font-family: var(--font-mono); | |
| font-size: var(--t-10); | |
| letter-spacing: var(--tr-label); | |
| text-transform: uppercase; | |
| color: var(--ink-muted); | |
| transition: all var(--dur-2) var(--ease); | |
| } | |
| .explain-toggle:hover { border-color: var(--ink); color: var(--ink); } | |
| .explain-toggle[aria-pressed="true"] { | |
| background: var(--yellow-400); | |
| border-color: var(--yellow-500); | |
| color: var(--gray-900); | |
| } | |
| .explain-toggle__dot { | |
| width: 0.4rem; height: 0.4rem; | |
| border-radius: 50%; | |
| background: currentColor; | |
| opacity: 0.4; | |
| } | |
| .explain-toggle[aria-pressed="true"] .explain-toggle__dot { opacity: 1; } | |
| /* Inline term with a definition on hover/focus */ | |
| .term { | |
| border-bottom: var(--rule) dashed var(--ink-faint); | |
| cursor: help; | |
| position: relative; | |
| } | |
| .term:hover, .term:focus-visible { border-bottom-color: var(--accent); } | |
| .tip { | |
| position: absolute; | |
| bottom: calc(100% + 0.5rem); | |
| left: 50%; | |
| transform: translateX(-50%) translateY(4px); | |
| width: max-content; | |
| max-width: 17rem; | |
| padding: var(--sp-3); | |
| background: var(--paper-inverse); | |
| color: var(--paper); | |
| font-family: var(--font-sans); | |
| font-size: var(--t-11); | |
| line-height: 1.45; | |
| letter-spacing: 0; | |
| text-transform: none; | |
| border-radius: var(--r-2); | |
| box-shadow: var(--shadow-lg); | |
| opacity: 0; | |
| pointer-events: none; | |
| transition: opacity var(--dur-2) var(--ease), | |
| transform var(--dur-2) var(--ease); | |
| z-index: var(--z-modal); | |
| } | |
| .term:hover .tip, | |
| .term:focus-visible .tip { | |
| opacity: 1; | |
| transform: translateX(-50%) translateY(0); | |
| } | |
| /* ========================================================================== | |
| 10 — DIALOG, TOAST | |
| ========================================================================== */ | |
| .dialog { | |
| position: fixed; | |
| inset: 0; | |
| z-index: var(--z-modal); | |
| display: grid; | |
| place-items: center; | |
| padding: var(--sp-5); | |
| visibility: hidden; | |
| pointer-events: none; | |
| } | |
| .dialog.is-open { visibility: visible; pointer-events: auto; } | |
| .dialog__scrim { | |
| position: absolute; | |
| inset: 0; | |
| background: var(--scrim); | |
| opacity: 0; | |
| transition: opacity var(--dur-3) var(--ease); | |
| } | |
| .dialog.is-open .dialog__scrim { opacity: 1; } | |
| .dialog__panel { | |
| position: relative; | |
| width: min(46rem, 100%); | |
| max-height: min(85vh, 48rem); | |
| overflow-y: auto; | |
| background: var(--paper); | |
| border: var(--rule) solid var(--line); | |
| border-radius: var(--r-3); | |
| box-shadow: var(--shadow-lg); | |
| opacity: 0; | |
| transform: translateY(1rem) scale(0.99); | |
| transition: opacity var(--dur-3) var(--ease), | |
| transform var(--dur-3) var(--ease); | |
| } | |
| .dialog.is-open .dialog__panel { opacity: 1; transform: none; } | |
| .dialog__head { | |
| position: sticky; | |
| top: 0; | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: var(--sp-4); | |
| padding: var(--sp-5) var(--sp-6); | |
| border-bottom: var(--rule) solid var(--line); | |
| background: var(--paper); | |
| z-index: 2; | |
| } | |
| .dialog__body { padding: var(--sp-6); } | |
| .toast-stack { | |
| position: fixed; | |
| bottom: var(--sp-5); | |
| left: 50%; | |
| transform: translateX(-50%); | |
| z-index: var(--z-toast); | |
| display: flex; | |
| flex-direction: column; | |
| gap: var(--sp-2); | |
| width: min(28rem, calc(100vw - 2rem)); | |
| pointer-events: none; | |
| } | |
| .toast { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: var(--sp-3); | |
| padding: var(--sp-4); | |
| background: var(--paper-inverse); | |
| color: var(--paper); | |
| border-radius: var(--r-2); | |
| box-shadow: var(--shadow-lg); | |
| font-size: var(--t-13, 0.8125rem); | |
| line-height: var(--lh-prose); | |
| animation: rise var(--dur-3) var(--ease); | |
| pointer-events: auto; | |
| } | |
| .toast__bar { width: 2px; align-self: stretch; background: var(--accent); flex: none; } | |
| .toast[data-tone="error"] .toast__bar { background: var(--red-700); } | |
| .toast[data-tone="success"] .toast__bar { background: var(--green-600); } | |
| /* ========================================================================== | |
| 11 — FOOTER | |
| ========================================================================== */ | |
| .site-footer { | |
| border-top: var(--rule) solid var(--line-ink); | |
| padding-block: var(--sp-9) var(--sp-7); | |
| margin-top: var(--sp-6); | |
| } | |
| .site-footer__grid { | |
| display: grid; | |
| grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr)); | |
| gap: var(--sp-7) var(--sp-6); | |
| } | |
| .site-footer__col-title { | |
| margin-bottom: var(--sp-4); | |
| padding-bottom: var(--sp-3); | |
| border-bottom: var(--rule) solid var(--line); | |
| display: block; | |
| } | |
| .site-footer__link { | |
| display: block; | |
| padding: var(--sp-2) 0; | |
| font-size: var(--t-14); | |
| color: var(--ink-secondary); | |
| transition: color var(--dur-2) var(--ease), padding-left var(--dur-2) var(--ease); | |
| } | |
| .site-footer__link:hover { color: var(--accent-ink); padding-left: var(--sp-2); } | |
| .site-footer__base { | |
| margin-top: var(--sp-8); | |
| padding-top: var(--sp-5); | |
| border-top: var(--rule) solid var(--line); | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: var(--sp-4); | |
| align-items: center; | |
| justify-content: space-between; | |
| } | |
| @media (max-width: 900px) { | |
| .site-footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } | |
| } | |
| @media (max-width: 560px) { | |
| .site-footer__grid { grid-template-columns: 1fr; } | |
| } | |
| /* ========================================================================== | |
| 12 — UTILITIES | |
| ========================================================================== */ | |
| .hidden { display: none ; } | |
| .invisible { visibility: hidden; } | |
| .full { width: 100%; } | |
| .center { text-align: center; } | |
| .nowrap { white-space: nowrap; } | |
| .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } | |
| .scroll-x { | |
| overflow-x: auto; | |
| scrollbar-width: thin; | |
| -webkit-overflow-scrolling: touch; | |
| } | |
| .scroll-x::-webkit-scrollbar { height: 4px; } | |
| .scroll-x::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 2px; } | |