/* ======================================== TAILWIND + DAISYUI ======================================== */ @import "tailwindcss"; /* Content sources for class detection */ @source "../../templates/**/*.html"; @source "../../public/js/**/*.js"; @plugin "@tailwindcss/typography"; @plugin "daisyui" { themes: light --default, dark --prefersdark; } /* ======================================== WEB FONTS — Onest (display), Figtree (body), Commit Mono (mono) All self-hosted under /fonts/. Variable bodies for display/body, static weights for mono. ======================================== */ /* Onest — variable (400..800), display face */ @font-face { font-family: "Onest"; font-style: normal; font-weight: 400 800; font-display: swap; src: url("/fonts/onest-latin.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "Onest"; font-style: normal; font-weight: 400 800; font-display: swap; src: url("/fonts/onest-latin-ext.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* Figtree — variable (300..900), body face */ @font-face { font-family: "Figtree"; font-style: normal; font-weight: 300 900; font-display: swap; src: url("/fonts/figtree-latin.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "Figtree"; font-style: normal; font-weight: 300 900; font-display: swap; src: url("/fonts/figtree-latin-ext.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* Commit Mono — static 400/400-italic/700, mono face */ @font-face { font-family: "Commit Mono"; font-style: normal; font-weight: 400; font-display: swap; src: url("/fonts/commit-mono-400.woff2") format("woff2"); } @font-face { font-family: "Commit Mono"; font-style: italic; font-weight: 400; font-display: swap; src: url("/fonts/commit-mono-400-italic.woff2") format("woff2"); } @font-face { font-family: "Commit Mono"; font-style: normal; font-weight: 700; font-display: swap; src: url("/fonts/commit-mono-700.woff2") format("woff2"); } /* ======================================== TYPE SYSTEM — semantic tokens Override Tailwind 4's default font stacks so `font-sans` / `font-mono` utilities (and DaisyUI components) pick up our vendored fonts. ======================================== */ @theme inline { --font-sans: "Figtree", ui-sans-serif, system-ui, sans-serif; --font-mono: "Commit Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; --font-display: "Onest", ui-sans-serif, system-ui, sans-serif; } /* ============================================ DARK - "Deep Ocean" ============================================ */ @plugin "daisyui/theme" { name: "dark"; default: false; prefersdark: true; color-scheme: "dark"; --color-base-100: oklch(20% 0.05 250); --color-base-200: oklch(25% 0.05 250); --color-base-300: oklch(30% 0.05 250); --color-base-content: oklch(95.4% 0.022 211); --color-primary: oklch(60% 0.126 221.723); --color-primary-content: oklch(10% 0.126 221.723); --color-secondary: oklch(76.43% 0.135 57.94); --color-secondary-content: oklch(26% 0.079 36.259); --color-accent: oklch(77.32% 0.1 187.98); --color-accent-content: oklch(27% 0.046 192.524); --color-neutral: oklch(32.3% 0.032 259.7); --color-neutral-content: oklch(93.3% 0.026 208.7); --color-info: oklch(74% 0.16 232.661); --color-info-content: oklch(29% 0.066 243.157); --color-success: oklch(76% 0.177 163.223); --color-success-content: oklch(37% 0.077 168.94); --color-warning: oklch(82% 0.189 84.429); --color-warning-content: oklch(41% 0.112 45.904); --color-error: oklch(71% 0.194 13.428); --color-error-content: oklch(27% 0.105 12.094); --radius-selector: 0.5rem; --radius-field: 0.25rem; --radius-box: 0.5rem; --size-selector: 0.25rem; --size-field: 0.25rem; --border: 1px; --depth: 1; --noise: 0; } /* ============================================ LIGHT - "Surface / Shallow Water" ============================================ */ @plugin "daisyui/theme" { name: "light"; default: true; prefersdark: false; color-scheme: "light"; --color-base-100: oklch(98% 0.01 225); --color-base-200: oklch(95% 0.02 225); --color-base-300: oklch(92% 0.03 225); --color-base-content: oklch(21.1% 0.037 254.4); --color-primary: oklch(60% 0.126 221.723); --color-primary-content: oklch(10% 0.126 221.723); --color-secondary: oklch(76.43% 0.135 57.94); --color-secondary-content: oklch(26% 0.079 36.259); --color-accent: oklch(77.32% 0.1 187.98); --color-accent-content: oklch(27% 0.046 192.524); --color-neutral: oklch(32.3% 0.032 259.7); --color-neutral-content: oklch(93.3% 0.026 208.7); --color-info: oklch(74% 0.16 232.661); --color-info-content: oklch(29% 0.066 243.157); --color-success: oklch(76% 0.177 163.223); --color-success-content: oklch(37% 0.077 168.94); --color-warning: oklch(82% 0.189 84.429); --color-warning-content: oklch(41% 0.112 45.904); --color-error: oklch(71% 0.194 13.428); --color-error-content: oklch(27% 0.105 12.094); --radius-selector: 0.5rem; --radius-field: 0.25rem; --radius-box: 0.5rem; --size-selector: 0.25rem; --size-field: 0.25rem; --border: 1px; --depth: 1; --noise: 0; } /* ======================================== ADDITIONAL CSS VARIABLES ======================================== */ :root { /* Dedicated star/favorite color — semantically distinct from `warning` even if values currently coincide. Used by .text-star/.fill-star/etc. */ --color-star: oklch(82% 0.189 84.429); /* Helm brand color (official Helm blue #0F1689). Two variants so the light-mode value stays legible on a near-white surface and the dark-mode value stays legible on Deep Ocean. */ --color-helm-light: oklch(31% 0.181 267.5); --color-helm-dark: oklch(64.6% 0.19 273.2); /* Vulnerability severity scale. Held constant across themes on purpose: CVE severity is a product-semantic signal that needs to read the same way regardless of surface. Content-pair colors come from the same hue family (lighter for dark surfaces, darker for light surfaces) to avoid gray-on-color contrast problems. */ --color-severity-critical: oklch(45% 0.19 25); --color-severity-critical-content: oklch(97% 0.01 25); --color-severity-high: oklch(56% 0.19 50); --color-severity-high-content: oklch(97% 0.01 50); --color-severity-medium: oklch(72% 0.15 70); --color-severity-medium-content: oklch(25% 0.05 70); --color-severity-low: oklch(80% 0.1 85); --color-severity-low-content: oklch(25% 0.05 85); } /* ======================================== STAR / FAVORITE UTILITIES Tailwind 4 @utility so the `!` important modifier and variants (hover:, group-hover:) still work on these classes. ======================================== */ @utility text-star { color: var(--color-star); } @utility stroke-star { stroke: var(--color-star); } @utility fill-star { fill: var(--color-star); } @utility border-star { border-color: var(--color-star); } /* ======================================== TYPE UTILITIES — display font + tabular numerals `font-display` applies Onest; use it on brand lockups and hero headings. `tabular-nums` aligns numeric columns in dense tables. ======================================== */ @utility font-display { font-family: var(--font-display); letter-spacing: 0.005em; } @utility tabular-nums { font-variant-numeric: tabular-nums; } /* Card elevation. In dark mode, shadows disappear against a dark surface — depth is communicated primarily by the base-100 → base-200 surface ramp plus a white-alpha edge ring (see `.card-interactive` rule below). On hover we add a neutral-black amplified shadow (~4–5× the light-mode alpha). Tinted or glow shadows read as highlights, not elevation. */ [data-theme="dark"] { --shadow-card-hover: 0 2px 4px -1px oklch(0% 0 0 / 0.55), 0 12px 24px -6px oklch(0% 0 0 / 0.45); } [data-theme="light"] { --shadow-card-hover: 0 1px 2px oklch(0% 0 0 / 0.06), 0 8px 24px -6px oklch(0% 0 0 / 0.12); } /* ======================================== NAVBAR GHOST BUTTON HOVER Override DaisyUI's neutral hover for nav icons ======================================== */ .navbar .btn-ghost:hover { --btn-bg: oklch(from var(--color-secondary) l c h / 0.15); --btn-border: transparent; } /* ======================================== STICKY FOOTER LAYOUT + BASE TYPE ======================================== */ @layer base { body { @apply min-h-screen flex flex-col; font-family: var(--font-sans); -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; } main { @apply flex-1; } /* Cap long prose at a comfortable reading width. Pages that need to break out of this (dashboards, tables) override with max-w-* utilities. */ .prose { max-width: 68ch; } /* Every table gets tabular-nums by default. Registry UIs are tables of numbers (pull counts, sizes, CVE counts, timestamps) — digits should align vertically so the eye can compare rows. */ table { font-variant-numeric: tabular-nums; } } /* ======================================== TYPOGRAPHY (PROSE) THEME INTEGRATION ======================================== */ @layer base { /* Make prose inherit DaisyUI theme colors */ .prose { --tw-prose-body: var(--color-base-content); --tw-prose-headings: var(--color-base-content); --tw-prose-lead: var(--color-base-content); --tw-prose-links: var(--color-primary); --tw-prose-bold: var(--color-base-content); --tw-prose-counters: var(--color-base-content); --tw-prose-bullets: var(--color-base-content); --tw-prose-hr: var(--color-base-300); --tw-prose-quotes: var(--color-base-content); --tw-prose-quote-borders: var(--color-base-300); --tw-prose-captions: var(--color-base-content); --tw-prose-code: var(--color-base-content); --tw-prose-pre-code: var(--color-base-content); --tw-prose-pre-bg: var(--color-base-200); --tw-prose-th-borders: var(--color-base-300); --tw-prose-td-borders: var(--color-base-300); } } /* ======================================== SVG SPRITE ICONS ======================================== */ .icon { display: inline-block; width: 1em; height: 1em; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; fill: none; vertical-align: -0.125em; } /* Icon sizes (matching Tailwind size-* utilities) */ .icon.size-3 { width: 0.75rem; height: 0.75rem; } .icon.size-4 { width: 1rem; height: 1rem; } .icon.size-5 { width: 1.25rem; height: 1.25rem; } .icon.size-6 { width: 1.5rem; height: 1.5rem; } .icon.size-8 { width: 2rem; height: 2rem; } .icon.size-10 { width: 2.5rem; height: 2.5rem; } .icon.size-12 { width: 3rem; height: 3rem; } .icon.size-16 { width: 4rem; height: 4rem; } .icon.size-20 { width: 5rem; height: 5rem; } /* Special size for slightly larger than 1rem (used in star/pull count) */ .icon.size-\[1\.1rem\] { width: 1.1rem; height: 1.1rem; } /* Animate spin for loader icons */ .icon.animate-spin { animation: spin 1s linear infinite; } /* ======================================== ACCESSIBILITY UTILITIES ======================================== */ @layer utilities { /* Screen reader only - visually hidden but accessible */ .sr-only { @apply absolute w-px h-px p-0 -m-px overflow-hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; } /* Skip-to-content link. Hidden until keyboard-focused, then anchors at the top-left so the user can press Enter to jump past the nav. */ .skip-link { @apply absolute left-2 z-50 px-3 py-2 rounded-md; @apply bg-primary text-primary-content font-medium text-sm; top: -10rem; transition: top 0.15s ease-out; } .skip-link:focus, .skip-link:focus-visible { top: 0.5rem; } } /* ======================================== KEYBOARD FOCUS RING Applied only on :focus-visible so mouse users don't see it. Uses the primary hue so it reads as part of the Deep Ocean palette. ======================================== */ :where(a, button, [role="button"], [role="tab"], input, select, textarea, summary, [tabindex]):focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; } /* ======================================== TOUCH TARGET SIZING Small buttons and compact form controls meet the keyboard minimum on desktop but fall below the 44×44 recommended touch target on touch devices (WCAG 2.5.5). Grow them on any device that can't reliably produce hover — covers pure touch as well as hybrid touchscreen laptops where `pointer: coarse` alone misses. ======================================== */ @media (pointer: coarse), (hover: none) { /* Icon-only buttons grow both axes — daisyUI's circle/square variants are the marker for these. */ :is(.btn-circle, .btn-square):is(.btn-xs, .btn-sm) { min-width: 2.75rem; min-height: 2.75rem; } /* Text buttons only need vertical clearance — padding handles width. */ .btn-xs, .btn-sm { min-height: 2.75rem; } /* Small checkbox/radio: expand the clickable region without distorting the control itself — negative margin on the parent