diff --git a/astro.config.mjs b/astro.config.mjs
index f34bcb3d..2a37b8bf 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -1,4 +1,4 @@
-import {defineConfig} from 'astro/config';
+import {defineConfig, fontProviders} from 'astro/config';
import {rehypeHeadingIds} from '@astrojs/markdown-remark';
import react from '@astrojs/react';
import tailwind from "@astrojs/tailwind";
@@ -10,6 +10,37 @@ import { rehypeRelativeAssets } from './src/plugins/rehype-relative-assets.mjs';
// https://astro.build/config
export default defineConfig({
site: 'https://elixir.no',
+ // Self-vendored, preloaded web fonts (files live in src/assets/fonts, so the
+ // build has no network dependency and visitors never hit Google; CLS-safe).
+ // Body drives UI + MDX prose; display drives headings only. Both are variable
+ // fonts, so one file per family covers its weight range.
+ // Fonts API is experimental in Astro 5.x (Astro is pinned to ~5.18 for it).
+ experimental: {
+ fonts: [
+ {
+ provider: fontProviders.local(),
+ name: 'Hanken Grotesk',
+ cssVariable: '--font-body',
+ fallbacks: ['ui-sans-serif', 'system-ui', 'sans-serif'],
+ options: {
+ variants: [
+ { weight: '400 700', style: 'normal', src: ['./src/assets/fonts/hanken-grotesk.woff2'] },
+ ],
+ },
+ },
+ {
+ provider: fontProviders.local(),
+ name: 'Bricolage Grotesque',
+ cssVariable: '--font-display',
+ fallbacks: ['ui-sans-serif', 'system-ui', 'sans-serif'],
+ options: {
+ variants: [
+ { weight: '500 800', style: 'normal', src: ['./src/assets/fonts/bricolage-grotesque.woff2'] },
+ ],
+ },
+ },
+ ],
+ },
redirects: {
// ── Legacy underscore/mixed-case slugs → year/slug ──────────────────────
'/events/2025-06-10_arendalsuka': { destination: '/events/2025/arendalsuka', status: 301 },
diff --git a/package.json b/package.json
index 1df259a6..15754da1 100644
--- a/package.json
+++ b/package.json
@@ -26,8 +26,9 @@
"@astrojs/sitemap": "^3.7.2",
"@astrojs/tailwind": "^6.0.2",
"@headlessui/react": "^2.2.10",
+ "@heroicons/react": "^2.2.0",
"@tailwindcss/forms": "^0.5.7",
- "astro": "^5.18.1",
+ "astro": "~5.18.1",
"dayjs": "^1.11.20",
"dompurify": "^3.3.3",
"framer-motion": "^12.38.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c54ce680..dcdbb1a4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -48,11 +48,14 @@ importers:
'@headlessui/react':
specifier: ^2.2.10
version: 2.2.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ '@heroicons/react':
+ specifier: ^2.2.0
+ version: 2.2.0(react@18.3.1)
'@tailwindcss/forms':
specifier: ^0.5.7
version: 0.5.9(tailwindcss@3.4.14)
astro:
- specifier: ^5.18.1
+ specifier: ~5.18.1
version: 5.18.1(@types/node@24.12.2)(jiti@1.21.6)(rollup@4.60.1)(sass@1.99.0)(typescript@5.6.3)(yaml@2.8.3)
dayjs:
specifier: ^1.11.20
@@ -642,6 +645,11 @@ packages:
react: ^18 || ^19 || ^19.0.0-rc
react-dom: ^18 || ^19 || ^19.0.0-rc
+ '@heroicons/react@2.2.0':
+ resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==}
+ peerDependencies:
+ react: '>= 16 || ^19.0.0-rc'
+
'@img/colour@1.1.0':
resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==}
engines: {node: '>=18'}
@@ -1817,6 +1825,7 @@ packages:
glob@10.4.5:
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+ deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
hasBin: true
h3@1.15.9:
@@ -2867,6 +2876,7 @@ packages:
tsconfck@3.1.6:
resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==}
engines: {node: ^18 || >=20}
+ deprecated: unmaintained
hasBin: true
peerDependencies:
typescript: ^5.0.0
@@ -3812,6 +3822,10 @@ snapshots:
react-dom: 18.3.1(react@18.3.1)
use-sync-external-store: 1.6.0(react@18.3.1)
+ '@heroicons/react@2.2.0(react@18.3.1)':
+ dependencies:
+ react: 18.3.1
+
'@img/colour@1.1.0':
optional: true
@@ -4578,7 +4592,7 @@ snapshots:
smol-toml: 1.6.1
svgo: 4.0.1
tinyexec: 1.0.4
- tinyglobby: 0.2.15
+ tinyglobby: 0.2.16
tsconfck: 3.1.6(typescript@5.6.3)
ultrahtml: 1.6.0
unifont: 0.7.4
diff --git a/src/assets/fonts/bricolage-grotesque.woff2 b/src/assets/fonts/bricolage-grotesque.woff2
new file mode 100644
index 00000000..86d4f45d
Binary files /dev/null and b/src/assets/fonts/bricolage-grotesque.woff2 differ
diff --git a/src/assets/fonts/hanken-grotesk.woff2 b/src/assets/fonts/hanken-grotesk.woff2
new file mode 100644
index 00000000..e71775f9
Binary files /dev/null and b/src/assets/fonts/hanken-grotesk.woff2 differ
diff --git a/src/components/callout.tsx b/src/components/callout.tsx
index 5c8c0939..9bae0199 100644
--- a/src/components/callout.tsx
+++ b/src/components/callout.tsx
@@ -1,4 +1,10 @@
import React from 'react';
+import {
+ CheckCircleIcon,
+ ExclamationTriangleIcon,
+ InformationCircleIcon,
+ XCircleIcon,
+} from '@heroicons/react/24/outline';
const variants = {
info: {
@@ -7,9 +13,7 @@ const variants = {
title: 'text-blue-900 dark:text-blue-200',
text: 'text-blue-800 dark:text-blue-300',
icon: (
-
+
),
},
success: {
@@ -18,9 +22,7 @@ const variants = {
title: 'text-green-900 dark:text-green-200',
text: 'text-green-800 dark:text-green-300',
icon: (
-
+
),
},
warn: {
@@ -29,9 +31,7 @@ const variants = {
title: 'text-yellow-900 dark:text-yellow-200',
text: 'text-yellow-800 dark:text-yellow-300',
icon: (
-
+
),
},
danger: {
@@ -40,9 +40,7 @@ const variants = {
title: 'text-red-900 dark:text-red-200',
text: 'text-red-800 dark:text-red-300',
icon: (
-
+
),
},
};
diff --git a/src/components/carousel.tsx b/src/components/carousel.tsx
index 06ed6501..991ddab5 100644
--- a/src/components/carousel.tsx
+++ b/src/components/carousel.tsx
@@ -1,6 +1,6 @@
import React, { useEffect, useRef, useState } from 'react';
import { Transition } from '@headlessui/react';
-import { IoIosArrowBack, IoIosArrowForward } from "react-icons/io";
+import { ChevronLeftIcon, ChevronRightIcon, XMarkIcon } from '@heroicons/react/24/outline';
const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -94,14 +94,14 @@ const Carousel = ({ images, autoSlideInterval = 3000 }) => {
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-white dark:bg-black bg-opacity-50 group-hover:bg-opacity-75 rounded-full p-2"
aria-label="Previous slide"
>
-
+
@@ -145,11 +145,7 @@ const Carousel = ({ images, autoSlideInterval = 3000 }) => {
className="absolute top-4 right-4 text-white hover:text-gray-300 focus:outline-none"
aria-label="Close fullscreen view"
>
-
+
diff --git a/src/components/command-palette.tsx b/src/components/command-palette.tsx
index 713a6e79..5b2e2366 100644
--- a/src/components/command-palette.tsx
+++ b/src/components/command-palette.tsx
@@ -1,6 +1,7 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
import { AnimatePresence, motion, useReducedMotion } from 'framer-motion';
import DomPurify from 'dompurify';
+import { MagnifyingGlassIcon, ExclamationCircleIcon, NewspaperIcon, CalendarIcon, CubeIcon, FolderIcon, AcademicCapIcon, UserGroupIcon, DocumentTextIcon } from '@heroicons/react/24/outline';
const ignoredPaths = /^\/news\/?$/;
const DEBOUNCE_MS = 200;
@@ -25,14 +26,14 @@ function resultIcon(url: string) {
return 'page';
}
-const iconPaths: Record = {
- news: 'M12 7.5h1.5m-1.5 3h1.5m-7.5 3h7.5m-7.5 3h7.5m3-9h3.375c.621 0 1.125.504 1.125 1.125V18a2.25 2.25 0 0 1-2.25 2.25M16.5 7.5V18a2.25 2.25 0 0 0 2.25 2.25M16.5 7.5V4.875c0-.621-.504-1.125-1.125-1.125H4.125C3.504 3.75 3 4.254 3 4.875V18a2.25 2.25 0 0 0 2.25 2.25h13.5M6 7.5h3v3H6v-3Z',
- event: 'M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5',
- service: 'M21 7.5l-2.25-1.313M21 7.5v2.25m0-2.25l-2.25 1.313M3 7.5l2.25-1.313M3 7.5l2.25 1.313M3 7.5v2.25m9 3l2.25-1.313M12 12.75l-2.25-1.313M12 12.75V15m0 6.75l2.25-1.313M12 21.75V15m0 0l-2.25 1.313',
- project: 'M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z',
- training: 'M4.26 10.147a60.438 60.438 0 0 0-.491 6.347A48.62 48.62 0 0 1 12 20.904a48.62 48.62 0 0 1 8.232-4.41 60.46 60.46 0 0 0-.491-6.347m-15.482 0a50.636 50.636 0 0 0-2.658-.813A59.906 59.906 0 0 1 12 3.493a59.903 59.903 0 0 1 10.399 5.84c-.896.248-1.783.52-2.658.814m-15.482 0A50.717 50.717 0 0 1 12 13.489a50.702 50.702 0 0 1 7.74-3.342M6.75 15a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm0 0v-3.675A55.378 55.378 0 0 1 12 8.443m-7.007 11.55A5.981 5.981 0 0 0 6.75 15.75v-1.5',
- about: 'M18 18.72a9.094 9.094 0 0 0 3.741-.479 3 3 0 0 0-4.682-2.72m.94 3.198.001.031c0 .225-.012.447-.037.666A11.944 11.944 0 0 1 12 21c-2.17 0-4.207-.576-5.963-1.584A6.062 6.062 0 0 1 6 18.719m12 0a5.971 5.971 0 0 0-.941-3.197m0 0A5.995 5.995 0 0 0 12 12.75a5.995 5.995 0 0 0-5.058 2.772m0 0a3 3 0 0 0-4.681 2.72 8.986 8.986 0 0 0 3.74.477m.94-3.197a5.971 5.971 0 0 0-.94 3.197M15 6.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Zm6 3a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0Zm-13.5 0a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0Z',
- page: 'M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z',
+const iconMap: Record = {
+ news: NewspaperIcon,
+ event: CalendarIcon,
+ service: CubeIcon,
+ project: FolderIcon,
+ training: AcademicCapIcon,
+ about: UserGroupIcon,
+ page: DocumentTextIcon,
};
export default function CommandPalette({ open, setOpen }: { open: boolean; setOpen: (v: boolean) => void }) {
@@ -108,6 +109,17 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
if (e.key === 'Enter' && results[activeIndex]) { navigate(results[activeIndex].url); }
}, [close, navigate, results, activeIndex]);
+ // Close on Escape regardless of focus — clicking the results area moves
+ // focus off the input, so the input's own onKeyDown can't catch Escape.
+ useEffect(() => {
+ if (!open) return;
+ const onEsc = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') { e.preventDefault(); close(); }
+ };
+ document.addEventListener('keydown', onEsc);
+ return () => document.removeEventListener('keydown', onEsc);
+ }, [open, close]);
+
useEffect(() => {
const el = listRef.current?.children[activeIndex] as HTMLElement | undefined;
el?.scrollIntoView({ block: 'nearest' });
@@ -149,9 +161,7 @@ export default function CommandPalette({ open, setOpen }: { open: boolean; setOp
>
{/* Search input */}
-
+
{results.map((item, i) => {
const type = resultIcon(item.url);
- const path = iconPaths[type];
+ const ResultIcon = iconMap[type];
const sanitized = sanitize(item.excerpt);
return (
-
+
-
+
No results found
Try a different search term
diff --git a/src/components/featured-news.astro b/src/components/featured-news.astro
index 846d3983..a39ec679 100644
--- a/src/components/featured-news.astro
+++ b/src/components/featured-news.astro
@@ -1,6 +1,6 @@
---
import { getCollection } from "astro:content";
-import { HiArrowSmRight } from "react-icons/hi";
+import { ArrowRightIcon } from "@heroicons/react/24/outline";
const news = (await getCollection("news"))
.sort((a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime())
.splice(0, 3);
@@ -21,7 +21,7 @@ const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
More news
-
+
diff --git a/src/components/hero.tsx b/src/components/hero.tsx
index d66430df..00da8b3b 100644
--- a/src/components/hero.tsx
+++ b/src/components/hero.tsx
@@ -1,7 +1,9 @@
import { motion, useReducedMotion } from 'framer-motion';
import React, { Suspense, lazy, useState, useEffect } from 'react';
+import { ArrowRightIcon, ArrowTopRightOnSquareIcon, ChevronDownIcon, LifebuoyIcon } from '@heroicons/react/24/outline';
const ParticleField = lazy(() => import('./particle-field'));
+const MotionChevronDown = motion.create(ChevronDownIcon);
const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -89,19 +91,12 @@ function ScrollCue({ shouldReduceMotion }: { shouldReduceMotion: boolean | null
transition={{ duration: 0.4, delay: shouldReduceMotion ? 0 : 1 }}
className="absolute bottom-6 sm:bottom-8 left-1/2 -translate-x-1/2 z-10 p-2 text-gray-500 dark:text-gray-400 hover:text-brand-primary dark:hover:text-white transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 rounded-full"
>
-
-
-
+ />
);
}
@@ -137,9 +132,7 @@ export function Hero() {
className="inline-flex items-center px-3 py-1 rounded-full text-xs font-bold bg-accent/10 text-accent hover:bg-accent/20 transition-colors"
>
Part of the European ELIXIR infrastructure
-
+
@@ -169,17 +162,16 @@ export function Hero() {
>
Explore services
-
+
+
Get support
diff --git a/src/components/highlights-carousel.tsx b/src/components/highlights-carousel.tsx
index 812cd3fb..7b27efcc 100644
--- a/src/components/highlights-carousel.tsx
+++ b/src/components/highlights-carousel.tsx
@@ -1,5 +1,7 @@
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { motion, AnimatePresence, useReducedMotion } from 'framer-motion';
+import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
+import { PauseIcon, PlayIcon } from '@heroicons/react/24/solid';
const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -74,18 +76,14 @@ export default function HighlightsCarousel({ slides }: { slides: Slide[] }) {
className="p-2 rounded-lg border border-gray-200/60 dark:border-gray-700/30 text-brand-grey dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-white/5 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
aria-label="Previous slide"
>
-
+
@@ -163,13 +161,9 @@ export default function HighlightsCarousel({ slides }: { slides: Slide[] }) {
aria-label={paused ? 'Resume auto-play' : 'Pause auto-play'}
>
{paused ? (
-
+
) : (
-
+
)}
diff --git a/src/components/listing-filters.tsx b/src/components/listing-filters.tsx
index fb81fcfb..40fb14bc 100644
--- a/src/components/listing-filters.tsx
+++ b/src/components/listing-filters.tsx
@@ -1,4 +1,5 @@
import { useEffect, useState, useCallback } from 'react';
+import { AdjustmentsHorizontalIcon, XMarkIcon } from '@heroicons/react/24/outline';
export type FilterOption = {
id: string;
@@ -140,9 +141,7 @@ export default function ListingFilters({ groups, event = 'filters-changed' }: Pr
onClick={clearAll}
className="inline-flex items-center gap-1.5 text-xs font-medium text-gray-500 dark:text-gray-400 hover:text-brand-primary dark:hover:text-white transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:rounded"
>
-
+
Clear filters ({activeCount})
)}
@@ -157,9 +156,7 @@ export default function ListingFilters({ groups, event = 'filters-changed' }: Pr
className="sm:hidden flex items-center gap-2 rounded-lg border border-gray-200/60 dark:border-gray-700/30 bg-white dark:bg-white/[0.03] px-4 py-2.5 text-sm font-medium text-brand-primary dark:text-white transition-colors hover:border-accent/30 w-full justify-center focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
aria-expanded={mobileOpen}
>
-
+
Filters
{hasFilters && (
diff --git a/src/components/nav-about-menu.tsx b/src/components/nav-about-menu.tsx
index 384cabed..c78cb3e7 100644
--- a/src/components/nav-about-menu.tsx
+++ b/src/components/nav-about-menu.tsx
@@ -1,12 +1,11 @@
import { aboutNodes, aboutOverviewHref } from '../data/nav-menu';
+import { ArrowRightIcon } from '@heroicons/react/24/outline';
const isActive = (pathname: string, href: string) =>
pathname === href || pathname.startsWith(href + '/');
const ArrowIcon = () => (
-
+
);
type Props = {
diff --git a/src/components/nav-dropdown.tsx b/src/components/nav-dropdown.tsx
index a7b042ad..491d69c5 100644
--- a/src/components/nav-dropdown.tsx
+++ b/src/components/nav-dropdown.tsx
@@ -1,10 +1,9 @@
import { useEffect, useRef, useState, type ReactNode } from 'react';
import { AnimatePresence, motion, useReducedMotion } from 'framer-motion';
+import { ChevronDownIcon } from '@heroicons/react/24/outline';
const ChevronIcon = ({ className }: { className?: string }) => (
-
+
);
const linkColor = (active: boolean) =>
@@ -89,7 +88,7 @@ export default function NavDropdown({
>
{label}
diff --git a/src/components/nav-mobile-accordion.tsx b/src/components/nav-mobile-accordion.tsx
index e487c54c..7623e55d 100644
--- a/src/components/nav-mobile-accordion.tsx
+++ b/src/components/nav-mobile-accordion.tsx
@@ -1,10 +1,9 @@
import { useState, type ReactNode } from 'react';
import { AnimatePresence, motion, useReducedMotion } from 'framer-motion';
+import { ChevronDownIcon } from '@heroicons/react/24/outline';
const ChevronIcon = ({ className }: { className?: string }) => (
-
+
);
type Props = {
diff --git a/src/components/navigation.tsx b/src/components/navigation.tsx
index 430ce037..6e80e3a7 100644
--- a/src/components/navigation.tsx
+++ b/src/components/navigation.tsx
@@ -6,11 +6,10 @@ import NavAboutMenu from "./nav-about-menu.tsx";
import NavDropdown from "./nav-dropdown.tsx";
import NavMobileAccordion from "./nav-mobile-accordion.tsx";
import { useMagicPill } from "../lib/hooks/use-magic-pill";
+import { MagnifyingGlassIcon } from "@heroicons/react/24/outline";
const SearchIcon = ({ className }: { className?: string }) => (
-
+
);
const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -29,7 +28,7 @@ const isActivePath = (pathname: string, href: string) =>
pathname === href || pathname.startsWith(href + '/');
const navLinkClass = (active: boolean) =>
- `relative z-10 px-3 py-2 text-sm 2xl:text-base font-semibold rounded-lg transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${
+ `relative z-10 px-3.5 py-2 text-sm 2xl:text-[0.9375rem] font-medium tracking-[-0.01em] rounded-lg transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${
active ? 'text-accent' : 'text-brand-grey dark:text-gray-300 hover:text-brand-primary dark:hover:text-white'
}`;
@@ -85,8 +84,8 @@ export const Navigation = ({ pathname }: { pathname: string }) => {
diff --git a/src/components/particle-field.tsx b/src/components/particle-field.tsx
index 324e5f56..bf6c330d 100644
--- a/src/components/particle-field.tsx
+++ b/src/components/particle-field.tsx
@@ -9,8 +9,9 @@ interface Particle {
opacity: number;
}
-const CONNECTION_DISTANCE = 140;
-const CONNECTION_OPACITY = 0.1;
+const CONNECTION_DISTANCE = 165;
+const CONNECTION_OPACITY = 0.22;
+const CONNECTION_WIDTH = 0.9;
const SPEED = 0.2;
function particleCount(w: number): number {
@@ -116,20 +117,16 @@ export default function ParticleField({ playing = true }: { playing?: boolean })
ctx!.moveTo(particles[i].x, particles[i].y);
ctx!.lineTo(particles[j].x, particles[j].y);
ctx!.strokeStyle = `rgba(${accentRgb} / ${alpha})`;
- ctx!.lineWidth = 0.5;
+ ctx!.lineWidth = CONNECTION_WIDTH;
ctx!.stroke();
}
}
}
- // Draw particles (triangles)
+ // Draw particles
for (const p of particles) {
- const r = p.radius;
ctx!.beginPath();
- ctx!.moveTo(p.x, p.y - r);
- ctx!.lineTo(p.x - r * 0.866, p.y + r * 0.5);
- ctx!.lineTo(p.x + r * 0.866, p.y + r * 0.5);
- ctx!.closePath();
+ ctx!.arc(p.x, p.y, p.radius * 0.7, 0, Math.PI * 2);
ctx!.fillStyle = `rgba(${accentRgb} / ${p.opacity})`;
ctx!.fill();
}
diff --git a/src/components/people.astro b/src/components/people.astro
index 3d9ff94c..79941225 100644
--- a/src/components/people.astro
+++ b/src/components/people.astro
@@ -1,4 +1,5 @@
---
+import { ArrowRightIcon } from "@heroicons/react/24/outline";
import people from "../data/people.json";
type Org = {
@@ -104,9 +105,7 @@ function getElixirRole(person: any): string {
Meet the team
-
+
) : (
diff --git a/src/components/pricing.tsx b/src/components/pricing.tsx
index 7ad130a7..ecd088b4 100644
--- a/src/components/pricing.tsx
+++ b/src/components/pricing.tsx
@@ -1,3 +1,5 @@
+import { CheckIcon } from '@heroicons/react/24/outline';
+
export default function Pricing({ tiers }) {
return (
@@ -39,9 +41,7 @@ export default function Pricing({ tiers }) {
{tier.features.map((feature) => (
-
-
+
{feature}
))}
diff --git a/src/components/project-filters.tsx b/src/components/project-filters.tsx
index 16f4be34..f6c63572 100644
--- a/src/components/project-filters.tsx
+++ b/src/components/project-filters.tsx
@@ -1,4 +1,5 @@
import React, { useEffect, useState, useCallback } from 'react';
+import { AdjustmentsHorizontalIcon, CheckIcon, XMarkIcon } from '@heroicons/react/24/outline';
export type FilterOption = {
id: string;
@@ -85,9 +86,7 @@ export default function ProjectFilters({ groups = [] }: { groups: FilterGroup[]
: 'border-gray-300 dark:border-gray-600'
}`}>
{isActive && (
-
+
)}
{opt.label}
@@ -106,9 +105,7 @@ export default function ProjectFilters({ groups = [] }: { groups: FilterGroup[]
onClick={clearAll}
className="inline-flex items-center gap-1.5 text-xs font-medium text-gray-500 dark:text-gray-400 hover:text-brand-primary dark:hover:text-white transition-colors"
>
-
+
Clear all filters ({activeCount})
)}
@@ -123,9 +120,7 @@ export default function ProjectFilters({ groups = [] }: { groups: FilterGroup[]
className="lg:hidden flex items-center gap-2 rounded-lg border border-gray-200/60 dark:border-gray-700/30 bg-white dark:bg-white/[0.03] px-4 py-2.5 text-sm font-medium text-brand-primary dark:text-white transition-colors hover:border-accent/30 w-full justify-center"
aria-expanded={mobileOpen}
>
-
+
Filters
{hasAnyFilter && (
diff --git a/src/components/sections/latest-news.astro b/src/components/sections/latest-news.astro
index 0be0b6fd..947eb66c 100644
--- a/src/components/sections/latest-news.astro
+++ b/src/components/sections/latest-news.astro
@@ -1,5 +1,6 @@
---
import { getCollection } from "astro:content";
+import { ArrowRightIcon, ChevronRightIcon } from "@heroicons/react/24/outline";
const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -46,9 +47,7 @@ const featuredCover = featured?.data.cover?.source
class="hidden sm:inline-flex items-center gap-2 px-5 py-2.5 text-sm font-semibold text-accent hover:bg-accent/5 rounded-lg transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
>
View all news
-
+
@@ -88,9 +87,7 @@ const featuredCover = featured?.data.cover?.source
Read article
-
+
@@ -132,9 +129,7 @@ const featuredCover = featured?.data.cover?.source
-
+
);
})}
@@ -148,9 +143,7 @@ const featuredCover = featured?.data.cover?.source
class="inline-flex items-center gap-2 px-5 py-2.5 text-sm font-semibold text-accent hover:bg-accent/5 rounded-lg transition-colors"
>
View all news
-
+
diff --git a/src/components/sections/org-contact.astro b/src/components/sections/org-contact.astro
index 3f181823..a993b038 100644
--- a/src/components/sections/org-contact.astro
+++ b/src/components/sections/org-contact.astro
@@ -1,5 +1,11 @@
---
import type { OrgContact, OrgLink } from '../../data/organizations';
+import {
+ ArrowTopRightOnSquareIcon,
+ EnvelopeIcon,
+ InformationCircleIcon,
+ MapPinIcon,
+} from '@heroicons/react/24/outline';
interface Props {
contacts: OrgContact[];
@@ -42,9 +48,7 @@ const hasContactInfo = contacts.length > 0 || links.length > 0 || callout;
class="group flex items-start gap-4 p-4 rounded-xl bg-white dark:bg-white/[0.04] border border-gray-200/60 dark:border-gray-700/30 shadow-sm ring-1 ring-black/[0.03] dark:ring-white/[0.03] hover:border-accent/30 hover:shadow-md hover:shadow-accent/[0.06] transition-all duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
>
@@ -73,9 +77,7 @@ const hasContactInfo = contacts.length > 0 || links.length > 0 || callout;
rel="noopener noreferrer"
class="group flex items-center gap-3 px-4 py-3 rounded-lg hover:bg-white dark:hover:bg-white/[0.04] transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
>
-
+
{l.text}
@@ -88,9 +90,7 @@ const hasContactInfo = contacts.length > 0 || links.length > 0 || callout;
{callout && (
-
+
{callout}
@@ -118,10 +118,7 @@ const hasContactInfo = contacts.length > 0 || links.length > 0 || callout;
rel="noopener noreferrer"
class="inline-flex items-center gap-1.5 text-sm text-gray-500 dark:text-gray-400 hover:text-brand-primary dark:hover:text-white transition-colors"
>
-
+
{address}
diff --git a/src/components/sections/org-hero.astro b/src/components/sections/org-hero.astro
index 0f2fd684..69d932dd 100644
--- a/src/components/sections/org-hero.astro
+++ b/src/components/sections/org-hero.astro
@@ -1,4 +1,6 @@
---
+import { ArrowLeftIcon } from "@heroicons/react/24/outline";
+
interface Props {
nodeName: string;
university: string;
@@ -35,9 +37,7 @@ const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
href={`${BASE}/about`}
class="org-hero-fade inline-flex items-center gap-1.5 text-sm font-medium text-white/60 hover:text-white transition-colors mb-8 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/50 rounded"
>
-
+
About ELIXIR Norway
diff --git a/src/components/sections/services-overview.tsx b/src/components/sections/services-overview.tsx
index 8b7a8e02..ea41bb66 100644
--- a/src/components/sections/services-overview.tsx
+++ b/src/components/sections/services-overview.tsx
@@ -1,5 +1,12 @@
import React from 'react';
import { motion, useReducedMotion } from 'framer-motion';
+import {
+ ArrowRightIcon,
+ LifebuoyIcon,
+ Squares2X2Icon,
+ ServerStackIcon,
+ ShieldCheckIcon,
+} from '@heroicons/react/24/outline';
const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -15,28 +22,28 @@ const services: Service[] = [
{
title: 'Research Support',
description: 'Short and long-term support with bioinformatics analyses, programming and data management tasks.',
- icon:
,
+ icon:
,
color: '#3b82f6',
href: `${BASE}/research-support`,
},
{
title: 'Services',
description: 'Analysis and management of life science data within marine, health, genomics, proteomics and more.',
- icon:
,
+ icon:
,
color: '#f47d20',
href: `${BASE}/services`,
},
{
title: 'e-Infrastructure',
description: <>
NeLS, the Norwegian e-Infrastructure for Life Sciences, for analysis, sharing, management and storage of life science data.>,
- icon:
,
+ icon:
,
color: '#10b981',
href: `${BASE}/e-infrastructure`,
},
{
title: 'Sensitive Data',
description: <>Archiving solutions for potentially identifiable human data with support on
TSD,
HUNT Cloud and
SAFE.>,
- icon:
,
+ icon:
,
color: '#8b5cf6',
href: `${BASE}/sensitive-data`,
},
@@ -78,9 +85,7 @@ export default function ServicesOverview() {
className="mt-6 inline-flex items-center gap-2 text-sm font-semibold text-accent hover:underline underline-offset-4 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
>
Explore all services
-
+
@@ -114,9 +119,7 @@ export default function ServicesOverview() {
Learn more
-
+
))}
diff --git a/src/components/service-status-summary.tsx b/src/components/service-status-summary.tsx
index ed509758..09655a24 100644
--- a/src/components/service-status-summary.tsx
+++ b/src/components/service-status-summary.tsx
@@ -1,5 +1,6 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import { useReducedMotion } from 'framer-motion';
+import { ArrowRightIcon } from '@heroicons/react/24/outline';
import { probe, type Status } from '../lib/service-probe';
type ServiceInfo = {
@@ -137,12 +138,10 @@ export default function ServiceStatusSummary({ services, href }: { services: Ser
{label}
{countText &&
· {countText}}
-
+ aria-hidden="true"
+ />
);
}
diff --git a/src/components/service-status.tsx b/src/components/service-status.tsx
index d297d00f..600e71cf 100644
--- a/src/components/service-status.tsx
+++ b/src/components/service-status.tsx
@@ -1,4 +1,5 @@
import { useState, useEffect, useCallback, useRef } from 'react';
+import { CheckIcon, ExclamationTriangleIcon, InformationCircleIcon } from '@heroicons/react/24/outline';
import { probe, type Status } from '../lib/service-probe';
type ServiceInfo = {
@@ -116,21 +117,15 @@ function OverallSummary({ states }: { states: Map
}) {
) : allOk ? (
) : problems > 0 ? (
) : (
)}
diff --git a/src/components/share-buttons.tsx b/src/components/share-buttons.tsx
index c66ad5ed..a1a1c5e4 100644
--- a/src/components/share-buttons.tsx
+++ b/src/components/share-buttons.tsx
@@ -1,4 +1,5 @@
import { useEffect, useRef, useState } from 'react';
+import { CheckIcon, EnvelopeIcon, LinkIcon } from '@heroicons/react/24/outline';
interface Props {
url: string;
@@ -73,13 +74,9 @@ export default function ShareButtons({ url, title, summary = '' }: Props) {
className={btn}
>
{copied ? (
-
+
) : (
-
+
)}
-
+
+
@@ -27,9 +31,7 @@ function renderInlineMarkdown(md: string): string {
class="fixed right-3 top-1 p-1 rounded-md !text-white/60 hover:!text-white hover:bg-white/10 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-white/50 z-[61]"
aria-label="Dismiss announcement"
>
-
+
diff --git a/src/layouts/base.astro b/src/layouts/base.astro
index f69c2c1b..66171a3a 100644
--- a/src/layouts/base.astro
+++ b/src/layouts/base.astro
@@ -3,6 +3,7 @@ import Navigation from "../components/navigation";
import Footer from "../components/footer";
import SEOHead from "../components/seo-head.astro";
import SiteBanner from "../components/site-banner.astro";
+import { Font } from "astro:assets";
import "../styles/global.scss";
interface Props {
@@ -31,6 +32,9 @@ const { seo } = Astro.props;
+
+
+
diff --git a/src/layouts/page.astro b/src/layouts/page.astro
index 4aca3ad4..a0549a9d 100644
--- a/src/layouts/page.astro
+++ b/src/layouts/page.astro
@@ -2,6 +2,7 @@
import BaseLayout from "./base.astro";
import Breadcrumbs from "../components/breadcrumbs.astro";
import ShareButtons from "../components/share-buttons.tsx";
+import { ArrowLeftIcon, ArrowTopRightOnSquareIcon, BuildingLibraryIcon, CalendarIcon, ClockIcon } from "@heroicons/react/24/outline";
import { slugToTitleCase } from "../lib/utils";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
@@ -241,9 +242,7 @@ const jsonLd = contentType === 'news' ? JSON.stringify({
href={`${BASE}/${contentType === 'projects' ? 'funding-and-projects' : contentType}`}
class="inline-flex items-center gap-1.5 text-sm font-medium text-gray-500 dark:text-gray-400 hover:text-brand-primary dark:hover:text-white transition-colors mb-6"
>
-
+
{contentType === 'news' ? 'All news' : contentType === 'events' ? 'All events' : contentType === 'services' ? 'All services' : 'All projects'}
)}
@@ -324,9 +323,7 @@ const jsonLd = contentType === 'news' ? JSON.stringify({
{/* Date row for non-news */}
{contentType !== 'news' && dateObj && (
-
+
@@ -340,17 +337,13 @@ const jsonLd = contentType === 'news' ? JSON.stringify({
{period && (
-
+
{periodToRelative(period)}
)}
{funder?.name && (
-
+
{funder.link
? {funder.name}
: funder.name
@@ -359,9 +352,7 @@ const jsonLd = contentType === 'news' ? JSON.stringify({
)}
{externalLink && (
-
+
Project website
)}
@@ -384,9 +375,7 @@ const jsonLd = contentType === 'news' ? JSON.stringify({
class="mt-6 inline-flex items-center gap-2 rounded-lg bg-accent px-5 py-2.5 text-sm font-semibold text-white transition-opacity hover:opacity-90 focus:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 dark:focus-visible:ring-offset-dark-background"
>
Visit service
-
+
)}
diff --git a/src/lib/hooks/use-magic-pill.ts b/src/lib/hooks/use-magic-pill.ts
index 063aa14e..c4626e62 100644
--- a/src/lib/hooks/use-magic-pill.ts
+++ b/src/lib/hooks/use-magic-pill.ts
@@ -45,7 +45,7 @@ export function useMagicPill(activeIndex: number) {
return () => window.removeEventListener('resize', onResize);
}, [measure]);
- // Re-measure once the web font (Space Grotesk) has loaded — item widths shift.
+ // Re-measure once web fonts have loaded — item widths shift as the face swaps.
useEffect(() => {
if (typeof document === 'undefined' || !('fonts' in document)) return;
let cancelled = false;
diff --git a/src/pages/about/everyone.astro b/src/pages/about/everyone.astro
index c23d74b2..a76b771f 100644
--- a/src/pages/about/everyone.astro
+++ b/src/pages/about/everyone.astro
@@ -2,6 +2,7 @@
import BaseLayout from "../../layouts/base.astro";
import people from "../../data/people.json";
import { organizations } from "../../data/organizations";
+import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/24/outline";
export const prerender = true;
@@ -89,20 +90,7 @@ const externalPeople: ExternalPerson[] = externalOrgKeys.flatMap((key) => {
href={`${BASE}/about`}
class="everyone-fade inline-flex items-center gap-1.5 text-sm font-medium text-white/60 hover:text-white transition-colors mb-8 focus:outline-none focus-visible:ring-2 focus-visible:ring-white/50 rounded"
>
-
+
About ELIXIR Norway
@@ -223,9 +211,7 @@ const externalPeople: ExternalPerson[] = externalOrgKeys.flatMap((key) => {
class="ml-auto hidden sm:inline-flex items-center gap-1.5 text-xs font-semibold text-gray-500 dark:text-gray-400 hover:text-brand-primary dark:hover:text-white transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-accent rounded"
>
View node
-
+
)}
diff --git a/src/pages/events/index.astro b/src/pages/events/index.astro
index 4c5f6823..9972fe7c 100644
--- a/src/pages/events/index.astro
+++ b/src/pages/events/index.astro
@@ -2,6 +2,7 @@
import Page from "../../layouts/page.astro";
import { getCollection } from "astro:content";
import { idToSlug, resolveContentAsset } from "../../lib/utils";
+import { ArrowRightIcon, CalendarIcon } from "@heroicons/react/24/outline";
const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -73,9 +74,7 @@ function formatDate(dateString: string): string {
) : (
)}
@@ -90,9 +89,7 @@ function formatDate(dateString: string): string {
@@ -128,9 +125,7 @@ function formatDate(dateString: string): string {
) : (
)}
@@ -145,9 +140,7 @@ function formatDate(dateString: string): string {
@@ -160,9 +153,7 @@ function formatDate(dateString: string): string {
{events.length === 0 && (
-
+
No events scheduled at this time.
)}
diff --git a/src/pages/funding-and-projects/index.astro b/src/pages/funding-and-projects/index.astro
index deee92d0..9feb6fd0 100644
--- a/src/pages/funding-and-projects/index.astro
+++ b/src/pages/funding-and-projects/index.astro
@@ -5,6 +5,7 @@ import ProjectFilters from "../../components/project-filters";
import { slugToTitleCase, idToSlug } from "../../lib/utils";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
+import { ArrowRightIcon, BuildingLibraryIcon, CalendarIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
dayjs.extend(relativeTime);
@@ -106,9 +107,7 @@ const categoryColors: Record
= {
-
+
= {
{project.data.period && (
-
+
{periodToRelative(project.data.period)}
)}
{project.data.funder?.name && (
-
+
{project.data.funder.name}
)}
@@ -196,9 +191,7 @@ const categoryColors: Record
= {
{/* Arrow */}
);
@@ -207,9 +200,7 @@ const categoryColors: Record = {
-
+
No projects match the selected filters.
diff --git a/src/pages/news/index.astro b/src/pages/news/index.astro
index fe73edcc..df8a369d 100644
--- a/src/pages/news/index.astro
+++ b/src/pages/news/index.astro
@@ -2,6 +2,7 @@
import { getCollection } from 'astro:content';
import Page from "../../layouts/page.astro";
import ListingFilters from "../../components/listing-filters";
+import { NewspaperIcon, ArrowRightIcon } from "@heroicons/react/24/outline";
import { idToSlug, resolveContentAsset, slugToTitleCase } from "../../lib/utils";
const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -102,9 +103,7 @@ const INITIAL_COUNT = 18;
) : (
)}
@@ -128,9 +127,7 @@ const INITIAL_COUNT = 18;
)}
diff --git a/src/pages/research-support.astro b/src/pages/research-support.astro
index 11761184..da69a4f6 100644
--- a/src/pages/research-support.astro
+++ b/src/pages/research-support.astro
@@ -2,6 +2,7 @@
import Page from "../layouts/page.astro";
import Pricing from "../components/pricing.tsx";
import Callout from "../components/callout.tsx";
+import { AcademicCapIcon, ArrowRightIcon, CheckIcon, CircleStackIcon, DocumentTextIcon, EnvelopeIcon, QuestionMarkCircleIcon } from "@heroicons/react/24/outline";
---
-
+
support@elixir.no
NeLS user documentation
-
+
@@ -61,17 +58,13 @@ import Callout from "../components/callout.tsx";
Support types
{["General advice & experimental design", "Programming & scripting assistance", "Data analysis & interpretation", "Data management & archiving"].map(item => (
-
-
+
{item}
))}
@@ -81,17 +74,13 @@ import Callout from "../components/callout.tsx";
Data types
{["High-throughput sequence data (DNA/RNA)", "Proteomics & structural data", "ChIP-seq & epigenomics", "Metagenomics & microbiome"].map(item => (
-
-
+
{item}
))}
@@ -101,17 +90,13 @@ import Callout from "../components/callout.tsx";
Fields of expertise
{["Genome & transcriptome assembly", "Variant calling & annotation", "Gene expression & epigenetics", "Statistical genomics & network analysis", "Cancer, health & marine biology"].map(item => (
-
-
+
{item}
))}
@@ -138,9 +123,7 @@ import Callout from "../components/callout.tsx";
-
+
The Service Agreement
diff --git a/src/pages/services/index.astro b/src/pages/services/index.astro
index 989c0ec7..cf54bc70 100644
--- a/src/pages/services/index.astro
+++ b/src/pages/services/index.astro
@@ -4,6 +4,7 @@ import Page from "../../layouts/page.astro";
import ListingFilters from "../../components/listing-filters";
import ServiceStatusSummary from "../../components/service-status-summary";
import { slugToTitleCase, idToSlug, resolveContentAsset } from "../../lib/utils";
+import { ArrowRightIcon, GlobeAltIcon } from "@heroicons/react/24/outline";
const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
const services = (await getCollection("services")).sort((a, b) => a.data.title.localeCompare(b.data.title));
@@ -106,15 +107,11 @@ const tags = [...tagCounts.entries()]
Learn more
-
+
{hasWebsite && (
-
+
Web
)}
diff --git a/src/pages/training/index.astro b/src/pages/training/index.astro
index fb777fa9..d165df01 100644
--- a/src/pages/training/index.astro
+++ b/src/pages/training/index.astro
@@ -1,5 +1,15 @@
---
import Page from "../../layouts/page.astro";
+import {
+ AcademicCapIcon,
+ ArrowTopRightOnSquareIcon,
+ BeakerIcon,
+ BookOpenIcon,
+ CalendarIcon,
+ CircleStackIcon,
+ MagnifyingGlassIcon,
+ WrenchScrewdriverIcon,
+} from "@heroicons/react/24/outline";
const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
---
@@ -33,9 +43,7 @@ const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -48,9 +56,7 @@ const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -63,9 +69,7 @@ const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -78,9 +82,7 @@ const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -102,17 +104,13 @@ const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
@@ -157,9 +149,7 @@ const BASE = import.meta.env.BASE_URL.replace(/\/$/, '');
-
+
No upcoming training events at the moment.
diff --git a/src/styles/global.scss b/src/styles/global.scss
index f340a02a..a552741a 100644
--- a/src/styles/global.scss
+++ b/src/styles/global.scss
@@ -1,5 +1,3 @@
-@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap');
-
@tailwind base;
@tailwind components;
@tailwind utilities;
@@ -48,7 +46,7 @@
html.dark { scrollbar-color: rgba(255,255,255,0.2) transparent; }
h1, h2, h3, h4, h5, h6, dt {
- @apply tracking-tight text-pretty text-slate-950 dark:text-slate-50;
+ @apply font-display tracking-tight text-pretty text-slate-950 dark:text-slate-50;
#main-content &:first-child {
@apply mt-0;
diff --git a/tailwind.config.mjs b/tailwind.config.mjs
index a099c497..96083257 100644
--- a/tailwind.config.mjs
+++ b/tailwind.config.mjs
@@ -8,7 +8,8 @@ export default {
theme: {
extend: {
fontFamily: {
- sans: ['Space Grotesk', ...defaultTheme.fontFamily.sans],
+ sans: ['var(--font-body, ui-sans-serif)', ...defaultTheme.fontFamily.sans],
+ display: ['var(--font-display, ui-sans-serif)', ...defaultTheme.fontFamily.sans],
},
colors: {
accent: 'rgb(var(--color-accent) /
)',