/* ============================================================ HydroPD design system: instrument, product discipline. Hanken Grotesk (display + UI/body) · Spline Sans Mono (data/codes/numerals). Self-hosted WOFF2, Latin subset, light theme only. See DESIGN.md. ============================================================ */ /* ---------- fonts (self-hosted, offline-safe) ---------- */ @font-face { font-family: 'Hanken Grotesk'; font-style: normal; font-weight: 400; font-display: swap; src: url('./assets/fonts/hanken-400.woff2') format('woff2'); } @font-face { font-family: 'Hanken Grotesk'; font-style: normal; font-weight: 600; font-display: swap; src: url('./assets/fonts/hanken-600.woff2') format('woff2'); } @font-face { font-family: 'Hanken Grotesk'; font-style: normal; font-weight: 800; font-display: swap; src: url('./assets/fonts/hanken-800.woff2') format('woff2'); } @font-face { font-family: 'Spline Sans Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('./assets/fonts/spline-mono-400.woff2') format('woff2'); } @font-face { font-family: 'Spline Sans Mono'; font-style: normal; font-weight: 600; font-display: swap; src: url('./assets/fonts/spline-mono-600.woff2') format('woff2'); } :root { /* ---- brand: deepened teal (committed identity, preserved) ---- */ --accent: oklch(0.55 0.09 182); /* borders, focus ring, selection, non-text accent */ --accent-strong: oklch(0.47 0.088 185); /* accent TEXT (links) + primary button bg (white passes AA) */ --accent-hover: oklch(0.40 0.08 186); /* primary button hover/active */ --accent-soft: oklch(0.95 0.03 185); /* selected rows, accent badges */ --accent-tint: oklch(0.975 0.016 185); /* 4-8% surface wash */ /* ---- secondary / info (data-viz + info states only, never decoration) ---- */ --blue: oklch(0.52 0.12 245); --blue-soft: oklch(0.94 0.035 245); /* ---- neutrals, tinted toward the brand hue (~205) ---- */ --bg: oklch(0.984 0.004 205); /* canvas */ --surface: oklch(0.997 0.0015 205); /* cards (lighter than canvas) */ --surface-2: oklch(0.963 0.005 205); /* nav, toolbars, table heads, insets */ --border: oklch(0.905 0.006 210); --border-strong: oklch(0.85 0.009 210); /* ---- ink ---- */ --text: oklch(0.28 0.02 225); --text-muted: oklch(0.49 0.018 225); /* AA body (>=4.5:1 on surface) */ --text-faint: oklch(0.60 0.014 225); /* captions / large only (>=3:1) */ /* ---- semantic (consistent meaning; AA on their -soft fills) ---- */ --good: oklch(0.50 0.11 155); --good-soft: oklch(0.94 0.04 158); --warn: oklch(0.50 0.10 60); --warn-soft: oklch(0.93 0.055 72); --bad: oklch(0.52 0.17 25); --bad-soft: oklch(0.93 0.05 25); /* ---- radii (over-rounding is a tell) ---- */ --radius-sm: 4px; --radius: 6px; --radius-lg: 8px; /* ---- shadow (used sparingly: navbar + floating elements) ---- */ --shadow: 0 1px 2px oklch(0.28 0.02 225 / 0.05), 0 6px 16px oklch(0.28 0.02 225 / 0.06); --shadow-sm: 0 1px 2px oklch(0.28 0.02 225 / 0.06); /* ---- spacing scale ---- */ --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 24px; --space-6: 32px; --space-7: 48px; --space-8: 64px; /* ---- type scale (fixed rem, ratio ~1.2) ---- */ --text-xs: 0.75rem; --text-sm: 0.875rem; --text-base: 1rem; --text-md: 1.125rem; --text-lg: 1.375rem; --text-xl: 1.75rem; --text-2xl: 2.25rem; --text-display: clamp(2.1rem, 1.55rem + 2.2vw, 2.75rem); /* single hero display only */ /* ---- families (grotesque display + UI, distinctive mono for data) ---- */ --font-display: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, system-ui, sans-serif; --font: 'Hanken Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; --mono: 'Spline Sans Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace; } * { box-sizing: border-box; } html, body, #root { margin: 0; padding: 0; min-height: 100%; } body { font-family: var(--font); font-size: var(--text-base); background: var(--bg); color: var(--text); line-height: 1.55; font-kerning: normal; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } a { color: var(--accent-strong); text-decoration: none; } a:hover { text-decoration: underline; } /* Grotesque display carries page and section headings; mono is reserved for data. */ h1, h2, h3 { font-family: var(--font-display); color: var(--text); font-weight: 800; line-height: 1.12; letter-spacing: -0.022em; text-wrap: balance; margin: 0 0 0.4em; } h4 { font-family: var(--font); color: var(--text); font-weight: 600; line-height: 1.3; margin: 0 0 0.4em; } h1 { font-size: var(--text-2xl); } h2 { font-size: var(--text-xl); } h3 { font-size: var(--text-lg); } h4 { font-size: var(--text-base); } p { margin: 0 0 1rem; text-wrap: pretty; } code, .mono { font-family: var(--mono); font-size: 0.85em; font-variant-numeric: tabular-nums; } /* Reduced-motion: honor globally; individual components add crossfade fallbacks. */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; } } /* ---------- layout ---------- */ .app-shell { display: flex; flex-direction: column; min-height: 100vh; } .navbar { position: sticky; top: 0; z-index: 20; background: var(--surface); border-bottom: 1px solid var(--border); box-shadow: var(--shadow-sm); } .navbar-inner { max-width: 1180px; margin: 0 auto; padding: 0 24px; height: 62px; display: flex; align-items: center; gap: 28px; } .brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--text); } .brand:hover { text-decoration: none; } .brand-mark { width: 30px; height: 30px; border-radius: var(--radius-sm); background: var(--accent-strong); display: grid; place-items: center; color: var(--surface); font-family: var(--font-display); font-weight: 600; font-size: 0.98rem; letter-spacing: 0; } .brand-name { font-family: var(--font-display); font-weight: 600; font-size: 1.2rem; letter-spacing: -0.01em; } .brand-tag { font-size: var(--text-xs); color: var(--text-muted); font-weight: 400; } .nav-links { display: flex; align-items: center; gap: 4px; margin-left: auto; flex-wrap: wrap; } .nav-link { padding: 7px 12px; border-radius: var(--radius-sm); color: var(--text-muted); font-size: var(--text-sm); font-weight: 500; transition: color 0.15s ease, background 0.15s ease; } .nav-link:hover { background: var(--surface-2); color: var(--text); text-decoration: none; } .nav-link.active { color: var(--accent-strong); background: var(--accent-soft); } .page { flex: 1; max-width: 1180px; width: 100%; margin: 0 auto; padding: var(--space-7) var(--space-6) var(--space-8); } .page-header { margin-bottom: var(--space-6); padding-bottom: var(--space-5); border-bottom: 1px solid var(--border); } .page-header h1 { font-size: var(--text-2xl); margin-bottom: var(--space-3); } .page-header p.lead { color: var(--text-muted); font-size: var(--text-md); max-width: 68ch; margin: 0; } /* The in-card labeled hairline-rule section device lives in `.type-detail-head`. */ .rule { height: 1px; background: var(--border); border: 0; margin: var(--space-5) 0; } .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; } @media (max-width: 860px) { .grid-2 { grid-template-columns: 1fr; } .nav-links { gap: 0; } } .footer { border-top: 1px solid var(--border); background: var(--surface-2); color: var(--text-muted); font-size: var(--text-sm); } .footer-inner { max-width: 1180px; margin: 0 auto; padding: var(--space-5) var(--space-6); display: flex; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; } /* ---------- card ---------- */ /* Editorial flat: hairline border carries the surface, no drop shadow (the hairline-border-plus-diffuse-shadow combo is an AI signature). */ .card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-5); } .card + .card { margin-top: var(--space-5); } .card-title { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-1); } .card-title h3 { margin: 0; } .card-subtitle { color: var(--text-muted); font-size: var(--text-sm); margin: 0 0 var(--space-4); } /* ---------- buttons ---------- */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: 7px; font-family: var(--font); font-size: var(--text-sm); font-weight: 600; padding: 9px 16px; border-radius: var(--radius-sm); border: 1px solid transparent; cursor: pointer; transition: background 0.15s ease, border-color 0.15s ease, opacity 0.15s ease; white-space: nowrap; } .btn:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--accent-soft); } .btn:disabled { opacity: 0.5; cursor: not-allowed; } .btn-primary { background: var(--accent-strong); color: var(--surface); } .btn-primary:hover:not(:disabled) { background: var(--accent-hover); } .btn-secondary { background: var(--surface); color: var(--text); border-color: var(--border-strong); } .btn-secondary:hover:not(:disabled) { background: var(--surface-2); border-color: var(--text-faint); } .btn-ghost { background: transparent; color: var(--accent-strong); padding: 6px 10px; } .btn-ghost:hover:not(:disabled) { background: var(--accent-soft); } .btn-sm { padding: 6px 11px; font-size: var(--text-xs); } /* ---------- forms ---------- */ .field { margin-bottom: 16px; } .field:last-child { margin-bottom: 0; } .field-label { display: block; font-weight: 600; font-size: var(--text-sm); margin-bottom: 6px; } .field-hint { color: var(--text-muted); font-size: var(--text-xs); font-weight: 400; margin-left: 6px; } input[type='text'], input[type='number'], select, textarea { width: 100%; font-family: var(--font); font-size: var(--text-sm); color: var(--text); background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius-sm); padding: 9px 11px; transition: border-color 0.15s ease, box-shadow 0.15s ease; } textarea { resize: vertical; min-height: 120px; font-family: var(--mono); font-size: var(--text-sm); line-height: 1.5; } input:focus-visible, select:focus-visible, textarea:focus-visible, input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); } /* ---------- badges → squared editorial tags ---------- */ .badge { display: inline-flex; align-items: center; gap: 5px; font-size: var(--text-xs); font-weight: 600; padding: 2px 8px; border-radius: var(--radius-sm); background: var(--surface-2); color: var(--text-muted); border: 1px solid var(--border); } .badge-accent { background: var(--accent-soft); color: var(--accent-strong); border-color: transparent; } .badge-blue { background: var(--blue-soft); color: var(--blue); border-color: transparent; } .badge-good { background: var(--good-soft); color: var(--good); border-color: transparent; } .badge-muted { background: var(--bg); color: var(--text-faint); } .badge-warn { background: var(--warn-soft); color: var(--warn); border-color: transparent; } /* ---------- condition matcher (detectability ranking) ---------- */ .cond-selects { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; margin-bottom: 12px; } .cond-select { display: flex; flex-direction: column; gap: 4px; font-size: 0.76rem; font-weight: 600; color: var(--text-muted); } .cond-select select { font: inherit; font-weight: 500; padding: 7px 8px; border-radius: var(--radius); border: 1px solid var(--border); background: var(--surface); color: var(--text); } .cond-ranked { display: flex; flex-direction: column; gap: 6px; padding: 10px; margin-bottom: 12px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); } .cond-rank-row { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); cursor: pointer; } .cond-rank-row:hover { border-color: var(--border-strong); } .cond-rank-row.selected { border-color: var(--accent-strong); box-shadow: inset 0 0 0 1px var(--accent-strong); } .cond-rank-pos { font-weight: 700; color: var(--accent-strong); min-width: 1.6em; text-align: center; } .cond-rank-body { display: flex; flex-direction: column; gap: 3px; flex: 1; } .cond-rank-title { font-size: 0.86rem; } .cond-rank-tags { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; } .cond-rank-tags .tag { font-size: 0.7rem; font-weight: 600; padding: 1px 7px; border-radius: var(--radius-sm); background: var(--surface-2); color: var(--text-faint); border: 1px solid var(--border); } .cond-rank-tags .tag.tag-on { background: var(--good-soft); color: var(--good); border-color: transparent; } /* ---------- bioactivity screening: activity filter + DB links ---------- */ .filter-block { margin-top: 14px; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); display: flex; flex-direction: column; gap: 10px; } .filter-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; } .filter-actions { display: flex; gap: 4px; } .filter-axis { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; } .filter-axis-label { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-faint); min-width: 84px; } .filter-chip { font: inherit; font-size: var(--text-xs); font-weight: 500; padding: 4px 11px; border-radius: var(--radius-sm); border: 1px solid var(--border-strong); background: var(--surface); color: var(--text-muted); cursor: pointer; transition: background 0.12s, color 0.12s, border-color 0.12s; } .filter-chip:hover { border-color: var(--accent-strong); } .filter-chip.on { background: var(--accent-soft); color: var(--accent-strong); border-color: transparent; font-weight: 600; } .db-links a { color: var(--accent-strong); text-decoration: none; border-bottom: 1px solid var(--accent-soft); white-space: nowrap; } .db-links a:hover { border-bottom-color: var(--accent-strong); } .selected-model { margin-top: 14px; padding: 8px 12px; border-radius: var(--radius); background: var(--accent-soft); color: var(--accent-strong); font-size: 0.82rem; font-weight: 500; } /* ---------- species accordion (model picker) ---------- */ .species-accordion { display: flex; flex-direction: column; gap: 6px; } .species-group { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface); } .species-group.open { border-color: var(--border-strong); } .species-head { display: flex; align-items: center; gap: 10px; width: 100%; padding: 9px 12px; background: var(--bg); border: 0; font: inherit; cursor: pointer; text-align: left; } .species-head:hover { background: var(--surface-2, var(--bg)); } .species-caret { color: var(--text-faint); font-size: 0.8rem; flex: none; } .species-name { font-weight: 600; text-transform: capitalize; } .species-count { color: var(--text-faint); font-size: 0.78rem; } .species-sel { margin-left: auto; } .species-body { padding: 8px; } /* In-card sub-section header: the labeled hairline-rule signature device. */ .type-detail-head { display: flex; align-items: center; gap: var(--space-4); font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin: var(--space-4) 0 var(--space-3); } .type-detail-head::after { content: ''; flex: 1; height: 1px; background: var(--border); } /* ---------- legend ---------- */ .legend { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 0.78rem; color: var(--text-muted); } .legend-item { display: inline-flex; align-items: center; gap: 6px; } .legend-swatch { width: 11px; height: 11px; border-radius: 3px; display: inline-block; } /* ---------- inline bar charts ---------- */ .bar-row { display: flex; align-items: center; gap: 10px; padding: 3px 0; font-size: 0.82rem; } .bar-label { flex: none; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .bar-track { position: relative; flex: 1; height: 15px; background: var(--bg); border: 1px solid var(--border); border-radius: 4px; overflow: hidden; min-width: 60px; } .bar-fill { position: absolute; top: 0; left: 0; height: 100%; border-radius: 4px 0 0 4px; } /* range whisker: vertical caps via inset shadow (not side borders). */ .bar-whisker { position: absolute; top: 50%; transform: translateY(-50%); height: 9px; box-shadow: inset 2px 0 0 var(--text), inset -2px 0 0 var(--text); opacity: 0.45; } .bar-value { flex: none; width: auto; min-width: 48px; text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; color: var(--text); } .bar-note { color: var(--text-faint); font-weight: 400; font-size: 0.74rem; } /* ---------- tables ---------- */ .table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); } table.table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); } .table thead th { background: var(--surface-2); text-align: left; font-weight: 600; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-muted); padding: 10px 14px; border-bottom: 1px solid var(--border-strong); white-space: nowrap; position: sticky; top: 0; } .table thead th.sortable { cursor: pointer; user-select: none; } .table thead th.sortable:hover { color: var(--text); } .table tbody td { padding: 9px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; } .table tbody tr:last-child td { border-bottom: none; } .table tbody tr:hover { background: var(--surface-2); } .table td.mono, .table td .mono { font-family: var(--mono); font-size: 0.8rem; font-variant-numeric: tabular-nums; } .table .num { text-align: right; font-variant-numeric: tabular-nums; } .row-clickable { cursor: pointer; } .row-clickable:hover { background: var(--accent-soft) !important; } /* ---------- misc ---------- */ .toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; } .stat-row { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 16px; } /* Figure-style stat block: a mono tabular number over a rule and a caption. */ .stat { flex: 1; min-width: 130px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: var(--space-4); } .stat-value { font-family: var(--mono); font-size: 1.55rem; font-weight: 500; letter-spacing: -0.01em; line-height: 1.1; color: var(--text); font-variant-numeric: tabular-nums; } .stat-label { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--border); } .muted { color: var(--text-muted); } .empty-state { text-align: center; color: var(--text-muted); padding: 40px 20px; border: 1px dashed var(--border-strong); border-radius: var(--radius); background: var(--bg); } /* checkbox / radio lists */ .option-list { display: flex; flex-direction: column; gap: 8px; } .option-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 8px; } .option { display: flex; align-items: flex-start; gap: 9px; padding: 10px 12px; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); cursor: pointer; transition: border-color 0.12s, background 0.12s; } .option:hover { border-color: var(--accent); } .option.selected { border-color: var(--accent); background: var(--accent-soft); } .option input { width: auto; margin-top: 3px; } .option-body { flex: 1; } .option-title { font-weight: 600; font-size: 0.88rem; } .option-desc { font-size: 0.76rem; color: var(--text-muted); } /* Compact single-line option (enzyme multi-select): center the checkbox with the label. */ .option-compact { align-items: center; padding: 8px 10px; } .option-compact input { margin-top: 0; } /* tabs */ .tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 20px; } .tab { padding: 10px 16px; font-weight: 600; font-size: 0.92rem; color: var(--text-muted); border: none; background: none; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; } .tab:hover { color: var(--text); } .tab.active { color: var(--accent-strong); border-bottom-color: var(--accent); } /* dropzone */ .dropzone { border: 2px dashed var(--border-strong); border-radius: var(--radius); background: var(--bg); padding: 22px; text-align: center; cursor: pointer; transition: border-color 0.12s, background 0.12s; } .dropzone:hover { border-color: var(--accent); } .dropzone.dragging { border-color: var(--accent); background: var(--accent-soft); } .dropzone-icon { font-size: 1.5rem; } .dropzone-main { font-weight: 600; font-size: 0.9rem; margin-top: 4px; } .dropzone-sub { font-size: 0.78rem; color: var(--text-muted); } /* detail panel */ .detail-panel { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 16px 18px; margin-top: -1px; } .detail-grid { display: grid; grid-template-columns: 150px 1fr; gap: 8px 16px; font-size: 0.85rem; } .detail-grid dt { color: var(--text-muted); font-weight: 600; } .detail-grid dd { margin: 0; } .chip-list { display: flex; flex-wrap: wrap; gap: 5px; } /* home hero (instrument) + tool index */ .hero { padding: var(--space-7) 0 var(--space-7); margin-bottom: var(--space-6); border-bottom: 1px solid var(--border); } .hero-eyebrow { font-family: var(--mono); font-size: var(--text-xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent-strong); margin-bottom: var(--space-3); } .hero h1 { font-size: var(--text-display); line-height: 1.04; margin-bottom: var(--space-4); } .hero h1 .nowrap { white-space: nowrap; } /* On very narrow screens let the long first line wrap instead of overflowing. */ @media (max-width: 520px) { .hero h1 .nowrap { white-space: normal; } } .hero p.lead { color: var(--text-muted); max-width: 62ch; font-size: var(--text-md); margin: 0; } /* mass-spectrum hero visual */ .spectrum { width: 100%; height: 128px; margin: var(--space-6) 0 var(--space-5); display: block; } /* instrument metric readout */ .readout { display: flex; flex-wrap: wrap; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface); } .readout-cell { flex: 1; min-width: 130px; padding: var(--space-4) var(--space-4); border-right: 1px solid var(--border); } .readout-cell:last-child { border-right: 0; } .readout-k { font-family: var(--mono); font-size: var(--text-xs); letter-spacing: 0.05em; text-transform: uppercase; color: var(--text-muted); white-space: nowrap; } .readout-v { font-family: var(--mono); font-weight: 600; font-size: 1.4rem; color: var(--text); margin-top: var(--space-1); font-variant-numeric: tabular-nums; } .hero-btns { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-5); } .hero-btns .btn { font-size: var(--text-base); padding: 11px 20px; } @media (max-width: 640px) { .readout-cell { border-right: 0; border-bottom: 1px solid var(--border); } .hero h1 { max-width: none; } } /* Editorial index, not an identical icon-card grid. */ .tool-grid { display: flex; flex-direction: column; border-top: 1px solid var(--border); } .tool-card { display: grid; grid-template-columns: 1fr auto; align-items: baseline; column-gap: var(--space-5); row-gap: var(--space-2); padding: var(--space-5) var(--space-4); border-bottom: 1px solid var(--border); color: var(--text); transition: background 0.15s ease; } .tool-card:hover { background: var(--surface-2); text-decoration: none; } .tool-card .tool-go { transition: transform 0.15s ease; } .tool-card:hover .tool-go { transform: translateX(3px); } .tool-card p { grid-column: 1 / -1; } .tool-card h3 { margin: 0; font-size: var(--text-lg); } .tool-card p { color: var(--text-muted); font-size: var(--text-sm); margin: 0; max-width: 56ch; } .tool-card .tool-go { color: var(--accent-strong); font-weight: 600; font-size: var(--text-sm); } /* preview / info banners */ .preview-banner { background: var(--warn-soft); border: 1px solid var(--warn); color: var(--warn); border-radius: var(--radius-sm); padding: 11px 14px; font-size: var(--text-sm); margin-bottom: 20px; } .info-banner { background: var(--blue-soft); border: 1px solid var(--blue); color: var(--blue); border-radius: var(--radius-sm); padding: 11px 14px; font-size: var(--text-sm); } /* segmented toggle (Data tab audience) */ .segmented { display: inline-flex; background: var(--surface-2); border: 1px solid var(--border-strong); border-radius: var(--radius); padding: 3px; gap: 3px; } .segmented button { border: none; background: none; font-family: var(--font); font-size: var(--text-sm); font-weight: 600; color: var(--text-muted); padding: 7px 16px; border-radius: var(--radius-sm); cursor: pointer; transition: background 0.15s ease, color 0.15s ease; } .segmented button.active { background: var(--accent-strong); color: var(--surface); } /* priority tags for data gaps */ .prio-high { background: var(--bad-soft); color: var(--bad); border-color: transparent; } .prio-medium { background: var(--warn-soft); color: var(--warn); border-color: transparent; } .prio-low { background: var(--surface-2); color: var(--text-muted); } tr.zero-used td { background: var(--warn-soft); } /* download card */ .dl-card { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); margin-bottom: var(--space-3); } .dl-card .dl-meta { font-size: var(--text-sm); color: var(--text-muted); } /* schema tier grid */ .tier-badge-min { background: var(--good-soft); color: var(--good); border-color: transparent; } .tier-badge-ideal { background: var(--blue-soft); color: var(--blue); border-color: transparent; } /* ============================================================ Consistency utilities (Impeccable deep pass) ============================================================ */ /* One shared disclosure caret (single glyph, rotates on open). */ .caret { display: inline-block; color: var(--text-faint); font-size: 0.7em; line-height: 1; transition: transform 0.15s ease; } .caret.open { transform: rotate(90deg); } /* Data numerals in tables use the mono family (matches the stat tiles). */ .table tbody td.num { font-family: var(--mono); } /* Keyboard focus is non-optional on every custom control. */ .tab:focus-visible, .segmented button:focus-visible, .filter-chip:focus-visible, .species-head:focus-visible, .cond-rank-row:focus-visible, .tool-card:focus-visible, .dropzone:focus-visible, tr.row-clickable:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); } .option:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); } /* Captions / footnotes / page notes. */ .footnote, .caption { font-size: var(--text-xs); color: var(--text-faint); } .page-note { text-align: center; font-size: var(--text-sm); color: var(--text-muted); margin-top: var(--space-6); } /* Error affordance (parallels .info-banner / .preview-banner). */ .error-banner { background: var(--bad-soft); border: 1px solid var(--bad); color: var(--bad); border-radius: var(--radius-sm); padding: 11px 14px; font-size: var(--text-sm); } /* Small segmented variant (in-card sort toggles). */ .segmented-sm { padding: 2px; } .segmented-sm button { padding: 5px 12px; font-size: var(--text-xs); } /* Disabled form controls (e.g. locked feature set for Pfly). */ input:disabled, select:disabled, textarea:disabled { opacity: 0.6; cursor: not-allowed; background: var(--surface-2); } /* ---------- code block (API docs) ---------- */ /* Monospace snippet on the second neutral surface; a labeled bar carries a copy button. Wide lines scroll inside the block so the page body never scrolls horizontally. */ .codeblock { margin: 0 0 var(--space-3); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2); overflow: hidden; } .codeblock-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: 6px 10px 6px 12px; border-bottom: 1px solid var(--border); } .codeblock-label { font-family: var(--font); font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-faint); } .codeblock-copy { font-family: var(--font); font-size: var(--text-xs); font-weight: 600; color: var(--accent-strong); background: none; border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 3px 10px; cursor: pointer; transition: background 160ms ease-out, border-color 160ms ease-out; } .codeblock-copy:hover { background: var(--accent-tint); border-color: var(--border-strong); } .codeblock-copy:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; } .codeblock-pre { margin: 0; padding: var(--space-4); overflow-x: auto; font-family: var(--mono); font-size: var(--text-sm); line-height: 1.6; color: var(--text); tab-size: 2; white-space: pre; } /* ---------- API endpoint blocks ---------- */ .api-endpoint-head { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); } .api-method { font-family: var(--mono); font-size: var(--text-xs); font-weight: 500; letter-spacing: 0.04em; padding: 2px 8px; border-radius: var(--radius-sm); } .api-method-get { color: var(--blue); background: var(--blue-soft); } .api-method-post { color: var(--accent-strong); background: var(--accent-soft); } .api-path { font-family: var(--mono); font-size: var(--text-md); font-weight: 500; color: var(--text); } .api-endpoint-summary { color: var(--text-muted); font-size: var(--text-sm); line-height: 1.55; max-width: 72ch; margin: 0 0 var(--space-3); } .api-endpoint-note { color: var(--text-muted); font-size: var(--text-sm); line-height: 1.55; max-width: 72ch; margin: 0 0 var(--space-3); padding: 10px 12px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); } .api-inline, .api-endpoint-summary code, .api-table code { font-family: var(--mono); font-size: 0.9em; color: var(--text); } /* ---------- API rate-limit table ---------- */ .api-table-wrap { overflow-x: auto; } .api-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); } .api-table th { text-align: left; font-weight: 600; color: var(--text-muted); background: var(--surface-2); padding: 8px 12px; border-bottom: 1px solid var(--border); } .api-table td { padding: 8px 12px; border-bottom: 1px solid var(--border); color: var(--text); } .api-table tr:last-child td { border-bottom: 0; } .api-num { font-family: var(--mono); color: var(--text-muted); white-space: nowrap; }