diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index bf4d9418..bbb9b91f 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -84,23 +84,18 @@ jobs:
- name: Build site
run: stack exec --system-ghc site rebuild
- - name: Build CSS
- # The Node/Tailwind toolchain lives in tools/tailwind/; its npm scripts
- # cd back to the repo root before invoking postcss.
- working-directory: tools/tailwind
- run: |
- npm ci
- npm run build:production
-
- # Gate every push/PR: dev.css is a checked-in snapshot of `npm run build`
- # (concatenated onto tailwind.css by site.hs for Node-less previews).
- # Regenerate it and fail if the committed copy has drifted.
- - name: Check dev.css is in sync with Tailwind output
+ # assets/css/tailwind.built.css is the checked-in Tailwind output, which
+ # `site rebuild` above copied into _site — i.e. it is what ships. So this
+ # gate is what keeps a stale stylesheet from being deployed: rebuild it
+ # from source (the Node/Tailwind toolchain lives in tools/tailwind/, whose
+ # npm scripts cd back to the repo root before invoking postcss) and fail
+ # if the committed copy differs.
+ - name: Check assets/css/tailwind.built.css is in sync with Tailwind output
run: |
- npm --prefix tools/tailwind run build:dev-snapshot
- if ! git diff --quiet -- dev.css; then
- echo "::error file=dev.css::dev.css is out of date. Regenerate it with 'cd tools/tailwind && npm run build:dev-snapshot' and commit the result."
- git --no-pager diff -- dev.css
+ (cd tools/tailwind && npm ci && npm run build)
+ if ! git diff --quiet -- assets/css/tailwind.built.css; then
+ echo "::error file=assets/css/tailwind.built.css::The checked-in CSS is out of date. Regenerate it with 'cd tools/tailwind && npm run build' and commit the result."
+ git --no-pager diff -- assets/css/tailwind.built.css
exit 1
fi
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ca9a1874..f6923f72 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -76,36 +76,39 @@ The site will be built in the `_site` directory, and you can open the files in y
The site is styled with [Tailwind CSS](https://tailwindcss.com) (v4). Tailwind is a CSS framework whose classes are short abbreviations for inline styles (e.g. `pt-4`, `text-center`), scattered directly across the HTML templates and content. At build time the Tailwind compiler acts as a kind of "CSS tree-shaker": it scans the site for the Tailwind classes actually in use and emits only the CSS needed for them.
-Two files matter:
+Three files matter:
-- `assets/css/tailwind.css` — the Tailwind entry point. It holds the v4 CSS-native configuration (`@theme` colors/fonts, `@plugin`, and the `@source` lines that tell the compiler which directories to scan). **New pages that use Tailwind classes must add an `@source` line here**, or those classes will be dropped from the production build.
+- `assets/css/tailwind.css` — the Tailwind entry point. It holds the v4 CSS-native configuration (`@theme` colors/fonts, `@plugin`, and the `@source` lines that tell the compiler which directories to scan). **New pages that use Tailwind classes must add an `@source` line here**, or those classes will be dropped from the build. This file is compiler *input*; it is never served.
+- `assets/css/tailwind.built.css` — the compiler's output, **checked into the repository** and served as `assets/css/tailwind.css`. This is the CSS the live site loads, so it must be regenerated and committed whenever it changes (see below).
- `assets/css/main.css` — hand-written CSS that is *not* processed by Tailwind. This is the place for ordinary, non-Tailwind styles.
### Do I need Node installed?
-**No, if you are only editing content or Haskell code.** Hakyll concatenates a checked-in snapshot, `dev.css`, onto `assets/css/tailwind.css` at build time (see the `match "assets/css/tailwind.css"` rule in `site.hs`). `dev.css` is a pre-generated copy of the real Tailwind output, so `stack exec -- site build` on its own produces a site that looks close enough to preview — no Node toolchain required. This keeps the site accessible to contributors of all skill sets.
+**No, if you are only editing content or Haskell code.** Hakyll copies the checked-in `assets/css/tailwind.built.css` into the site, so `stack exec -- site build` alone gives you the real stylesheet — no Node toolchain required. This keeps the site accessible to contributors of all skill sets.
-**Yes, if you are changing the appearance.** Because `dev.css` is only a snapshot, it does *not* reflect edits to `assets/css/tailwind.css`, `assets/css/main.css`, `tools/tailwind/postcss.config.js`, or any *newly used* Tailwind class. To regenerate the real CSS you need [Node.js](https://nodejs.org). The Node/Tailwind toolchain lives in [`tools/tailwind/`](tools/tailwind/) (see its README), separate from the Hakyll project, so run npm from there:
+**Yes, if you are changing the appearance** — that is, editing `assets/css/tailwind.css`, `assets/css/main.css`, `tools/tailwind/postcss.config.js`, or *using a Tailwind class the site did not use before* (Tailwind only emits the classes it finds, so a brand-new class has no CSS until the compiler runs). You will need [Node.js](https://nodejs.org). The toolchain lives in [`tools/tailwind/`](tools/tailwind/) (see its README), separate from the Hakyll project, so run npm from there:
```bash
cd tools/tailwind
-npm ci # once, to install the toolchain
-npm run build # compile -> _site/assets/css/tailwind.css
-npm run build:production # minified build (NODE_ENV=production)
+npm ci # once, to install the toolchain
+npm run build # compile -> assets/css/tailwind.built.css
+npm run watch # same, then recompile on source/content changes
```
If you do not want to install `npm` globally and have `nix` available, drop into the Nix development shell which provides `npm` and a basic Haskell toolchain.
-If your change alters the CSS, regenerate the checked-in `dev.css` snapshot and commit it:
+**Commit the regenerated `assets/css/tailwind.built.css` with your change.** CI reruns `npm run build` on every push and PR and fails if the committed copy has drifted, so a stale stylesheet cannot reach the live site.
+
+### Live preview
+
+Run both watchers and the two chain into each other — postcss writes `assets/css/tailwind.built.css`, which Hakyll then copies into `_site` and reloads:
```bash
-cd tools/tailwind
-npm run build:dev-snapshot # recompile the dev.css snapshot in place
+cabal run site -- watch & # or: stack exec -- site watch
+cd tools/tailwind && npm run watch
```
-CI runs this same command and fails the build if the committed `dev.css` is out of date, so a stale snapshot cannot slip through review.
-
-> **Note:** `dev.css` is only an *unminified* snapshot of `npm run build`; it still differs from the minified `npm run build:production` output shipped to production, so verify appearance-critical changes against a real production build.
+> **Note:** `npm run watch` is *additive* — it picks up newly used classes, but a class you removed keeps its CSS until the next one-shot `npm run build`. So finish with `npm run build` before committing, or CI's check will complain about the leftovers.
## CI
@@ -117,8 +120,8 @@ The general steps are:
2. Install Haskell and Node.js
3. Restore the cached build artefacts
4. Build the `site` executable
-5. Rebuild the site contents using the `site` executable
-6. Build the production CSS (`cd tools/tailwind && npm ci && npm run build:production`)
+5. Rebuild the site contents using the `site` executable (this copies the checked-in CSS into `_site`)
+6. Recompile the CSS (`cd tools/tailwind && npm ci && npm run build`) and fail if the committed `assets/css/tailwind.built.css` has drifted
7. Check out the `main` branch
8. Copy the `_site` directory over the `main` branch contents
9. Commit and push the site contents to the `main` branch.
diff --git a/assets/css/main.css b/assets/css/main.css
index a4afb548..25e61417 100644
--- a/assets/css/main.css
+++ b/assets/css/main.css
@@ -14,30 +14,34 @@ textarea::placeholder {
opacity: 1;
}
-a {
- cursor: pointer;
- --tw-text-opacity: 1;
- color: rgba(109, 40, 217, var(--tw-text-opacity));
-}
+/*
+ * Element defaults for text colour live in `@layer base` so that Tailwind's
+ * `text-*` utilities (later `utilities` layer) can override them — e.g. the
+ * light paragraph/link colours on the dark panels. Everything outside this
+ * block stays unlayered on purpose and therefore beats utilities.
+ */
+@layer base {
+ a {
+ cursor: pointer;
+ color: #6d28d9; /* purple-700 */
+ }
-a:hover {
- text-decoration: underline;
-}
+ a:hover {
+ color: #4c1d95; /* purple-900 */
+ text-decoration: underline;
+ }
-a:hover,
-a:visited {
- --tw-text-opacity: 1;
- color: rgba(139, 92, 246, var(--tw-text-opacity));
+ p {
+ color: #52525b; /* gray-600 */
+ }
}
.arrow-link {
- --tw-border-opacity: 1;
- border-color: rgba(109, 40, 217, var(--tw-border-opacity));
+ border-color: #6d28d9;
}
.arrow-link:hover {
- --tw-border-opacity: 1;
- border-color: rgba(139, 92, 246, var(--tw-border-opacity));
+ border-color: #4c1d95;
}
.arrow-link {
@@ -181,17 +185,6 @@ h6 {
* {
--tw-ring-inset: var(--tw-empty);
}
-
-.divide-y-2 > :not([hidden]) ~ :not([hidden]) {
- --tw-divide-y-reverse: 0;
- border-top-width: calc(2px * (1 - var(--tw-divide-y-reverse)));
- border-bottom-width: calc(2px * var(--tw-divide-y-reverse));
-}
-
-p {
- --tw-text-opacity: 1;
- color: rgba(113, 113, 122, var(--tw-text-opacity));
-}
.youtube-video {
position: relative;
width: 100%;
diff --git a/dev.css b/assets/css/tailwind.built.css
similarity index 97%
rename from dev.css
rename to assets/css/tailwind.built.css
index c2e2bf83..c6baab9b 100644
--- a/dev.css
+++ b/assets/css/tailwind.built.css
@@ -287,6 +287,24 @@
.z-20 {
z-index: 20;
}
+ .container {
+ width: 100%;
+ @media (width >= 40rem) {
+ max-width: 40rem;
+ }
+ @media (width >= 48rem) {
+ max-width: 48rem;
+ }
+ @media (width >= 64rem) {
+ max-width: 64rem;
+ }
+ @media (width >= 80rem) {
+ max-width: 80rem;
+ }
+ @media (width >= 96rem) {
+ max-width: 96rem;
+ }
+ }
.m-4 {
margin: calc(var(--spacing) * 4);
}
@@ -843,6 +861,13 @@
.w-48 {
width: calc(var(--spacing) * 48);
}
+ .w-auto {
+ width: auto;
+ }
+ .w-fit {
+ width: -moz-fit-content;
+ width: fit-content;
+ }
.w-full {
width: 100%;
}
@@ -876,6 +901,9 @@
.cursor-pointer {
cursor: pointer;
}
+ .grid-cols-\[auto_1fr\] {
+ grid-template-columns: auto 1fr;
+ }
.flex-col {
flex-direction: column;
}
@@ -913,6 +941,13 @@
margin-block-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)));
}
}
+ .space-y-2 {
+ :where(& > :not(:last-child)) {
+ --tw-space-y-reverse: 0;
+ margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));
+ margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)));
+ }
+ }
.space-y-4 {
:where(& > :not(:last-child)) {
--tw-space-y-reverse: 0;
@@ -934,6 +969,10 @@
margin-block-end: calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)));
}
}
+ .gap-x-3 {
+ -moz-column-gap: calc(var(--spacing) * 3);
+ column-gap: calc(var(--spacing) * 3);
+ }
.space-x-4 {
:where(& > :not(:last-child)) {
--tw-space-x-reverse: 0;
@@ -955,6 +994,9 @@
margin-inline-end: calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-x-reverse)));
}
}
+ .gap-y-1 {
+ row-gap: calc(var(--spacing) * 1);
+ }
.divide-y-2 {
:where(& > :not(:last-child)) {
--tw-divide-y-reverse: 0;
@@ -964,6 +1006,11 @@
border-bottom-width: calc(2px * calc(1 - var(--tw-divide-y-reverse)));
}
}
+ .divide-gray-200 {
+ :where(& > :not(:last-child)) {
+ border-color: var(--color-gray-200);
+ }
+ }
.self-start {
align-self: flex-start;
}
@@ -1149,6 +1196,10 @@
font-size: var(--text-4xl);
line-height: var(--tw-leading, var(--text-4xl--line-height));
}
+ .text-base {
+ font-size: var(--text-base);
+ line-height: var(--tw-leading, var(--text-base--line-height));
+ }
.text-lg {
font-size: var(--text-lg);
line-height: var(--tw-leading, var(--text-lg--line-height));
@@ -1207,6 +1258,9 @@
.text-gray-600 {
color: var(--color-gray-600);
}
+ .text-purple-200 {
+ color: var(--color-purple-200);
+ }
.text-purple-700 {
color: var(--color-purple-700);
}
@@ -1249,6 +1303,13 @@
}
}
}
+ .hover\:text-white {
+ &:hover {
+ @media (hover: hover) {
+ color: var(--color-white);
+ }
+ }
+ }
.focus\:outline-none {
&:focus {
--tw-outline-style: none;
@@ -1598,6 +1659,11 @@
margin-top: calc(var(--spacing) * 12);
}
}
+ .md\:mt-16 {
+ @media (width >= 48rem) {
+ margin-top: calc(var(--spacing) * 16);
+ }
+ }
.md\:mt-24 {
@media (width >= 48rem) {
margin-top: calc(var(--spacing) * 24);
@@ -1725,6 +1791,12 @@
line-height: var(--tw-leading, var(--text-5xl--line-height));
}
}
+ .md\:text-lg {
+ @media (width >= 48rem) {
+ font-size: var(--text-lg);
+ line-height: var(--tw-leading, var(--text-lg--line-height));
+ }
+ }
.md\:leading-tight {
@media (width >= 48rem) {
--tw-leading: var(--leading-tight);
diff --git a/assets/css/tailwind.css b/assets/css/tailwind.css
index cc131301..bc0a212a 100644
--- a/assets/css/tailwind.css
+++ b/assets/css/tailwind.css
@@ -1,21 +1,18 @@
/**
- * This is the Tailwind entry point (source). It is NOT overwritten by the
- * build — its compiled *output* lands at _site/assets/css/tailwind.css (see
- * steps below). Only put Tailwind config/directives here; hand-written CSS
- * belongs in assets/css/main.css.
+ * This is the Tailwind entry point (source), and it is never served: only put
+ * Tailwind config/directives here, and hand-written CSS in assets/css/main.css.
*
- * NOTE: The underlying implementation details of how this works are as follows
- * 1. tailwindcss needs these directives in order to know where to generate the
- * output
- * 2. first, hakyll is run and copies this source file verbatim to
- * _site/assets/css/tailwind.css
- * 3. then, after hakyll is done, postcss is run on _this_ source
- * assets/css/tailwind.css file. Postcss will, during execution, invoke
- * tailwindcss. tailwindcss (the compiler) will scan all the files in the
- * site for tailwind classes (including _this_ source file).
- * 4. postcss's output file is configured to be _site/assets/css/tailwind.css,
- * so postcss overwrites the copy hakyll made in step 2 with the real,
- * compiled CSS. This source file is never modified.
+ * How it reaches the browser:
+ * 1. postcss runs tailwindcss over this file (`npm run build` in
+ * tools/tailwind), scanning the @source paths below for utility classes, and
+ * writes the compiled CSS to assets/css/tailwind.built.css. That output is
+ * checked into the repo, so building the site needs no Node toolchain.
+ * 2. hakyll copies assets/css/tailwind.built.css to
+ * _site/assets/css/tailwind.css — the URL the templates link. This source
+ * file is neither modified nor copied.
+ *
+ * So: regenerate and commit the built file whenever you touch this one, use a
+ * new utility class, or edit the postcss config. CI fails on any drift.
*/
/*
@@ -24,7 +21,7 @@
* @source paths below are scanned — mirrors the old
* topLevelFoldersWithTailwind/topLevelFilesWithTailwind purge.content list.
* New pages using Tailwind utility classes must add an @source line here,
- * or their classes will be missing from the production build.
+ * or their classes will be missing from the compiled CSS.
*/
/*
* The Node/Tailwind toolchain lives in tools/tailwind/ (see its README), so
diff --git a/flake.nix b/flake.nix
index c6c5de41..c5eaf976 100644
--- a/flake.nix
+++ b/flake.nix
@@ -32,9 +32,17 @@
pkgs.ghc
pkgs.haskell-language-server
+ # Screenshotting pages during design work.
+ (pkgs.python3.withPackages (ps: [ ps.playwright ]))
+
# System.
pkgs.zlib
];
+
+ env = {
+ PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
+ PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = "true";
+ };
};
};
flake = { };
diff --git a/site.hs b/site.hs
index 47de7269..99ffe664 100644
--- a/site.hs
+++ b/site.hs
@@ -40,32 +40,31 @@ config = defaultConfiguration
ignoreFile defaultConfiguration file
}
+-- | The Tailwind entry point and its checked-in build output. Neither is served
+-- under its own name: the entry point (@import@/@\@theme@/@\@source@) is
+-- compiler input a browser cannot use, and the build output is routed to the
+-- entry point's URL instead.
+tailwindFiles :: Pattern
+tailwindFiles = tailwindEntryPoint .||. tailwindBuilt
+
+tailwindEntryPoint, tailwindBuilt :: Pattern
+tailwindEntryPoint = "assets/css/tailwind.css"
+tailwindBuilt = "assets/css/tailwind.built.css"
+
--------------------------------------------------------------------------------------------------------
-- MAIN GENERATION -------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------
main :: IO ()
main = hakyllWith config $ do
-- statics ---------------------------------------------------------------------------------------------
- match "dev.css" $ compile getResourceString
- match "assets/css/tailwind.css" $ do
- route idRoute
- -- We concatenate a dev.css file that exists at the root of the repository so that people don't
- -- need to have nodejs setup or working in order to get a functional development experience
- -- "why yes this is very crimes why do you ask"
- -- dev.css is a checked-in snapshot of the Tailwind build; regenerate it
- -- with `npm run build:dev-snapshot` from tools/tailwind and commit. CI
- -- fails if it drifts.
- compile $ do
- devCss <- loadBody "dev.css"
- fmap ((devCss ++ "\n") ++) <$> getResourceString
-
- -- Here is where interop with JS would happen if we wanted every
- -- Haskell developer working on this site to also set up a Node toolchain
- -- match "assets/css/*.css" $ do
- -- route idRoute
- -- undefined -- (insert some invoke "npm run build" step here)
+ -- The Tailwind build output is checked in, so a Node toolchain is needed to
+ -- *change* the CSS but not to build the site with the real thing. Regenerate
+ -- it with `npm run build` from tools/tailwind; CI fails if it has drifted.
+ match tailwindBuilt $ do
+ route $ constRoute "assets/css/tailwind.css"
+ compile copyFileCompiler
- match "assets/**" $ do
+ match ("assets/**" .&&. complement tailwindFiles) $ do
route idRoute
compile copyFileCompiler
diff --git a/templates/affiliates/list.html b/templates/affiliates/list.html
index 8382c387..98ac176f 100644
--- a/templates/affiliates/list.html
+++ b/templates/affiliates/list.html
@@ -2,7 +2,7 @@
title: Affiliates
---
-
+
We invite existing Haskell projects, committees and communities to explicitly affiliate and align themselves
@@ -11,7 +11,7 @@
@@ -19,7 +19,7 @@
-
+

diff --git a/templates/careers/list.html b/templates/careers/list.html
index 645c1ac6..12c142bf 100644
--- a/templates/careers/list.html
+++ b/templates/careers/list.html
@@ -9,7 +9,7 @@
Careers
$if(openreqs)$
-
+
Working at the Haskell Foundation
Interested in working at the crossroads of the Haskell ecosystem?
@@ -27,7 +27,7 @@
Working at
$endif$
-
+
Haskell Foundation Sponsors Hiring Haskellers
Many of our sponsors are actively hiring Haskell engineers.
diff --git a/templates/careers/page.html b/templates/careers/page.html
index 3a3efa11..7cf03b66 100644
--- a/templates/careers/page.html
+++ b/templates/careers/page.html
@@ -1,6 +1,6 @@
-
+
$title$
$summary$
diff --git a/templates/donations/list.html b/templates/donations/list.html
index c4a2be27..7098d3ed 100644
--- a/templates/donations/list.html
+++ b/templates/donations/list.html
@@ -121,16 +121,16 @@
Gold
-
+
In-Kind Support
- Non-financial contributions to HF are also welcome. As a volunteer-based organization, the Haskell Foundation needs volunteers who can work on software, documentation, promotion, and other tasks to support the HF affiliated projects and the Haskell community. Individuals who contribute their own time or on behalf of their company are the backbone of our organization. Please reach out to us at contact@haskell.foundation to learn more about how you can volunteer or offer in-kind support.
+ Non-financial contributions to HF are also welcome. As a volunteer-based organization, the Haskell Foundation needs volunteers who can work on software, documentation, promotion, and other tasks to support the HF affiliated projects and the Haskell community. Individuals who contribute their own time or on behalf of their company are the backbone of our organization. Please reach out to us at contact@haskell.foundation to learn more about how you can volunteer or offer in-kind support.
-
+

diff --git a/templates/events/page.html b/templates/events/page.html
index 4b447252..e5a90e3f 100644
--- a/templates/events/page.html
+++ b/templates/events/page.html
@@ -1,6 +1,6 @@
-
+
$title$
$summary$
diff --git a/templates/events/tile.html b/templates/events/tile.html
index 7bad13be..2c3f6271 100644
--- a/templates/events/tile.html
+++ b/templates/events/tile.html
@@ -3,21 +3,12 @@
$title$
$summary$
-
-
-
- | Dates: |
-
- $daterange$
- |
-
-
- | Location: |
-
- $location$
- |
-
-
+
+ - Dates:
+ - $daterange$
+ - Location:
+ - $location$
+
diff --git a/templates/footer.html b/templates/footer.html
index b5263c34..5caab002 100644
--- a/templates/footer.html
+++ b/templates/footer.html
@@ -1,4 +1,4 @@
-
+
SPONSORS
@@ -40,20 +40,21 @@
+
-

-
+

+
diff --git a/templates/homepage.html b/templates/homepage.html
index dcfd6daa..ae2cf845 100644
--- a/templates/homepage.html
+++ b/templates/homepage.html
@@ -15,7 +15,7 @@
Amplify Haskell’s impact on humanity.
-
+
$if(openreqs)$
$for(openreqs)$
@@ -78,7 +78,7 @@
We drive change.
-
+
Not “just another programming language”
Haskell embodies a radical and elegant attack on the entire enterprise of writing software. It profoundly influences the world of software for the better.
@@ -99,7 +99,7 @@
Our Ethos
-
+
@@ -145,7 +145,7 @@
Follow HF Developments
-
+
diff --git a/templates/mobile-nav-flyout.html b/templates/mobile-nav-flyout.html
index 9d63aace..c6d90f5a 100644
--- a/templates/mobile-nav-flyout.html
+++ b/templates/mobile-nav-flyout.html
@@ -20,31 +20,31 @@
diff --git a/templates/nav.html b/templates/nav.html
index 64b4ab33..8ec9c524 100644
--- a/templates/nav.html
+++ b/templates/nav.html
@@ -2,7 +2,7 @@
diff --git a/templates/news/page.html b/templates/news/page.html
index 968bd111..be8b19dd 100644
--- a/templates/news/page.html
+++ b/templates/news/page.html
@@ -1,9 +1,9 @@
-
+
$title$
-
-
$if(author)$$author$, $endif$$date$
+
+ $if(author)$$author$, $endif$$date$
diff --git a/templates/news/tile.html b/templates/news/tile.html
index e751eca4..50bb067e 100644
--- a/templates/news/tile.html
+++ b/templates/news/tile.html
@@ -1,34 +1,25 @@
-
+
$category$
-
- $for(news)$
-
-
-
-
-
-
$title$
- $if(author)$
-
- $author$
-
- $endif$
-
-
-
-
-
+ $for(news)$
+
+
$title$
+ $if(author)$
+
+ $author$
+
+ $endif$
+
+
$endfor$
diff --git a/templates/partnerships/page.html b/templates/partnerships/page.html
index 33723db2..9ccddb65 100644
--- a/templates/partnerships/page.html
+++ b/templates/partnerships/page.html
@@ -1,6 +1,6 @@
-
+
$title$
$summary$
diff --git a/templates/podcast/list.html b/templates/podcast/list.html
index 968718ba..da83792b 100644
--- a/templates/podcast/list.html
+++ b/templates/podcast/list.html
@@ -7,32 +7,37 @@
The Haskell Interlude
-
-
- The Haskell Interlude is a Haskell-focused podcast where we
- interview guests from the Haskell community. The hosts are
- Samantha Frohlich, Andres Löh, Matthías Páll Gissurarson,
- Mike Sperber, Farhad Mehta, and Jess Foster.
-
-
- The music used is "Blue Lambda" by Donya Quick.
- Many thanks to Donya for giving us permission to use this track for our podcast.
-
-
- This podcast would not be possible without the help of our Editors, John Zhuang Hui and Jess Foster, and our Quality Inspector, Artin Ghasivand.
-
-
- We are very grateful to our previous hosts Alejandro
- Serrano, Joachim Breitner, Wouter Swierstra, and Niki Vazou,
- as well as to Alp Mestanogullari and Jose Calderon for their editing work and
- to Krishna Padmasola, Ben Orchard, and Mihai Maruseac for their transcription work.
-
-
- You can also follow the Interlude
- on Mastodon,
- Bluesky
- and X.
-
+
+
+
+ The Haskell Interlude is a Haskell-focused podcast where we
+ interview guests from the Haskell community. The hosts are
+ Samantha Frohlich, Andres Löh, Matthías Páll Gissurarson,
+ Mike Sperber, Farhad Mehta, and Jess Foster.
+
+
+ The music used is "Blue Lambda" by
+ Donya Quick.
+ Many thanks to Donya for giving us permission to use this track for our podcast.
+
+
+ You can also follow the Interlude on
+ Mastodon,
+ Bluesky
+ and X.
+
+
+
+
+ This podcast would not be possible without the help of our Editors, John Zhuang Hui and Jess Foster, and our Quality Inspector, Artin Ghasivand.
+
+
+ We are very grateful to our previous hosts Alejandro
+ Serrano, Joachim Breitner, Wouter Swierstra, and Niki Vazou,
+ as well as to Alp Mestanogullari and Jose Calderon for their editing work and
+ to Krishna Padmasola, Ben Orchard, and Mihai Maruseac for their transcription work.
+
+
diff --git a/templates/press/list.html b/templates/press/list.html
index 7554c73e..269a0c97 100644
--- a/templates/press/list.html
+++ b/templates/press/list.html
@@ -13,11 +13,11 @@
Press
-
+
Press Kit
- Please reach out to us at press@haskell.foundation for our
+ Please reach out to us at press@haskell.foundation for our
press kit, including relevant marketing materials and branding.
diff --git a/templates/projects/list.html b/templates/projects/list.html
index 84165679..9f8363f6 100644
--- a/templates/projects/list.html
+++ b/templates/projects/list.html
@@ -8,10 +8,10 @@
Projects
-
+
diff --git a/templates/projects/tile.html b/templates/projects/tile.html
index 5c7a14a9..7d68b84b 100644
--- a/templates/projects/tile.html
+++ b/templates/projects/tile.html
@@ -1,13 +1,13 @@
$title$
-
$body$
+ $body$
$subtitle$
-
+
$if(leader0name)$
diff --git a/templates/reports/page.html b/templates/reports/page.html
index bd12aa81..436361b2 100644
--- a/templates/reports/page.html
+++ b/templates/reports/page.html
@@ -1,9 +1,9 @@
-
+
$title$
-
-
$author$, $date$
+
+ $author$, $date$
$if(summary)$
diff --git a/templates/resources/tile.html b/templates/resources/tile.html
index c80ed06b..faf19bb3 100644
--- a/templates/resources/tile.html
+++ b/templates/resources/tile.html
@@ -1,6 +1,6 @@
$title$
-
$body$
+ $body$
>> $link-text$
diff --git a/templates/who-we-are/exec-and-board.html b/templates/who-we-are/exec-and-board.html
index 66a36dee..e8b89df6 100644
--- a/templates/who-we-are/exec-and-board.html
+++ b/templates/who-we-are/exec-and-board.html
@@ -8,7 +8,7 @@
Who We Are
$if(currentexecutiveteam)$
-
+
Executive Team
@@ -17,7 +17,7 @@
Executive
-
+
$for(currentexecutiveteam)$
@@ -28,9 +28,7 @@
$name$
$title$
-
- $body$
-
+ $body$
@@ -46,7 +44,7 @@
$name$
$endif$
-
+
The Board of Directors
@@ -56,7 +54,7 @@
The Board
-
+
$for(currentboard)$
@@ -69,9 +67,7 @@
$name$
$endif$
-
- $body$
-
+ $body$
$if(false)$
Committees
diff --git a/templates/who-we-are/past-board.html b/templates/who-we-are/past-board.html
index 696d849b..f91c89b7 100644
--- a/templates/who-we-are/past-board.html
+++ b/templates/who-we-are/past-board.html
@@ -6,7 +6,7 @@
Past Boards
-
+
Past Board Members
@@ -16,7 +16,7 @@
Past Board
-
+
$for(pastboard)$
@@ -26,13 +26,11 @@
Past Board
$name$
$if(title)$
$title$
- $tenureStart$ - $tenureEnd$
+ $tenureStart$ - $tenureEnd$
$endif$
-
- $body$
-
+ $body$
$if(committees)$
Committees
@@ -55,7 +53,7 @@
$name$
-
+
Past Executive Team Members
@@ -65,7 +63,7 @@
Past Execu
-
+
$for(pastexecutiveteam)$
@@ -75,13 +73,11 @@
Past Execu
$name$
$if(title)$
$title$
- $tenureStart$ - $tenureEnd$
+ $tenureStart$ - $tenureEnd$
$endif$
-
- $body$
-
+ $body$
-
+
The Interim Board of Directors
@@ -106,7 +102,7 @@
The Interi
-
+
$for(interimboard)$
@@ -117,9 +113,7 @@
$name$
$interimBoardTitle$
-
- $body$
-
+ $body$
$endfor$
diff --git a/tools/screenshot/shoot.py b/tools/screenshot/shoot.py
new file mode 100755
index 00000000..a491ee97
--- /dev/null
+++ b/tools/screenshot/shoot.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+"""Screenshot pages of the built site for visual review.
+
+Needs the Nix dev shell, which provides python3 with playwright and the
+browsers (`nix develop`, or automatically via direnv).
+
+Start the two watchers once, then shoot as often as you like — postcss keeps
+`assets/css/tailwind.built.css` current and Hakyll copies it into `_site`:
+
+ cabal run site -- watch & # http://127.0.0.1:8000
+ (cd tools/tailwind && npm run watch) &
+ ./tools/screenshot/shoot.py /tmp/shots --slice 1100 home=/ news=/news/
+ ./tools/screenshot/shoot.py /tmp/shots --width 390 --slice 900 mhome=/
+
+For a one-shot look, build by hand and serve without recompiling:
+
+ (cd tools/tailwind && npm run build) && cabal run site -- build
+ cabal run site -- server &
+ ./tools/screenshot/shoot.py /tmp/shots --slice 1100 home=/
+
+Here you must repeat the first line after every template or CSS edit: `server`
+only serves `_site`, it does not rebuild, so it will happily keep serving stale
+pages (no need to restart it, though).
+
+Either way the CSS is the real thing — but `npm run watch` only ever *adds*
+utilities, so a class you deleted still has styles until the next one-shot
+`npm run build`. If a removal seems not to take effect, that is why.
+
+Targets are `name=path` (resolved against --base) or `name=full-url`:
+
+ ./tools/screenshot/shoot.py out/ home=/ news=/news/
+ ./tools/screenshot/shoot.py out/ --width 390 --slice 900 news=/news/
+
+Without --slice one full-page PNG per target is written; with it the page is cut
+into `--slice`-tall pieces (`name-00.png`, `name-01.png`, …), which keeps long
+pages legible instead of downscaling them to nothing.
+"""
+
+import argparse
+from playwright.sync_api import sync_playwright
+
+
+def main():
+ ap = argparse.ArgumentParser()
+ ap.add_argument("outdir")
+ ap.add_argument("targets", nargs="+", metavar="NAME=PATH")
+ ap.add_argument("--base", default="http://127.0.0.1:8000",
+ help="server to resolve relative targets against (`cabal run site -- server`)")
+ ap.add_argument("--width", type=int, default=1440)
+ ap.add_argument("--slice", type=int, default=0, help="cut into pieces of this height")
+ ap.add_argument("--settle", type=int, default=1500, help="ms to wait after load")
+ args = ap.parse_args()
+
+ targets = [(name, url if "://" in url else args.base.rstrip("/") + "/" + url.lstrip("/"))
+ for name, url in (t.split("=", 1) for t in args.targets)]
+ viewport = {"width": args.width, "height": args.slice or 1000}
+
+ with sync_playwright() as pw:
+ browser = pw.chromium.launch()
+ for name, url in targets:
+ page = browser.new_page(viewport=viewport)
+ page.goto(url, wait_until="load")
+ page.wait_for_timeout(args.settle)
+ height = page.evaluate("document.documentElement.scrollHeight")
+ if args.slice:
+ for i, top in enumerate(range(0, height, args.slice)):
+ page.screenshot(
+ path=f"{args.outdir}/{name}-{i:02d}.png",
+ full_page=True,
+ clip={"x": 0, "y": top, "width": args.width,
+ "height": min(args.slice, height - top)},
+ )
+ else:
+ page.screenshot(path=f"{args.outdir}/{name}.png", full_page=True)
+ print(f"{name}: {args.width}x{height}")
+ page.close()
+ browser.close()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/tailwind/README.md b/tools/tailwind/README.md
index 9a6c0d11..f97522e2 100644
--- a/tools/tailwind/README.md
+++ b/tools/tailwind/README.md
@@ -6,10 +6,12 @@ don't get tangled (`node_modules/` no longer sits next to the Haskell source,
and Hakyll's `ignoreFile` just skips all of `tools/`).
It contains only *build config* — `package.json`, `package-lock.json`, and
-`postcss.config.js`. The CSS **sources** stay where Hakyll routes them from:
+`postcss.config.js`. The CSS itself stays where Hakyll routes it from:
- `assets/css/tailwind.css` — Tailwind v4 entry point (`@theme`, `@source`,
`@plugin`). New pages using Tailwind classes must add an `@source` line here.
+- `assets/css/tailwind.built.css` — this toolchain's output, checked in and
+ served as `assets/css/tailwind.css`.
- `assets/css/main.css` — hand-written, non-Tailwind CSS.
## Usage
@@ -17,12 +19,16 @@ It contains only *build config* — `package.json`, `package-lock.json`, and
Run npm **from this directory**:
```bash
-npm ci # install the toolchain (once)
-npm run build # dev build -> ../../_site/assets/css/tailwind.css
-npm run build:production # minified -> ../../_site/assets/css/tailwind.css (NODE_ENV=production)
-npm run build:dev-snapshot # regenerate -> ../../dev.css (the Node-less preview snapshot)
+npm ci # install the toolchain (once)
+npm run build # compile -> ../../assets/css/tailwind.built.css
+npm run watch # same, then recompile on source/content changes
```
+Pair `npm run watch` with `
site -- watch`: postcss
+writes the built CSS, Hakyll copies it into `_site` and reloads. Note that
+`--watch` only ever *adds* utilities, so finish with a one-shot `npm run build`
+before committing (see [../../CONTRIBUTING.md](../../CONTRIBUTING.md)).
+
## Why the scripts `cd ../..`
Two Tailwind v4 constraints force the build to run from the **repo root**, not
@@ -42,9 +48,13 @@ from here:
The `--config tools/tailwind` flag points postcss back here for
`postcss.config.js` after the `cd`.
-## dev.css
+## Why the output is checked in
+
+`assets/css/tailwind.built.css` is a generated file in version control, which is
+a deliberate trade: contributors without a Node toolchain can build and preview
+the site with the real CSS, and nothing has to run npm at deploy time. The
+price is that it *is* the deployed stylesheet, so it must not go stale — CI
+recompiles it on every push and PR and fails on any difference.
-`dev.css` (at the repo root) is a checked-in snapshot of `npm run build` that
-`site.hs` concatenates onto `tailwind.css` so contributors without Node can
-still preview the site. CI fails if it drifts; regenerate it with
-`npm run build:dev-snapshot` and commit.
+There is no minified variant: cssnano saved ~800 bytes gzipped, which is not
+worth a single-line file that cannot be diffed or merged.
diff --git a/tools/tailwind/package-lock.json b/tools/tailwind/package-lock.json
index 4a3733b4..ce98fbe3 100644
--- a/tools/tailwind/package-lock.json
+++ b/tools/tailwind/package-lock.json
@@ -13,7 +13,6 @@
"devDependencies": {
"@tailwindcss/typography": "^0.5.19",
"autoprefixer": "^10.5.0",
- "cssnano": "^8.0.0",
"postcss": "^8.5.14",
"postcss-cli": "^11.0.1",
"tailwindcss": "4.2.4"
@@ -31,13 +30,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@colordx/core": {
- "version": "5.4.3",
- "resolved": "https://registry.npmjs.org/@colordx/core/-/core-5.4.3.tgz",
- "integrity": "sha512-kIxYSfA5T8HXjav55UaaH/o/cKivF6jCCGIb8eqtcsfI46wsvlSiT8jMDyrl779qLec3c2c2oHBZo4oAhvbjrQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
@@ -306,6 +298,64 @@
"node": ">=14.0.0"
}
},
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
+ "version": "1.8.1",
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.1.0",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
+ "version": "1.8.1",
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
+ "version": "1.1.0",
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
+ "version": "1.1.1",
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.7.1",
+ "@emnapi/runtime": "^1.7.1",
+ "@tybys/wasm-util": "^0.10.1"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/Brooooooklyn"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
+ "version": "0.10.1",
+ "inBundle": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
+ "version": "2.8.1",
+ "inBundle": true,
+ "license": "0BSD",
+ "optional": true
+ },
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.4.tgz",
@@ -467,13 +517,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/boolbase": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
- "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
@@ -521,19 +564,6 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
- "node_modules/caniuse-api": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
- "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "browserslist": "^4.0.0",
- "caniuse-lite": "^1.0.0",
- "lodash.memoize": "^4.1.2",
- "lodash.uniq": "^4.5.0"
- }
- },
"node_modules/caniuse-lite": {
"version": "1.0.30001792",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001792.tgz",
@@ -615,60 +645,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/commander": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
- "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=16"
- }
- },
- "node_modules/css-select": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
- "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "boolbase": "^1.0.0",
- "css-what": "^6.1.0",
- "domhandler": "^5.0.2",
- "domutils": "^3.0.1",
- "nth-check": "^2.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/fb55"
- }
- },
- "node_modules/css-tree": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz",
- "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "mdn-data": "2.27.1",
- "source-map-js": "^1.2.1"
- },
- "engines": {
- "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
- }
- },
- "node_modules/css-what": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
- "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">= 6"
- },
- "funding": {
- "url": "https://github.com/sponsors/fb55"
- }
- },
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -682,120 +658,6 @@
"node": ">=4"
}
},
- "node_modules/cssnano": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-8.0.0.tgz",
- "integrity": "sha512-FBjMD2UTnAshdTNoFnF6vLICR3/gCypkWdveXbxpO+cPlJZ3RYdYOv84ibCxEHzo5Wuoy7yAmBkmUGuLLzoUwA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cssnano-preset-default": "^8.0.0",
- "lilconfig": "^3.1.3"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/cssnano"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/cssnano-preset-default": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-8.0.0.tgz",
- "integrity": "sha512-uIJx5WOQ2vlH0HwKZz3AbhYffVvYTUcS2S76gr3oLnU2i9qn7yy3LLs0rk3YAtBB9gayYr0aTvk0pZ6MlenUlw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "browserslist": "^4.28.2",
- "cssnano-utils": "^6.0.0",
- "postcss-calc": "^10.1.1",
- "postcss-colormin": "^8.0.0",
- "postcss-convert-values": "^8.0.0",
- "postcss-discard-comments": "^8.0.0",
- "postcss-discard-duplicates": "^8.0.0",
- "postcss-discard-empty": "^8.0.0",
- "postcss-discard-overridden": "^8.0.0",
- "postcss-merge-longhand": "^8.0.0",
- "postcss-merge-rules": "^8.0.0",
- "postcss-minify-font-values": "^8.0.0",
- "postcss-minify-gradients": "^8.0.0",
- "postcss-minify-params": "^8.0.0",
- "postcss-minify-selectors": "^8.0.0",
- "postcss-normalize-charset": "^8.0.0",
- "postcss-normalize-display-values": "^8.0.0",
- "postcss-normalize-positions": "^8.0.0",
- "postcss-normalize-repeat-style": "^8.0.0",
- "postcss-normalize-string": "^8.0.0",
- "postcss-normalize-timing-functions": "^8.0.0",
- "postcss-normalize-unicode": "^8.0.0",
- "postcss-normalize-url": "^8.0.0",
- "postcss-normalize-whitespace": "^8.0.0",
- "postcss-ordered-values": "^8.0.0",
- "postcss-reduce-initial": "^8.0.0",
- "postcss-reduce-transforms": "^8.0.0",
- "postcss-svgo": "^8.0.0",
- "postcss-unique-selectors": "^8.0.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/cssnano-utils": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-6.0.0.tgz",
- "integrity": "sha512-ztS9W/+uaDn+bkYmDhs+GdMveHJ3CL8IPNHpRqDUQXv5GJOTQAJjV1XUOInr9esLXSabQV1pLRZlJpyUwEqDyQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/csso": {
- "version": "5.0.5",
- "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz",
- "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "css-tree": "~2.2.0"
- },
- "engines": {
- "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
- "npm": ">=7.0.0"
- }
- },
- "node_modules/csso/node_modules/css-tree": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
- "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "mdn-data": "2.0.28",
- "source-map-js": "^1.0.1"
- },
- "engines": {
- "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
- "npm": ">=7.0.0"
- }
- },
- "node_modules/csso/node_modules/mdn-data": {
- "version": "2.0.28",
- "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz",
- "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
- "dev": true,
- "license": "CC0-1.0"
- },
"node_modules/dependency-graph": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz",
@@ -815,65 +677,6 @@
"node": ">=8"
}
},
- "node_modules/dom-serializer": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
- "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.2",
- "entities": "^4.2.0"
- },
- "funding": {
- "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
- }
- },
- "node_modules/domelementtype": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
- "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/fb55"
- }
- ],
- "license": "BSD-2-Clause"
- },
- "node_modules/domhandler": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
- "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "domelementtype": "^2.3.0"
- },
- "engines": {
- "node": ">= 4"
- },
- "funding": {
- "url": "https://github.com/fb55/domhandler?sponsor=1"
- }
- },
- "node_modules/domutils": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
- "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "dom-serializer": "^2.0.0",
- "domelementtype": "^2.3.0",
- "domhandler": "^5.0.3"
- },
- "funding": {
- "url": "https://github.com/fb55/domutils?sponsor=1"
- }
- },
"node_modules/electron-to-chromium": {
"version": "1.5.351",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.351.tgz",
@@ -901,19 +704,6 @@
"node": ">=10.13.0"
}
},
- "node_modules/entities": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
- "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=0.12"
- },
- "funding": {
- "url": "https://github.com/fb55/entities?sponsor=1"
- }
- },
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -1362,20 +1152,6 @@
"url": "https://github.com/sponsors/antonk52"
}
},
- "node_modules/lodash.memoize": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
- "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.uniq": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
- "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -1385,13 +1161,6 @@
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
- "node_modules/mdn-data": {
- "version": "2.27.1",
- "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz",
- "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==",
- "dev": true,
- "license": "CC0-1.0"
- },
"node_modules/nanoid": {
"version": "3.3.12",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
@@ -1427,19 +1196,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/nth-check": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
- "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
- "dev": true,
- "license": "BSD-2-Clause",
- "dependencies": {
- "boolbase": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/fb55/nth-check?sponsor=1"
- }
- },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -1497,37 +1253,6 @@
"node": "^10 || ^12 || >=14"
}
},
- "node_modules/postcss-calc": {
- "version": "10.1.1",
- "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz",
- "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-selector-parser": "^7.0.0",
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^18.12 || ^20.9 || >=22.0"
- },
- "peerDependencies": {
- "postcss": "^8.4.38"
- }
- },
- "node_modules/postcss-calc/node_modules/postcss-selector-parser": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
- "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/postcss-cli": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.1.tgz",
@@ -1557,111 +1282,6 @@
"postcss": "^8.0.0"
}
},
- "node_modules/postcss-colormin": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-8.0.0.tgz",
- "integrity": "sha512-KKwMmsSgsmdYXqrjQeqL3tnuIFtctiR1GEMHdjNpDpz/TCRkkkok2mMcreK2zVV3l7POWOmAkR2xYHUpRUK1DA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@colordx/core": "^5.4.3",
- "browserslist": "^4.28.2",
- "caniuse-api": "^3.0.0",
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-convert-values": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-8.0.0.tgz",
- "integrity": "sha512-Ohtj3rNZWawTRePv5NCHTy8VJSdJ/G/uKuxcxJreOMichuqcT6uEl2TAnopVeJCJ/c13jaSqg7m63yFLM5zBsA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "browserslist": "^4.28.2",
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-discard-comments": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-8.0.0.tgz",
- "integrity": "sha512-zGpvVLj2sbagEp+BTVETvAfkZdGVA6rALNujDK/WTIjdf1/rQOxOG8BBzkI8UQgnw8SkL6xffAfbtGMHFypadw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-selector-parser": "^7.1.1"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-discard-comments/node_modules/postcss-selector-parser": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
- "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/postcss-discard-duplicates": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-8.0.0.tgz",
- "integrity": "sha512-zjRyYmNGI3PTipKBBtCgExlmZXQn49KvKoaiNnR2g+iXxeNk7GY5Js2ULtZXPrCYeqjPagrzKIBNcBocvXCR7g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-discard-empty": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-8.0.0.tgz",
- "integrity": "sha512-kxPJg6EqahbBvm+l7hpYYCtpsv8dlz7Tv6wJXUXZaeuY0WGS61DxfGdZR4uVB/Cx+yi3iOHQVSqpSHKMFaBg6Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-discard-overridden": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-8.0.0.tgz",
- "integrity": "sha512-sW2OWH3l9p0FmBSVr228uztFseqroZxwgD7SGF0Ks0dRPDttSo3P8FK5ZBLtWBH2A5+chpB0J2fB/T8heKHLBw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
"node_modules/postcss-load-config": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.1.0.tgz",
@@ -1702,333 +1322,6 @@
}
}
},
- "node_modules/postcss-merge-longhand": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-8.0.0.tgz",
- "integrity": "sha512-YDmAmQ8H+ljfomVpSXvr9NA0GP01fraQJqjWBYoMVGg6rOT+PJLwPyeVo2ekn4WB4ZVSH5ddtK3DTRxbz6CFzg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0",
- "stylehacks": "^8.0.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-merge-rules": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-8.0.0.tgz",
- "integrity": "sha512-bgstL5mpi41dDpnYGDUcI3M814NWkCMcIWpwDqEHXkHg3BT7b4XRAfNEuwJncZOVn/67kVKvWzhfv/7xyrp2uQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "browserslist": "^4.28.2",
- "caniuse-api": "^3.0.0",
- "cssnano-utils": "^6.0.0",
- "postcss-selector-parser": "^7.1.1"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
- "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/postcss-minify-font-values": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-8.0.0.tgz",
- "integrity": "sha512-EnOHQEnSt6oH5NrL1DMFAQuwB2IOimFXTCzc9bKfUeH1jREbqIF5MAK4gQJQOC4mPUwJt4sWifAmNZ1qLu6j3Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-minify-gradients": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-8.0.0.tgz",
- "integrity": "sha512-43iAnYIGk0ZjNx5X/rkIcHi6dhmu/vEjY0kqfUfxPuJRO+V7jx8uKIdcnL0dpfNoC5J9TSh3EtzLWbq0gpqnWA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@colordx/core": "^5.4.3",
- "cssnano-utils": "^6.0.0",
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-minify-params": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-8.0.0.tgz",
- "integrity": "sha512-z7w4QO7G55l4vMUK1Lmx03GW7iyRLgf2V5Dz/7ioSPLnXRjeD+b7m0XfAXUGrbBYYrJ6bXPk+3LoX5u4JfAcSg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "browserslist": "^4.28.2",
- "cssnano-utils": "^6.0.0",
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-minify-selectors": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-8.0.0.tgz",
- "integrity": "sha512-pQKzVGjUfOVP8QH95lXN/cpMcwHvdsqF3tQTEWPsRPnHw2SZ7G9c69oWDfjWkpCd81APF8E34QKUEUo+qUp5qw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "browserslist": "^4.28.1",
- "caniuse-api": "^3.0.0",
- "cssesc": "^3.0.0",
- "postcss-selector-parser": "^7.1.1"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
- "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/postcss-normalize-charset": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-8.0.0.tgz",
- "integrity": "sha512-s88FUNDSUD8m0wBYvTQQcubVts6zhXwBU8zCD4vkRKiecd0v8cOjHVIF9r/i+5xzS/WG3f98qq4XsOM0JqvfLA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-normalize-display-values": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-8.0.0.tgz",
- "integrity": "sha512-gG2nBxD27fiw6Luinb1QYKdM/Co5GornRJgSD+JTwNH4PGKxImP0qyruDDav49aHUPLY3qrL3qN3LvybO7IzxQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-normalize-positions": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-8.0.0.tgz",
- "integrity": "sha512-t/wGqpehS20Ke7kc4QAsWpH+AJjUdMK/V5qV2RhrXkj8hO/fT1t1MJ8NL7sedWYk7ZqC7eISEJQonW5j0tU1MQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-normalize-repeat-style": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-8.0.0.tgz",
- "integrity": "sha512-3ebOmGdCYKrBYyGKc1xhj0unEnW7beZpVU7JohVeGl7mTxR+7T6egpaawTWAVsB0pEIhcsbJVOjPKCJSoRO6Zg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-normalize-string": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-8.0.0.tgz",
- "integrity": "sha512-TvWCGZ/e04Tv31uJvOUtbexkfgUnqmQ3M2P5DkAaVzvOj+BvTkG2QjpA5Y71SL1SPxJcj4M23fNh+RDVCmG8kA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-normalize-timing-functions": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-8.0.0.tgz",
- "integrity": "sha512-uEfaXst5Xgqxv7geYUuz6vs9mn88K2NPY2RoIzM3BMmSjsdTSeppV9x2qIgrxsisdbSqF6IVhzI2occcte3hTA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-normalize-unicode": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-8.0.0.tgz",
- "integrity": "sha512-+WYngZaChEeTHZmWhmKtnJ4gTzWdINEaFcgWBnu6WdVu8Ftim8OBTcw768DuCC/3Aax9bZ9WkwrLGHym2Lzf+A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "browserslist": "^4.28.2",
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-normalize-url": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-8.0.0.tgz",
- "integrity": "sha512-4Mz9hZHn/QIB+YtFqTXrDmE2193GYxGb3F8uMfLvMicaEXCCUlDIJ658gFFJbqEGl9FYzwPtRiuNgbwlO9kkBg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-normalize-whitespace": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-8.0.0.tgz",
- "integrity": "sha512-V1f8tYnwIP5tscOXQFTKK8Y5EJ+R2GMpFJ6FjzwoKoQnhbqQy3IeSrDjJJb8JjVos8ut6Osi80Zybpayv/XjIQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-ordered-values": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-8.0.0.tgz",
- "integrity": "sha512-Dg9+itb6lmD0bxqhQyHCtXAwYRh0wUrx6Mp4/BNXgkLoJmdYMmWi+V+Pypw79Q6iQhxA8KFMHqLBITQJV2gKMA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cssnano-utils": "^6.0.0",
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-reduce-initial": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-8.0.0.tgz",
- "integrity": "sha512-DChcE9d528AKrlpCTHjhsAiOsWCk4H9ApHPS1QqRT3praObWTiWyn6W1UddGpc46K9LQnHwUu4YwaPUukGtXVA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "browserslist": "^4.28.2",
- "caniuse-api": "^3.0.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-reduce-transforms": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-8.0.0.tgz",
- "integrity": "sha512-cLZT0som7vvumQT9XQCnSKOSnRinNQZd1Hm+J723Ney13E8CIydDhw6JwzsjPtgnYThTqn9Q45906gz6wxaAsw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
"node_modules/postcss-reporter": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.1.0.tgz",
@@ -2070,53 +1363,6 @@
"node": ">=4"
}
},
- "node_modules/postcss-svgo": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-8.0.0.tgz",
- "integrity": "sha512-Q2fMSYEiNE1ioDc/3sxvI24NdgA/MJno2XLNpOxgv8aCcJbym8mZY10/lDY5+AWCIc3Aiqzy2Wcp9/zaIXBZgQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-value-parser": "^4.2.0",
- "svgo": "^4.0.1"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-unique-selectors": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-8.0.0.tgz",
- "integrity": "sha512-iObuolUX+ITJfMU2QQFQdh31JgSjNLPNjVs6YGAqBHvOvAWXMMNget6donQl83aQaeS32i5XeKZURUW/WBxIUw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "postcss-selector-parser": "^7.1.1"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/postcss-unique-selectors/node_modules/postcss-selector-parser": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
- "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/postcss-value-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
@@ -2167,16 +1413,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/sax": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz",
- "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==",
- "dev": true,
- "license": "BlueOak-1.0.0",
- "engines": {
- "node": ">=11.0.0"
- }
- },
"node_modules/slash": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
@@ -2227,63 +1463,6 @@
"node": ">=8"
}
},
- "node_modules/stylehacks": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-8.0.0.tgz",
- "integrity": "sha512-sWyjaJvBqHoVKYPbQ8JRvrGSPaYWtWrJsU+fGVtwKB1GE1rRPu3rC7T6UCuXLoL00Dwb+tsHe2T904r8Vnsx8w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "browserslist": "^4.28.2",
- "postcss-selector-parser": "^7.1.1"
- },
- "engines": {
- "node": "^22.11.0 || ^24.11.0 || >=26.0"
- },
- "peerDependencies": {
- "postcss": "^8.5.14"
- }
- },
- "node_modules/stylehacks/node_modules/postcss-selector-parser": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz",
- "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cssesc": "^3.0.0",
- "util-deprecate": "^1.0.2"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/svgo": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz",
- "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "commander": "^11.1.0",
- "css-select": "^5.1.0",
- "css-tree": "^3.0.1",
- "css-what": "^6.1.0",
- "csso": "^5.0.5",
- "picocolors": "^1.1.1",
- "sax": "^1.5.0"
- },
- "bin": {
- "svgo": "bin/svgo.js"
- },
- "engines": {
- "node": ">=16"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/svgo"
- }
- },
"node_modules/tailwindcss": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.4.tgz",
diff --git a/tools/tailwind/package.json b/tools/tailwind/package.json
index 4a2bd84f..08036cb7 100644
--- a/tools/tailwind/package.json
+++ b/tools/tailwind/package.json
@@ -4,14 +4,12 @@
"author": "Haskell Foundation",
"private": true,
"scripts": {
- "build": "cd ../.. && postcss build assets/css/tailwind.css -o _site/assets/css/tailwind.css --config tools/tailwind",
- "build:production": "cd ../.. && NODE_ENV=production postcss build assets/css/tailwind.css -o _site/assets/css/tailwind.css --config tools/tailwind",
- "build:dev-snapshot": "cd ../.. && postcss build assets/css/tailwind.css -o dev.css --config tools/tailwind"
+ "build": "cd ../.. && postcss build assets/css/tailwind.css -o assets/css/tailwind.built.css --config tools/tailwind",
+ "watch": "cd ../.. && postcss build assets/css/tailwind.css -o assets/css/tailwind.built.css --config tools/tailwind --watch"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.19",
"autoprefixer": "^10.5.0",
- "cssnano": "^8.0.0",
"postcss": "^8.5.14",
"postcss-cli": "^11.0.1",
"tailwindcss": "4.2.4"
diff --git a/tools/tailwind/postcss.config.js b/tools/tailwind/postcss.config.js
index 3ba613ea..d369a8e8 100644
--- a/tools/tailwind/postcss.config.js
+++ b/tools/tailwind/postcss.config.js
@@ -9,9 +9,8 @@ module.exports = {
'@tailwindcss/postcss': {},
// handles browser compatibility
'autoprefixer': {},
- ...(process.env.NODE_ENV === "production" ? {
- // Minify via cssnano, but only if NODE_ENV is set to production
- cssnano: {},
- }: {})
+ // No minifier: the output is checked in as assets/css/tailwind.built.css and
+ // shipped as-is, and a readable diff is worth more than the ~800 gzipped
+ // bytes cssnano saved.
}
}