Initial version

This commit is contained in:
Stefan Bethke 2024-06-13 22:14:05 +02:00
commit ed5653a7fc
211 changed files with 11043 additions and 0 deletions

View file

@ -0,0 +1,49 @@
/**
* @file
* A JavaScript file for the contact form.
*/
(function () {
'use strict';
const form = document.querySelector('.contact-form');
const button = form.querySelector('[type=submit]');
const action = form.getAttribute('data-protect');
const activateForm = function () {
form.setAttribute('action', action);
button.removeAttribute('disabled');
};
// Display the hidden form.
form.classList.remove('hidden');
// Wait for a mouse to move, indicating they are human.
document.body.addEventListener('mousemove', activateForm, {once: true});
// Wait for a touch move event, indicating that they are human.
document.body.addEventListener('touchmove', activateForm, {once: true});
// A tab or enter key pressed can also indicate they are human.
document.body.addEventListener('keydown', function (e) {
if ((e.key === 'Tab') || (e.key === 'Enter')) {
activateForm();
}
}, {once: true});
// Mark the form as submitted.
button.addEventListener('click', () => form.classList.add('js-submitted'));
// Display messages.
if (location.search.substring(1) !== '') {
switch (location.search.substring(1)) {
case 'submitted':
document.querySelector('.contact-submitted').classList.remove('hidden');
break;
case 'error':
document.querySelector('.contact-error').classList.remove('hidden');
break;
}
}
})();

View file

@ -0,0 +1,44 @@
/**
* @file
* A JavaScript file for cookie consent.
*/
(function () {
'use strict';
const cookiebanner = document.querySelector('.cookieconsent');
const cookieconsent = localStorage.getItem('cookieconsent');
if (cookiebanner && !cookieconsent) {
cookiebanner.classList.remove('hidden');
cookiebanner.classList.add('js-cookieconsent-open');
}
const cookie_buttons = document.querySelectorAll('button[data-consent]');
cookie_buttons.forEach(function (button) {
button.addEventListener('click', function () {
if (button.getAttribute('data-consent') === 'true') {
localStorage.setItem('cookieconsent', 'accept');
}
else {
localStorage.setItem('cookieconsent', 'decline');
}
cookiebanner.classList.remove('js-cookieconsent-open');
cookiebanner.classList.add('hidden');
});
});
const clear_buttons = document.querySelectorAll('.clearcookieconsent');
clear_buttons.forEach(function (button) {
button.addEventListener('click', function (e) {
e.preventDefault();
if (cookiebanner && cookieconsent) {
localStorage.removeItem('cookieconsent');
cookiebanner.classList.remove('hidden');
cookiebanner.classList.add('js-cookieconsent-open');
}
});
});
})();

View file

@ -0,0 +1,21 @@
/**
* @file
* A JavaScript file for Katex auto renderer.
*/
(function () {
'use strict';
document.addEventListener('DOMContentLoaded', function () {
// eslint-disable-next-line no-undef
renderMathInElement(document.body, {
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false}
],
throwOnError: false
});
});
})();

View file

@ -0,0 +1,52 @@
/**
* @file
* A JavaScript file for the mobile menu.
*/
(function () {
'use strict';
const nav = document.querySelector('.mobile-nav');
const sheet = document.querySelector('.mobile-nav__sheet');
const toggle = document.querySelector('.mobile-nav__toggle');
function navopen() {
nav.classList.add('js-nav-open');
sheet.setAttribute('aria-hidden', 'false');
toggle.setAttribute('aria-expanded', 'true');
}
function navclose() {
nav.classList.remove('js-nav-open');
sheet.setAttribute('aria-hidden', 'true');
toggle.setAttribute('aria-expanded', 'false');
}
// Toggle the mobile nav sheet.
const toggles = document.querySelectorAll('.mobile-nav__cover, .mobile-nav__toggle');
toggles.forEach(function (toggle) {
toggle.addEventListener('click', function (e) {
e.preventDefault();
if (nav.classList.contains('js-nav-open')) {
navclose();
}
else {
navopen();
}
});
});
// Close the nav sheet after click (needed for anchor links).
const links = document.querySelectorAll('.mobile-nav__sheet a');
links.forEach(function (link) {
link.addEventListener('click', function (e) {
navclose();
});
});
// Move focus back to button efter user tab out of last link.
const lastlink = [].slice.call(links).pop();
lastlink.addEventListener('blur', () => toggle.focus());
})();

View file

@ -0,0 +1,13 @@
/**
* @file
* A JavaScript file for the theme. Runs first, before other things have loaded.
*/
(function () {
'use strict';
// Add a js class to the html-tag when JavsScript is active.
document.querySelector('html').classList.replace('nojs', 'js');
})();

View file

@ -0,0 +1,12 @@
/**
* @file
* A JavaScript file for the theme.
*/
(function () {
'use strict';
// Place your code here.
})();

View file

@ -0,0 +1,92 @@
/**
* @file
* A JavaScript file for flexsearch.
*/
/* eslint-disable */
import * as params from '@params';
/* eslint-enable */
/* eslint-disable no-undef, guard-for-in */
(function () {
'use strict';
const index = new FlexSearch.Document({
document: {
id: 'id',
index: ['title', 'tags', 'content', 'date'],
store: ['title', 'summary', 'date', 'permalink']
},
tokenize: 'forward'
});
function showResults(items) {
const template = document.querySelector('template').content;
const fragment = document.createDocumentFragment();
const results = document.querySelector('.search-results');
results.textContent = '';
for (const id in items) {
const item = items[id];
const result = template.cloneNode(true);
const a = result.querySelector('a');
const time = result.querySelector('time');
const content = result.querySelector('.content');
a.innerHTML = item.title;
a.href = item.permalink;
time.innerText = item.date;
content.innerHTML = item.summary;
fragment.appendChild(result);
}
results.appendChild(fragment);
}
function doSearch() {
const query = document.querySelector('.search-text').value.trim();
const results = index.search({
query: query,
enrich: true,
limit: params.searchLimit
});
const items = {};
results.forEach(function (result) {
result.result.forEach(function (r) {
items[r.id] = r.doc;
});
});
showResults(items);
}
function enableUI() {
const searchform = document.querySelector('.search-form');
searchform.addEventListener('submit', function (e) {
e.preventDefault();
doSearch();
});
searchform.addEventListener('input', function () {
doSearch();
});
document.querySelector('.search-loading').classList.add('hidden');
document.querySelector('.search-input').classList.remove('hidden');
document.querySelector('.search-text').focus();
}
function buildIndex() {
const searchindex = params.basePath + 'searchindex.json';
document.querySelector('.search-loading').classList.remove('hidden');
fetch(searchindex)
.then(function (response) {
return response.json();
})
.then(function (data) {
data.forEach(function (item) {
index.add(item);
});
});
}
buildIndex();
enableUI();
})();

View file

@ -0,0 +1,29 @@
/**
* @file
* A JavaScript file for responsive tables.
*/
/* eslint-disable max-nested-callbacks */
(function () {
'use strict';
const tables = document.querySelectorAll('.responsive-table');
tables.forEach(function (table) {
const headers = table.querySelectorAll('th');
const rows = table.querySelectorAll('tbody tr');
rows.forEach(function (row) {
const cells = row.querySelectorAll('td');
cells.forEach(function (cell, i) {
cell.setAttribute('role','cell');
if (headers[i].innerText) {
cell.setAttribute('aria-label', headers[i].innerText);
}
});
});
});
})();

View file

@ -0,0 +1,34 @@
/**
* @file
* A JavaScript file for analytic tracking.
*/
/* eslint-disable */
import * as params from '@params';
/* eslint-enable */
/* eslint-disable no-undef */
const cookiebanner = params.cookieConsent;
const cookieconsent = localStorage.getItem('cookieconsent');
const idSite = params.piwikSiteID;
const matomoTrackingApiUrl = 'https://' + params.piwikTrackerUrl + '/matomo.php';
const googleAnalytics = params.GoogleAnalytics;
if (idSite) {
let _paq = window._paq = window._paq || [];
if (cookiebanner) {
_paq.push(['requireConsent']);
}
_paq.push(['setTrackerUrl', matomoTrackingApiUrl]);
_paq.push(['setSiteId', idSite]);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
if (cookiebanner && cookieconsent === 'accept') {
_paq.push(['setConsentGiven']);
}
}
if (googleAnalytics && cookiebanner && cookieconsent === 'decline') {
window['ga-disable-' + googleAnalytics] = true;
}

6
themes/zen/assets/libs/alpine.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,27 @@
/**!
* FlexSearch.js v0.7.31 (Compact)
* Copyright 2018-2022 Nextapps GmbH
* Author: Thomas Wilkerling
* Licence: Apache-2.0
* https://github.com/nextapps-de/flexsearch
*/
(function(self){'use strict';var t;function v(a){return"undefined"!==typeof a?a:!0}function w(a){const b=Array(a);for(let c=0;c<a;c++)b[c]=y();return b}function y(){return Object.create(null)}function aa(a,b){return b.length-a.length}function C(a){return"string"===typeof a}function D(a){return"object"===typeof a};function E(a,b){var c=ba;if(a&&(b&&(a=F(a,b)),this.G&&(a=F(a,this.G)),this.H&&1<a.length&&(a=F(a,this.H)),c||""===c)){a=a.split(c);if(this.filter){b=this.filter;c=a.length;const e=[];for(let d=0,f=0;d<c;d++){const g=a[d];g&&!b[g]&&(e[f++]=g)}a=e}return a}return a}const ba=/[\p{Z}\p{S}\p{P}\p{C}]+/u,ca=/[\u0300-\u036f]/g;
function H(a,b){const c=Object.keys(a),e=c.length,d=[];let f="",g=0;for(let h=0,k,m;h<e;h++)k=c[h],(m=a[k])?(d[g++]=I(b?"(?!\\b)"+k+"(\\b|_)":k),d[g++]=m):f+=(f?"|":"")+k;f&&(d[g++]=I(b?"(?!\\b)("+f+")(\\b|_)":"("+f+")"),d[g]="");return d}function F(a,b){for(let c=0,e=b.length;c<e&&(a=a.replace(b[c],b[c+1]),a);c+=2);return a}function I(a){return new RegExp(a,"g")}function J(a){let b="",c="";for(let e=0,d=a.length,f;e<d;e++)(f=a[e])!==c&&(b+=c=f);return b};var da={encode:K,B:!1,C:""};function K(a){return E.call(this,(""+a).toLowerCase(),!1)};const ea={},L={};function fa(a){M(a,"add");M(a,"append");M(a,"search");M(a,"update");M(a,"remove")}function M(a,b){a[b+"Async"]=function(){const c=this,e=arguments;var d=e[e.length-1];let f;"function"===typeof d&&(f=d,delete e[e.length-1]);d=new Promise(function(g){setTimeout(function(){c.async=!0;const h=c[b].apply(c,e);c.async=!1;g(h)})});return f?(d.then(f),this):d}};function ha(a,b,c,e){const d=a.length;let f=[],g,h,k=0;e&&(e=[]);for(let m=d-1;0<=m;m--){const n=a[m],u=n.length,q=y();let r=!g;for(let l=0;l<u;l++){const p=n[l],z=p.length;if(z)for(let B=0,A,x;B<z;B++)if(x=p[B],g){if(g[x]){if(!m)if(c)c--;else if(f[k++]=x,k===b)return f;if(m||e)q[x]=1;r=!0}if(e&&(A=(h[x]||0)+1,h[x]=A,A<d)){const G=e[A-2]||(e[A-2]=[]);G[G.length]=x}}else q[x]=1}if(e)g||(h=q);else if(!r)return[];g=q}if(e)for(let m=e.length-1,n,u;0<=m;m--){n=e[m];u=n.length;for(let q=0,r;q<u;q++)if(r=
n[q],!g[r]){if(c)c--;else if(f[k++]=r,k===b)return f;g[r]=1}}return f}function ja(a,b){const c=y(),e=y(),d=[];for(let f=0;f<a.length;f++)c[a[f]]=1;for(let f=0,g;f<b.length;f++){g=b[f];for(let h=0,k;h<g.length;h++)k=g[h],c[k]&&!e[k]&&(e[k]=1,d[d.length]=k)}return d};const ka={memory:{charset:"latin:extra",A:3,m:4,D:!1},performance:{A:3,m:3,s:!1,context:{depth:2,A:1}},match:{charset:"latin:extra",C:"reverse"},score:{charset:"latin:advanced",A:20,m:3,context:{depth:3,A:9}},"default":{}};function O(a,b){if(!(this instanceof O))return new O(a);var c;let e;a?(C(a)?a=ka[a]:(c=a.preset)&&(a=Object.assign({},c[c],a)),c=a.charset,e=a.lang,C(c)&&(-1===c.indexOf(":")&&(c+=":default"),c=L[c]),C(e)&&(e=ea[e])):a={};let d,f,g=a.context||{};this.encode=a.encode||c&&c.encode||K;this.register=b||y();this.A=d=a.resolution||9;this.C=b=c&&c.C||a.tokenize||"strict";this.depth="strict"===b&&g.depth;this.h=v(g.bidirectional);this.s=f=v(a.optimize);this.D=v(a.fastupdate);this.m=a.minlength||1;this.F=
a.boost;this.map=f?w(d):y();this.o=d=g.resolution||1;this.l=f?w(d):y();this.B=c&&c.B||a.rtl;this.G=(b=a.matcher||e&&e.G)&&H(b,!1);this.H=(b=a.stemmer||e&&e.H)&&H(b,!0);if(a=b=a.filter||e&&e.filter){a=b;c=y();for(let h=0,k=a.length;h<k;h++)c[a[h]]=1;a=c}this.filter=a}t=O.prototype;t.append=function(a,b){return this.add(a,b,!0)};
t.add=function(a,b,c,e){if(b&&(a||0===a)){if(!e&&!c&&this.register[a])return this.update(a,b);b=this.encode(b);if(e=b.length){const m=y(),n=y(),u=this.depth,q=this.A;for(let r=0;r<e;r++){let l=b[this.B?e-1-r:r];var d=l.length;if(l&&d>=this.m&&(u||!n[l])){var f=P(q,e,r),g="";switch(this.C){case "full":if(2<d){for(f=0;f<d;f++)for(var h=d;h>f;h--)if(h-f>=this.m){var k=P(q,e,r,d,f);g=l.substring(f,h);Q(this,n,g,k,a,c)}break}case "reverse":if(1<d){for(h=d-1;0<h;h--)g=l[h]+g,g.length>=this.m&&Q(this,n,
g,P(q,e,r,d,h),a,c);g=""}case "forward":if(1<d){for(h=0;h<d;h++)g+=l[h],g.length>=this.m&&Q(this,n,g,f,a,c);break}default:if(this.F&&(f=Math.min(f/this.F(b,l,r)|0,q-1)),Q(this,n,l,f,a,c),u&&1<e&&r<e-1)for(d=y(),g=this.o,f=l,h=Math.min(u+1,e-r),d[f]=1,k=1;k<h;k++)if((l=b[this.B?e-1-r-k:r+k])&&l.length>=this.m&&!d[l]){d[l]=1;const p=this.h&&l>f;Q(this,m,p?f:l,P(g+(e/2>g?0:1),e,r,h-1,k-1),a,c,p?l:f)}}}}this.D||(this.register[a]=1)}}return this};
function P(a,b,c,e,d){return c&&1<a?b+(e||0)<=a?c+(d||0):(a-1)/(b+(e||0))*(c+(d||0))+1|0:0}function Q(a,b,c,e,d,f,g){let h=g?a.l:a.map;if(!b[c]||g&&!b[c][g])a.s&&(h=h[e]),g?(b=b[c]||(b[c]=y()),b[g]=1,h=h[g]||(h[g]=y())):b[c]=1,h=h[c]||(h[c]=[]),a.s||(h=h[e]||(h[e]=[])),f&&h.includes(d)||(h[h.length]=d,a.D&&(a=a.register[d]||(a.register[d]=[]),a[a.length]=h))}
t.search=function(a,b,c){c||(!b&&D(a)?(c=a,a=c.query):D(b)&&(c=b));let e=[],d;let f,g=0;if(c){a=c.query||a;b=c.limit;g=c.offset||0;var h=c.context;f=c.suggest}if(a&&(a=this.encode(""+a),d=a.length,1<d)){c=y();var k=[];for(let n=0,u=0,q;n<d;n++)if((q=a[n])&&q.length>=this.m&&!c[q])if(this.s||f||this.map[q])k[u++]=q,c[q]=1;else return e;a=k;d=a.length}if(!d)return e;b||(b=100);h=this.depth&&1<d&&!1!==h;c=0;let m;h?(m=a[0],c=1):1<d&&a.sort(aa);for(let n,u;c<d;c++){u=a[c];h?(n=la(this,e,f,b,g,2===d,u,
m),f&&!1===n&&e.length||(m=u)):n=la(this,e,f,b,g,1===d,u);if(n)return n;if(f&&c===d-1){k=e.length;if(!k){if(h){h=0;c=-1;continue}return e}if(1===k)return ma(e[0],b,g)}}return ha(e,b,g,f)};
function la(a,b,c,e,d,f,g,h){let k=[],m=h?a.l:a.map;a.s||(m=na(m,g,h,a.h));if(m){let n=0;const u=Math.min(m.length,h?a.o:a.A);for(let q=0,r=0,l,p;q<u;q++)if(l=m[q])if(a.s&&(l=na(l,g,h,a.h)),d&&l&&f&&(p=l.length,p<=d?(d-=p,l=null):(l=l.slice(d),d=0)),l&&(k[n++]=l,f&&(r+=l.length,r>=e)))break;if(n){if(f)return ma(k,e,0);b[b.length]=k;return}}return!c&&k}function ma(a,b,c){a=1===a.length?a[0]:[].concat.apply([],a);return c||a.length>b?a.slice(c,c+b):a}
function na(a,b,c,e){c?(e=e&&b>c,a=(a=a[e?b:c])&&a[e?c:b]):a=a[b];return a}t.contain=function(a){return!!this.register[a]};t.update=function(a,b){return this.remove(a).add(a,b)};t.remove=function(a,b){const c=this.register[a];if(c){if(this.D)for(let e=0,d;e<c.length;e++)d=c[e],d.splice(d.indexOf(a),1);else R(this.map,a,this.A,this.s),this.depth&&R(this.l,a,this.o,this.s);b||delete this.register[a]}return this};
function R(a,b,c,e,d){let f=0;if(a.constructor===Array)if(d)b=a.indexOf(b),-1!==b?1<a.length&&(a.splice(b,1),f++):f++;else{d=Math.min(a.length,c);for(let g=0,h;g<d;g++)if(h=a[g])f=R(h,b,c,e,d),e||f||delete a[g]}else for(let g in a)(f=R(a[g],b,c,e,d))||delete a[g];return f}fa(O.prototype);function T(a){if(!(this instanceof T))return new T(a);var b=a.document||a.doc||a,c;this.F=[];this.h=[];this.o=[];this.register=y();this.key=(c=b.key||b.id)&&U(c,this.o)||"id";this.D=v(a.fastupdate);this.l=(c=b.store)&&!0!==c&&[];this.store=c&&y();this.async=!1;c=y();let e=b.index||b.field||b;C(e)&&(e=[e]);for(let d=0,f,g;d<e.length;d++)f=e[d],C(f)||(g=f,f=f.field),g=D(g)?Object.assign({},a,g):a,this.I||(c[f]=new O(g,this.register)),this.F[d]=U(f,this.o),this.h[d]=f;if(this.l)for(a=b.store,C(a)&&(a=
[a]),b=0;b<a.length;b++)this.l[b]=U(a[b],this.o);this.index=c}function U(a,b){const c=a.split(":");let e=0;for(let d=0;d<c.length;d++)a=c[d],0<=a.indexOf("[]")&&(a=a.substring(0,a.length-2))&&(b[e]=!0),a&&(c[e++]=a);e<c.length&&(c.length=e);return 1<e?c:c[0]}function oa(a,b){if(C(b))a=a[b];else for(let c=0;a&&c<b.length;c++)a=a[b[c]];return a}
function V(a,b,c,e,d){a=a[d];if(e===c.length-1)b[d]=a;else if(a)if(a.constructor===Array)for(b=b[d]=Array(a.length),d=0;d<a.length;d++)V(a,b,c,e,d);else b=b[d]||(b[d]=y()),d=c[++e],V(a,b,c,e,d)}function W(a,b,c,e,d,f,g,h){if(a=a[g])if(e===b.length-1){if(a.constructor===Array){if(c[e]){for(b=0;b<a.length;b++)d.add(f,a[b],!0,!0);return}a=a.join(" ")}d.add(f,a,h,!0)}else if(a.constructor===Array)for(g=0;g<a.length;g++)W(a,b,c,e,d,f,g,h);else g=b[++e],W(a,b,c,e,d,f,g,h)}t=T.prototype;
t.add=function(a,b,c){D(a)&&(b=a,a=oa(b,this.key));if(b&&(a||0===a)){if(!c&&this.register[a])return this.update(a,b);for(let e=0,d,f;e<this.h.length;e++)f=this.h[e],d=this.F[e],C(d)&&(d=[d]),W(b,d,this.o,0,this.index[f],a,d[0],c);if(this.store&&(!c||!this.store[a])){let e;if(this.l){e=y();for(let d=0,f;d<this.l.length;d++)f=this.l[d],C(f)?e[f]=b[f]:V(b,e,f,0,f[0])}this.store[a]=e||b}}return this};t.append=function(a,b){return this.add(a,b,!0)};t.update=function(a,b){return this.remove(a).add(a,b)};
t.remove=function(a){D(a)&&(a=oa(a,this.key));if(this.register[a]){for(let b=0;b<this.h.length&&(this.index[this.h[b]].remove(a,!this.I),!this.D);b++);this.store&&delete this.store[a];delete this.register[a]}return this};
t.search=function(a,b,c,e){c||(!b&&D(a)?(c=a,a=""):D(b)&&(c=b,b=0));let d=[],f=[],g,h,k,m,n,u,q=0;if(c)if(c.constructor===Array)k=c,c=null;else{a=c.query||a;k=(g=c.pluck)||c.index||c.field;m=!1;h=this.store&&c.enrich;n="and"===c.bool;b=c.limit||b||100;u=c.offset||0;if(m&&(C(m)&&(m=[m]),!a)){for(let l=0,p;l<m.length;l++)if(p=pa.call(this,m[l],b,u,h))d[d.length]=p,q++;return q?d:[]}C(k)&&(k=[k])}k||(k=this.h);n=n&&(1<k.length||m&&1<m.length);const r=!e&&(this.I||this.async)&&[];for(let l=0,p,z,B;l<
k.length;l++){let A;z=k[l];C(z)||(A=z,z=A.field,a=A.query||a,b=A.limit||b);if(r)r[l]=this.index[z].searchAsync(a,b,A||c);else{e?p=e[l]:p=this.index[z].search(a,b,A||c);B=p&&p.length;if(m&&B){const x=[];let G=0;n&&(x[0]=[p]);for(let S=0,ia,N;S<m.length;S++)if(ia=m[S],B=(N=this.J[ia])&&N.length)G++,x[x.length]=n?[N]:N;G&&(p=n?ha(x,b||100,u||0):ja(p,x),B=p.length)}if(B)f[q]=z,d[q++]=p;else if(n)return[]}}if(r){const l=this;return new Promise(function(p){Promise.all(r).then(function(z){p(l.search(a,b,
c,z))})})}if(!q)return[];if(g&&(!h||!this.store))return d[0];for(let l=0,p;l<f.length;l++){p=d[l];p.length&&h&&(p=qa.call(this,p));if(g)return p;d[l]={field:f[l],result:p}}return d};function pa(a,b,c,e){let d=this.J[a],f=d&&d.length-c;if(f&&0<f){if(f>b||c)d=d.slice(c,c+b);e&&(d=qa.call(this,d));return{tag:a,result:d}}}function qa(a){const b=Array(a.length);for(let c=0,e;c<a.length;c++)e=a[c],b[c]={id:e,doc:this.store[e]};return b}t.contain=function(a){return!!this.register[a]};t.get=function(a){return this.store[a]};
t.set=function(a,b){this.store[a]=b;return this};fa(T.prototype);var sa={encode:ra,B:!1,C:""};const ta=[I("[\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5]"),"a",I("[\u00e8\u00e9\u00ea\u00eb]"),"e",I("[\u00ec\u00ed\u00ee\u00ef]"),"i",I("[\u00f2\u00f3\u00f4\u00f5\u00f6\u0151]"),"o",I("[\u00f9\u00fa\u00fb\u00fc\u0171]"),"u",I("[\u00fd\u0177\u00ff]"),"y",I("\u00f1"),"n",I("[\u00e7c]"),"k",I("\u00df"),"s",I(" & ")," and "];function ra(a){var b=a=""+a;b.normalize&&(b=b.normalize("NFD").replace(ca,""));return E.call(this,b.toLowerCase(),!a.normalize&&ta)};var va={encode:ua,B:!1,C:"strict"};const wa=/[^a-z0-9]+/,xa={b:"p",v:"f",w:"f",z:"s",x:"s","\u00df":"s",d:"t",n:"m",c:"k",g:"k",j:"k",q:"k",i:"e",y:"e",u:"o"};function ua(a){a=ra.call(this,a).join(" ");const b=[];if(a){const c=a.split(wa),e=c.length;for(let d=0,f,g=0;d<e;d++)if((a=c[d])&&(!this.filter||!this.filter[a])){f=a[0];let h=xa[f]||f,k=h;for(let m=1;m<a.length;m++){f=a[m];const n=xa[f]||f;n&&n!==k&&(h+=n,k=n)}b[g++]=h}}return b};var za={encode:ya,B:!1,C:""};const Aa=[I("ae"),"a",I("oe"),"o",I("sh"),"s",I("th"),"t",I("ph"),"f",I("pf"),"f",I("(?![aeo])h(?![aeo])"),"",I("(?!^[aeo])h(?!^[aeo])"),""];function ya(a,b){a&&(a=ua.call(this,a).join(" "),2<a.length&&(a=F(a,Aa)),b||(1<a.length&&(a=J(a)),a&&(a=a.split(" "))));return a||[]};var Ca={encode:Ba,B:!1,C:""};const Da=I("(?!\\b)[aeo]");function Ba(a){a&&(a=ya.call(this,a,!0),1<a.length&&(a=a.replace(Da,"")),1<a.length&&(a=J(a)),a&&(a=a.split(" ")));return a||[]};L["latin:default"]=da;L["latin:simple"]=sa;L["latin:balance"]=va;L["latin:advanced"]=za;L["latin:extra"]=Ca;const X=self;let Y;const Z={Index:O,Document:T,Worker:null,registerCharset:function(a,b){L[a]=b},registerLanguage:function(a,b){ea[a]=b}};(Y=X.define)&&Y.amd?Y([],function(){return Z}):X.exports?X.exports=Z:X.FlexSearch=Z;}(this));

2
themes/zen/assets/libs/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
themes/zen/assets/libs/list.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,94 @@
// stylelint-disable color-no-hex, color-named, value-list-max-empty-lines
// stylelint-disable scss/dollar-variable-colon-space-after, scss/dollar-variable-empty-line-before
// Base colors.
$black: #000;
$nearblack: lighten($black, 20%); // #333
$grey-dark: lighten($black, 40%); // #666
$grey: lighten($black, 60%); // #999
$grey-light: lighten($black, 80%); // #ccc
$grey-extra-light: lighten($black, 93.33%); // #eee
$nearwhite: lighten($black, 97%); // #f7f7f7
$white: #fff;
$blue: #0072b9;
$red: #c00;
$green: #43a808;
$yellow: #fd0;
$brand: $nearblack;
$brand-alt: $grey;
$brand-light: $grey-light;
$brand-dark: $grey-dark;
// Colour map.
$colors: (
brand: $brand,
brand-alt: $brand-alt,
brand-light: $brand-light,
brand-dark: $brand-dark,
text: $black,
text-bg: $white,
text-meta: $grey-dark,
link: $brand,
link-visited: $brand,
link-hover: $brand-alt,
link-active: $red,
link-inverted: $white,
link-visited-inverted: $white,
link-hover-inverted: $white,
link-active-inverted: $red,
border: $brand,
border-light: $brand-light,
border-dark: $brand-dark,
autocomplete: $black,
autocomplete-bg: $white,
autocomplete-select: $white,
autocomplete-select-bg: $blue,
body-bg: $white,
header-bg: $white,
footer-bg: $white,
backdrop: $grey-extra-light,
mobile-menu: $brand,
mobile-menu-cover: rgba($black, .2),
button: $brand,
button-hover: $brand-alt,
button-text: $white,
button-text-hover: $white,
button-disabled: $grey,
mark-highlight: $red,
mark-bg: $yellow,
menu-active: $black,
preview-bg: lighten($yellow, 43%),
row-header: transparent,
row-odd: $nearwhite,
row-even: transparent,
status: $green,
status-bg: lighten($green, 62%),
warning: $black,
warning-bg: lighten($yellow, 45%),
warning-border: $yellow,
error: $red,
error-bg: lighten($red, 57%),
watermark: $grey-extra-light,
headings: $nearblack,
code: $nearblack,
highlight: $brand-alt,
);

View file

@ -0,0 +1 @@
// Site custom styles. This file loads last.

View file

@ -0,0 +1 @@
// Add and override variables. This file loads last during init.

View file

@ -0,0 +1,27 @@
// Font faces
//
// Instead of relying on the fonts that are available on a user's computer, you
// can use web fonts which, like images, are resources downloaded to the user's
// browser. Because of the bandwidth and rendering resources required, web fonts
// should be used with care.
//
// Numerous resources for web fonts can be found on the web. Here are a few
// websites where you can find Open Source fonts to download:
// - https://www.fontsquirrel.com/
// - https://www.theleagueofmoveabletype.com
// - https://fonts.google.com
//
// In order to use fonts on a web site you will need to convert them into woff2 format.
// Font Squirrel's Font-Face Generator is a good option:
// https://www.fontsquirrel.com/tools/webfont-generator
//
// The following is an example @font-face declaration. This font can then be
// used in any ruleset using a property like this: font-family: Example, serif;
//
// @font-face {
// font-family: 'Example';
// src: url('../fonts/example.woff2') format('woff2');
// font-weight: normal;
// font-style: normal;
// font-display: swap;
// }

View file

@ -0,0 +1,20 @@
// Initialization partial
// To make it easier to use all variables and mixins in any Sass file in this
// project, each .scss file has a `@import 'init';` declaration. The _init.scss
// file is in charge of importing all the other partials needed for the
// project.
// Colours and variables.
@import 'colors';
@import 'variables';
@import 'extra';
// Mixins and functions.
@import 'mixins/breakpoint/respond-to';
@import 'mixins/clearfix/clearfix';
@import 'mixins/debug/debug';
@import 'mixins/flex-calc/flex-calc';
@import 'mixins/image-url/image-url';
@import 'mixins/rtl/rtl';
@import 'mixins/spacing/spacing';

View file

@ -0,0 +1,114 @@
// stylelint-disable property-no-vendor-prefix
// Reset browsers to some sane defaults.
// Document
html {
// Prevent adjustments of font size.
-webkit-text-size-adjust: none;
text-size-adjust: none;
// On short pages, we want any background gradients to fill the entire height
// of the browser.
min-height: 100%;
// Use the saner border-box model.
box-sizing: border-box;
// Use smooth scrolling.
scroll-behavior: smooth;
// Improve text rendering.
-webkit-font-smoothing: antialiased;
}
// Use the saner border-box model for all elements.
*,
*::before,
*::after {
box-sizing: inherit;
}
// Sections
body {
// Remove the margin in all browsers.
margin: 0;
padding: 0;
}
// Embedded content
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
img,
svg {
height: auto;
}
figure {
margin-inline: 0;
}
// Form defaults.
input,
button,
textarea,
select {
font: inherit;
max-width: 100%;
}
label {
display: block;
font-weight: var(--fw-bold);
}
[type='search'] {
@include respond-to(s) {
// Correct the odd appearance in Safari on desktop.
-webkit-appearance: textfield;
}
}
// Text-level semantics
//
// The elements in this section give semantics to inline text.
// Code
code,
kbd,
samp {
font-family: var(--ff-monospace);
}
// Mark text
mark {
@extend %highlight-mark;
}
// Superscript / Subscript
sub,
sup {
// Prevent `sub` and `sup` elements from affecting the line height in
// all browsers.
font-size: var(--fs-xs);
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -.25em;
}
sup {
top: -.5em;
}

View file

@ -0,0 +1,35 @@
$breakout: $gutters !default;
$max-page-width: $max-content-width !default;
:root {
// Convert sass variables to css4 variables.
// Use like this: var(--color-brand).
@each $name, $color in $colors {
--color-#{$name}: #{$color};
}
@each $name, $size in $font-size {
--fs-#{$name}: #{$size};
}
@each $name, $weight in $font-weight {
--fw-#{$name}: #{$weight};
}
@each $name, $family in $font-family {
--ff-#{$name}: #{$family};
}
@each $name, $radius in $border-radius {
--radius-#{$name}: #{$radius};
}
--breakout: #{$breakout};
--gutters-reverse: #{$gutters-reverse};
--gutters: #{$gutters};
--heading-line-height: #{$heading-line-height};
--indent-amount: #{$indent-amount};
--max-content-width: #{$max-content-width};
--max-line-width: #{$max-line-width};
--max-page-width: #{$max-page-width};
}

View file

@ -0,0 +1,163 @@
// stylelint-disable max-line-length, number-leading-zero, number-no-trailing-zeros
// stylelint-disable scss/dollar-variable-colon-space-after, value-keyword-case
// Variables
// Font faces, stacks and sizes.
// The font size set on the root html element.
// Specify unitless, it will be recalculated as %.
$base-font-size: 18;
// Base and heading line height, unitless.
$base-line-height: 1.5;
$heading-line-height: 1.3;
// The pt font-size to be used for printing.
$print-font-size: 12pt;
// The font sizes in our type hierarchy as tee shirt sizes.
// Size m is base.
// Use like this: var(--fs-m)
$font-size-fixed: (
xxxxl: 3rem,
xxxl: 2.5rem,
xxl: 2rem,
xl: 1.5rem,
l: 1.25rem,
m: 1rem,
s: 0.889rem,
xs: 0.778rem,
);
// The responsive font sizes in our type hierarchy as tee shirt sizes.
// Size m is base.
// Use like this: var(--fs-m)
$font-size-fluid: (
xxxxl: clamp(2.4881rem, calc(1.8896rem + 2.9924vw), 4.2088rem),
xxxl: clamp(2.0738rem, calc(1.6968rem + 1.8848vw), 3.1575rem),
xxl: clamp(1.7281rem, calc(1.5053rem + 1.1141vw), 2.3688rem),
xl: clamp(1.44rem, calc(1.3228rem + 0.5859vw), 1.7769rem),
l: clamp(1.2rem, calc(1.1537rem + 0.2315vw), 1.3331rem),
m: 1rem,
s: 0.889rem,
xs: 0.778rem,
);
// Set the font sizes to use, fixed or fluid.
$font-size: $font-size-fixed;
// $font-size: $font-size-fluid;
// Font weights.
// Use like this: var(--fw-normal)
$font-weight: (
headings: 700,
bolder: 900,
bold: 700,
medium: 500,
normal: 400,
light: 300,
lighter: 200,
);
// The following font family declarations use widely available fonts.
// A user's web browser will look at the comma-separated list and will
// attempt to use each font in turn until it finds one that is available
// on the user's computer. The final "generic" font (sans-serif, serif or
// monospace) hints at what type of font to use if the web browser doesn't
// find any of the fonts in the list.
// System-ui font stack.
$system-ui: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', 'Liberation Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
// Serif font stacks.
$ui-serif: ui-serif, Constantia, 'Noto Serif', Georgia, serif;
$times: 'Times New Roman', 'Liberation Serif', 'Nimbus Roman No9 L', serif;
$georgia: Georgia, 'Noto Serif', ui-serif, serif;
$garamond: Garamond, Charter, Cambria, 'Noto Serif', ui-serif, serif;
// Sans-serif font stacks.
$ui-sans-serif: ui-sans-serif, $system-ui;
$helvetica: 'Helvetica Neue', Helvetica, 'Liberation Sans', 'Nimbus Sans L', Arial, sans-serif;
$futura: Futura, 'Century Gothic', Montserrat, Calibri, ui-sans-serif, sans-serif;
// Monospace font stacks.
$ui-monospace: ui-monospace, Menlo, 'Cascadia Mono', 'Segoe UI Mono', 'Noto Sans Mono', 'Liberation Mono', Monaco, Consolas, monospace;
// Font family.
// Use like this: var(--ff-body)
$font-family: (
body: $ui-serif,
headings: $ui-sans-serif,
alt: $system-ui,
monospace: $ui-monospace,
);
// Breakpoints
// Use the `respond-to(s)` mixin to use named breakpoints.
$breakpoints: (
'xxxl': 1222px,
'xxl': 1111px,
'xl': 999px,
'l': 888px,
'm': 777px,
's': 666px,
'xs': 555px,
'xxs': 444px,
'xxxs': 333px,
);
// Border radius.
// Use like this: var(--radius-m)
$border-radius: (
xl: 1rem,
l: 0.75rem,
m: 0.5rem,
s: 0.3rem,
xs: 0.125rem,
);
// Spacing
// Generates mt-m (mt = margin-top), mb-m (mb = margin-bottom) and
// mtb-m (mtb = margin-block) classes.
$spacing: (
xxl: 3,
xl: 2,
l: 1.5,
m: 1,
s: 0.75,
xs: 0.5,
xxs: 0.3,
0: 0,
);
// The max content width. (Consider using one of the breakpoints.)
$max-content-width: 1111px;
// The max page width. Defaults to max-content-width.
// Setting this to a larger value than max-content-width allows
// content with class "stretch" to stretch out to the page edge.
// $max-page-width: 1111px;
// The max line width for readability.
$max-line-width: 70ch;
// The left/right gutter/padding.
// Use like this: var(--gutters)
$gutters: calc(5px + 1.5625vw);
$gutters-reverse: calc(0px - (5px + 1.5625vw));
// Breakout amount.
// How much should the "breakout" be. Defaults to gutters value.
// $breakout: calc(5px + 1.5625vw);
// The amount lists, blockquotes and comments are indented.
// Use like this: var(--indent-amount)
$indent-amount: 2rem;
// Control whether RTL styles are added.
$include-rtl: false;
// Show horizontal grid to help with debugging typography.
$debug: false;
$debug-color: $grey-extra-light;

View file

@ -0,0 +1,167 @@
// Zen custom styles
// Page
body {
background-color: var(--color-backdrop);
}
.page {
background-color: var(--color-body-bg);
}
.footer {
border-top: 2px solid var(--color-border);
}
// Apply smaller text to blocks, footer etc.
th,
label,
legend,
figcaption {
font-size: var(--fs-s);
}
.language-selector,
.footer {
font-size: var(--fs-xs);
}
// Apply heading font stack and colour to labels etc.
th,
nav,
label,
legend,
.header,
.footer {
color: var(--color-headings);
font-family: var(--ff-headings);
}
th,
label {
font-weight: var(--fw-headings);
}
// Article and content.
article,
aside {
& > ul {
@extend %ul-straight-left;
}
& > ol {
@extend %ol-straight-left;
}
}
article {
.submitted,
.tags {
@include respond-to(s) {
display: inline-block;
padding-inline-end: 1rem;
}
}
code {
font-size: var(--fs-xs);
overflow-wrap: break-word;
}
pre {
border-radius: var(--radius-xs);
padding: 5px;
border: 1px solid var(--color-border-light);
background-color: var(--color-text-bg);
overflow: auto;
max-height: 300px;
max-width: 90vw;
&.chroma {
max-height: initial;
overflow-x: scroll;
}
& > code {
display: inline-block;
white-space: pre;
}
}
}
.content-dates {
text-align: end;
}
// Navigation
.main-menu {
margin-top: .75rem;
outline: 0;
li {
margin-bottom: .75rem;
padding: 0;
}
a {
display: block;
background-color: var(--color-button);
color: var(--color-text-bg);
padding: 2px 8px;
text-decoration: none;
&:hover,
&:focus {
background-color: var(--color-button-hover);
}
&:active,
&[aria-current] {
background-color: var(--color-button);
text-decoration: underline;
}
}
}
// Search
.search-text {
font-size: var(--fs-l);
}
// Form
main {
input,
textarea {
&:not(:placeholder-shown):valid {
background-color: var(--color-status-bg);
}
&:not(:placeholder-shown):invalid {
background-color: var(--color-error-bg);
}
}
button {
@extend %button--shadow;
}
}
.js-submitted {
input,
textarea {
&:valid {
background-color: var(--color-status-bg);
}
&:invalid {
background-color: var(--color-error-bg);
}
}
}

View file

@ -0,0 +1,10 @@
// Base styles.
// Broken into modular pieces to make it easier to edit.
@import 'document/document';
@import 'forms/forms';
@import 'grouping/grouping';
@import 'headings/headings';
@import 'images/images';
@import 'links/links';
@import 'tables/tables';

View file

@ -0,0 +1,18 @@
// Document
html {
// Change the default font family in all browsers.
font-family: var(--ff-body);
// Set base font size in percent.
font-size: calc(#{$base-font-size} / 16 * 100%);
// Correct the line height in all browsers.
line-height: $base-line-height;
// Set text colour.
color: var(--color-text);
}
body {
// Output a horizontal grid to help with debugging typography. The
// $debug variable will toggle its output.
@include debug-grid();
}

View file

@ -0,0 +1,66 @@
// stylelint-disable property-no-vendor-prefix
// Form defaults.
form {
// Add vertical rhythm margins.
@include margin-block(0 1);
}
input,
textarea,
select {
@include margin-block(0 1);
}
// Mark field as required if needed.
label {
&:has(+ :required) {
&::after {
content: '*';
color: var(--color-mark-highlight);
}
}
}
// Set max text line width in main for readability.
input,
label,
textarea,
select {
max-width: var(--max-line-width);
}
fieldset {
border: 1px solid var(--color-border);
}
input {
// Writing "Min" instead of "min" to force use of css "min()" instead of sass "min()".
// stylelint-disable-next-line function-name-case
width: Min(20em, 100%);
}
[type='text'],
textarea {
// Writing "Min" instead of "min" to force use of css "min()" instead of sass "min()".
// stylelint-disable-next-line function-name-case
width: Min(30em, 100%);
}
// For forms with multibple fields show submit button below the form.
input:not(:only-of-type),
textarea {
& + [type='submit'] {
display: block;
}
}
// For forms none mobile with single field add space between it and the submit button.
@include respond-to(s) {
input:only-of-type {
&:has(+ [type='submit']) {
margin-right: .5rem;
}
}
}

View file

@ -0,0 +1,99 @@
// Grouping content
// Block quotes
//
// The `<blockquote>` element is for quoting blocks of content from another
// source within your document. Wrap the `<blockquote>` around any <abbr
// title="HyperText Markup Language">HTML</abbr> as the quote. For straight
// quotes, we recommend a `<p>`.
//
// Optionally, add a `<footer>` to identify the source of the quote, wrapping
// the name of the source work in `<cite>`.
blockquote {
// Add vertical rhythm margins.
@include margin-block(0 1);
// Also indent the quote on both sides.
margin-inline: var(--indent-amount);
}
// Lists
dl,
ol,
ul,
menu {
// Add vertical rhythm margins.
@include margin-block(0 1);
}
dd {
margin: 0;
margin-inline-start: var(--indent-amount);
}
ol,
ul,
menu {
padding: 0;
padding-inline-start: var(--indent-amount);
// Turn off margins on nested lists.
ol,
ul,
menu {
margin: 0;
}
}
li {
// Set max text line width in main for readability.
.main & {
max-width: var(--max-line-width);
}
}
// Header
header {
// Add vertical rhythm margins.
@include margin-block(0 .33);
}
// Horizontal rule
hr {
@extend %divider;
height: 0;
}
// Paragraphs
p {
// Add vertical rhythm margins.
@include margin-block(0 1);
// Nicer text wrap, e.g. no lone work on last line.
text-wrap: pretty;
// Set max text line width in main for readability.
.main & {
max-width: var(--max-line-width);
}
}
// Preformatted text
pre {
// Add vertical rhythm margins.
@include margin-block(0 1);
font-family: var(--ff-monospace);
}
// Code
// Do not set colour for code with syntax highlighting.
code:not([data-lang]),
kbd,
samp {
color: var(--color-code);
}

View file

@ -0,0 +1,69 @@
// Headings
//
// All HTML headings, `<h1>` through `<h6>`, are available. `%h1` through `%h6`
// classes are also available, for when you want to match the font styling of a
// heading but not be a heading.
h1,
%h1,
h2,
%h2,
h3,
%h3,
h4,
%h4,
h5,
%h5,
h6,
%h6 {
@include margin-block(1 .33, 'em');
color: var(--color-headings);
font-family: var(--ff-headings);
font-weight: var(--fw-headings);
line-height: var(--heading-line-height);
text-wrap: balance;
// Smaller margin when a headeing is right after another heading.
& + & {
@include margin-block-start(.5, 'em');
}
// Set max text line width in main for readability.
.main & {
max-width: var(--max-line-width);
}
}
h1,
%h1 {
// h1 only on top of page so different margins.
@include margin-block(1 .5, 'rem');
font-size: var(--fs-xxl);
letter-spacing: -.01em;
}
h2,
%h2 {
font-size: var(--fs-xl);
letter-spacing: -.01em;
}
h3,
%h3 {
font-size: var(--fs-l);
letter-spacing: -.01em;
}
h4,
%h4 {
font-size: var(--fs-m);
}
h5,
%h5 {
font-size: var(--fs-s);
}
h6,
%h6 {
font-size: var(--fs-xs);
}

View file

@ -0,0 +1,82 @@
// Figure and image.
figure,
img {
&.image {
--image-padding: .75rem;
@include respond-to(s) {
&.center {
margin-inline: auto;
}
&.left {
padding-inline-end: var(--image-padding);
padding-block-end: var(--image-padding);
margin: 0;
float: left;
clear: both;
}
&.right {
padding-inline-start: var(--image-padding);
padding-block-end: var(--image-padding);
margin: 0;
float: right;
clear: both;
}
}
}
}
figure {
// Add vertical rhythm margins.
@include margin-block(0 1);
&.image {
figcaption {
padding-block-start: var(--image-padding);
@include respond-to(s) {
display: table-caption;
caption-side: bottom;
padding-block-start: 0;
}
p {
margin: 0;
}
}
@include respond-to(s) {
display: table;
&.left {
figcaption {
padding-inline-end: var(--image-padding);
padding-block-end: var(--image-padding);
}
}
&.right {
figcaption {
padding-inline-start: var(--image-padding);
padding-block-end: var(--image-padding);
}
}
}
}
&.podcast {
audio {
width: 95%;
}
}
}
img {
&.image {
// Add vertical rhythm margins.
@include margin-block(0 1);
}
}

View file

@ -0,0 +1,72 @@
// Links
//
// Hyperlinks are used to allow the user to navigate to other resources or to
// download a resource.
//
// The order of link states are based on Eric Meyer's article:
// http://meyerweb.com/eric/thoughts/2007/06/11/who-ordered-the-link-states
//
// :visited - A link that has already been visited.
// :hover - A link that is being hovered over.
// :focus - A link that has been given keyboard focus.
// :active - A link that is being actively clicked.
a,
%link {
color: var(--color-link);
}
// Any element can receive focus, but only links can be visited, so we can
// safely lower this selector's specificity. This also ensures visited links
// with additional styles won't have their styles overridden.
:visited {
color: var(--color-link-visited);
}
a:hover,
a:focus {
color: var(--color-link-hover);
}
a:active {
color: var(--color-link-active);
}
// Remove underline from links to current page to
// indicate that there is no need to click on it.
[aria-current] {
text-decoration: none;
}
.link-nav,
%link-nav {
a {
text-decoration: none;
&:hover,
&:focus {
text-decoration: underline;
}
}
}
// Inverted links, for dark backgrounds.
.link-inverted,
%link-inverted {
a {
color: var(--color-link-inverted);
&:visited {
color: var(--color-link-visited-inverted);
}
&:hover,
&:focus {
color: var(--color-link-hover-inverted);
}
&:active {
color: var(--color-link-active-inverted);
}
}
}

View file

@ -0,0 +1,31 @@
// Tables
//
// The `<table>` element displays tabular data in rows, columns, and cells.
table {
// Add vertical rhythm margins.
@include margin-block(0 1);
// Remove default spacing between table cells.
border-collapse: collapse;
// Prevent cramped-looking tables
width: 100%;
}
td,
th {
// Remove most spacing between table cells.
padding: 0;
// Align content to top of cells.
vertical-align: text-top;
}
th {
// Align content to bottom of headers.
vertical-align: bottom;
}
caption,
th {
// Align all text the same.
text-align: start;
}

View file

@ -0,0 +1,71 @@
// Box
//
// A simple box style.
//
// A block is often styled as a box. However, this design component is
// not applied to any blocks by default; it is used as an example of how to
// build and document a CSS component.
//
// "box" is the name of our component, so we define a `.box` class that we can
// apply to any HTML element that needs the box styling. We also provide a
// `%box` placeholder selector so that we can easily extend the basic box
// component with `@extend %box;`.
//
// Take a look at the source code for this component for more information about
// building a good component.
//
// :hover - The hover/focus styling.
// .box--highlight - The "highlight" box variant.
.box,
%box {
// Add vertical rhythm margins.
@include margin-block(1);
@include padding(.5);
border: 5px solid var(--color-border);
// Sass compiles this to the selector: .box__title, %box__title {}
// The "__" (double underscore) is part of a BEM naming convention that
// indicates the "title" is an _element_ of (a piece of) the "box" component.
&__title,
.title {
margin-top: 0;
}
// Sass compiles this to the selector: .box--highlight, %box--highlight {}
// The "--" (double dash) is part of a BEM naming convention that indicates
// the "highlight" is a _modifier_, creating a new variation of the standard
// "box" component.
&--highlight {
border-color: var(--color-highlight);
}
&--fit {
width: fit-content;
}
&--gutter {
padding-inline: var(--gutters);
}
&--inverted {
@extend %link-inverted;
background: var(--color-border);
color: var(--color-text-bg);
// Make sure headings etc. also gets inverted.
* {
color: var(--color-text-bg);
}
}
> * {
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
}

View file

@ -0,0 +1,98 @@
// Button
//
// In addition to the default styling of `<button>` and
// `<input type="submit|image|reset|button">` elements, the `.button` class and
// its variants can apply buttons styles to various elements (like an `<a>`
// link).
//
// :hover - Hover styling.
// :active - Depressed button styling.
.button,
%button,
button,
[type='button'],
[type='reset'],
[type='submit'] {
@extend %button--disabled;
// Some styles don't apply to <a> links since they are inline elements by default.
display: inline-block;
font-family: var(--ff-headings);
text-decoration: none;
text-align: center;
width: fit-content;
margin-right: 1rem;
margin-bottom: 1rem;
padding: .2rem 1rem;
// Improve usability and consistency of cursor style between image-type `input` and others.
cursor: pointer;
color: var(--color-button-text);
background-color: var(--color-button);
border: 1px solid var(--color-button);
border-radius: var(--radius-s);
&:hover,
&:focus-visible,
&:active {
// Override any link underlines and color changes.
text-decoration: none;
color: var(--color-button-text-hover);
background-color: var(--color-button-hover);
}
}
// Add button variations here.
.button,
%button {
&--small {
font-size: var(--fs-xs);
margin-right: .5rem;
margin-bottom: .5rem;
padding: .2rem .75rem;
}
&--alt {
color: var(--color-button-text-hover);
background-color: var(--color-button-hover);
&:hover,
&:focus-visible,
&:active {
color: var(--color-button-text);
background-color: var(--color-button);
}
}
&--outline {
color: var(--color-button);
background-color: var(--color-button-text);
border-color: var(--color-button);
&:hover,
&:focus-visible,
&:active {
color: var(--color-button-text);
background-color: var(--color-button);
}
}
&--shadow {
&:hover {
box-shadow: 2px 2px 5px 1px var(--color-button-hover);
}
&:active {
box-shadow: inset 2px 2px 5px 1px var(--color-button);
}
}
}
// The disabled variation should always go last, so that it overrides any
// other variations.
%button--disabled[disabled] {
@extend %disabled;
background-color: var(--color-grey-extra-light);
border: 1px solid var(--color-button-disabled);
background-image: none;
text-shadow: none;
}

View file

@ -0,0 +1,45 @@
// Cards
//
// A simple cards style.
.cards,
%cards {
@extend %grid-group;
// Add vertical rhythm margins.
@include margin-block(1);
}
.card,
%card {
@include padding(.5);
border: 1px solid var(--color-border);
&--highlight {
border-color: var(--color-highlight);
}
&--featured {
grid-row: span 2;
grid-column: span 2;
}
&--gutter {
padding-inline: var(--gutters);
}
&--inverted {
@extend %link-inverted;
background: var(--color-border);
color: var(--color-text-bg);
}
> * {
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
}

View file

@ -0,0 +1,12 @@
.grid-center {
display: grid;
place-items: center;
}
.text-center {
text-align: center;
}
.margin-center {
margin-inline: auto;
}

View file

@ -0,0 +1,9 @@
// Clearfix
//
// Allows the bottom of an element to extend to the bottom of all floated child
// elements. See http://nicolasgallagher.com/micro-clearfix-hack/
.clearfix,
%clearfix {
@include clearfix();
}

View file

@ -0,0 +1,33 @@
// Cookieconsent
.cookieconsent {
position: sticky;
bottom: 0;
width: 100%;
color: var(--color-warning);
background-color: var(--color-warning-bg);
border-top: 4px solid var(--color-warning-border);
font-size: var(--fs-s);
text-align: center;
transform: translateY(100vh);
transition: all 130ms ease-out;
z-index: 99;
a {
color: inherit;
}
}
.button {
&--accept {
border-color: var(--color-status);
}
&--decline {
border-color: var(--color-warning-border);
}
}
.js-cookieconsent-open {
transform: translateY(0);
}

View file

@ -0,0 +1,14 @@
.disabled,
%disabled {
// Re-set default cursor for disabled elements.
cursor: default;
color: var(--color-button-disabled);
&:hover,
&:focus,
&:active {
// Override any link underlines and color changes.
color: var(--color-button-disabled);
text-decoration: none;
}
}

View file

@ -0,0 +1,16 @@
// Divider
//
// Can be used as an `<hr>`, an empty `<div>` or as a container.
.divider,
%divider {
// Add vertical rhythm margins.
@include margin-block(1);
border: 0;
border-top: 1px solid var(--color-border);
// If used as a container, add a top margin to the first child.
> :first-child {
@include margin-top(1);
}
}

View file

@ -0,0 +1,32 @@
.flex-group,
%flex-group {
$gap: 1;
@include gap($gap);
display: flex;
flex-wrap: wrap;
& > * {
flex: 1;
}
&--2 > * {
@include flex(2, $gap);
}
&--3 > * {
@include flex(3, $gap);
}
&--4 > * {
@include flex(4, $gap);
}
&--5 > * {
@include flex(5, $gap);
}
&--6 > * {
@include flex(6, $gap);
}
}

View file

@ -0,0 +1,19 @@
.flex-inline,
%flex-inline {
--gap: .5rem;
display: flex;
flex-wrap: wrap;
gap: var(--gap);
padding: 0;
text-align: start;
&__item,
li {
list-style: none;
}
&--inline {
display: inline-flex;
}
}

View file

@ -0,0 +1,12 @@
// Branding footer
.footer,
%footer {
padding-block: var(--gutters);
background-color: var(--color-footer-bg);
text-align: center;
p {
margin: 0;
}
}

View file

@ -0,0 +1,52 @@
.grid-group,
%grid-group {
--column-min: 200px;
--gap: 1.5rem;
display: grid;
gap: var(--gap);
// Writing "Min" instead of "min" to force use of css "min()" instead of sass "min()".
// stylelint-disable-next-line function-name-case
grid-template-columns: repeat(auto-fit, minmax(Min(var(--column-min), 100%), 1fr));
&--fill {
// stylelint-disable-next-line function-name-case
grid-template-columns: repeat(auto-fill, minmax(Min(var(--column-min), 100%), 1fr));
}
&--100 {
--column-min: 100px;
}
&--150 {
--column-min: 150px;
}
&--200 {
--column-min: 200px;
}
&--250 {
--column-min: 250px;
}
&--300 {
--column-min: 300px;
}
&--350 {
--column-min: 350px;
}
&--400 {
--column-min: 400px;
}
&--500 {
--column-min: 500px;
}
&--600 {
--column-min: 600px;
}
}

View file

@ -0,0 +1,9 @@
.grid-stack,
%grid-stack {
display: grid;
& > * {
grid-column: 1 / 2;
grid-row: 1 / 2;
}
}

View file

@ -0,0 +1,51 @@
// Branding header
.header,
%header {
padding-block: var(--gutters);
display: flex;
flex-direction: column;
gap: var(--gutters);
background-color: var(--color-header-bg);
@include respond-to(s) {
flex-direction: row;
}
// Wrapping link for logo.
&__logo {
width: fit-content;
}
// Logo image.
&__logo-image {
vertical-align: bottom;
}
// The name of the website.
&__site-name {
margin: 0;
line-height: 1;
}
// The link around the name of the website.
&__site-link {
&:link,
&:visited {
color: var(--color-text);
text-decoration: none;
}
&:hover,
&:focus {
text-decoration: underline;
}
}
// Wrapper for any blocks placed in the header region.
&__region {
@include respond-to(s) {
margin-inline-start: auto;
}
}
}

View file

@ -0,0 +1,29 @@
// Hidden
//
// Hide elements from all users. Compare to the visually-hidden component.
//
// Used for elements which should not be immediately displayed to any user. An
// example would be a collapsible fieldset that will be expanded with a click
// from a user.
//
// For anything you want to hide on page load when JavaScript is enabled, use
// the `.js-hidden` class.
.hidden,
%hidden {
display: none;
}
.js-hidden,
%js-hidden {
html.js & {
@extend %hidden;
}
}
.nojs-hidden,
%nojs-hidden {
html.nojs & {
@extend %hidden;
}
}

View file

@ -0,0 +1,11 @@
// Highlight mark
//
// The "new" or "updated" marker. This is a very thin component. A front-end
// developer may choose to delete this component and just style the `<mark>`
// element directly.
.highlight-mark,
%highlight-mark {
color: var(--color-mark-highlight);
background-color: var(--color-mark-bg);
}

View file

@ -0,0 +1,27 @@
// Inline icons.
.icon-inline,
%icon-inline {
.icon-link {
opacity: 0;
transition: all 130ms ease-in;
text-decoration: none;
}
&:focus-visible,
&:hover {
.icon-link {
opacity: .3;
&:focus-visible,
&:hover {
opacity: 1;
}
}
}
svg {
display: inline;
vertical-align: middle;
}
}

View file

@ -0,0 +1,10 @@
// Language selector
.language-selector {
display: flex;
}
.language-icon {
@include margin-inline-end(.5);
fill: var(--color-text);
}

View file

@ -0,0 +1,55 @@
// Lists with a straight left margin.
.ul-straight-left,
%ul-straight-left {
display: table;
list-style: none;
padding: 0;
& > li {
display: table-row;
&::before {
@include padding-inline-end(.5);
display: table-cell;
content: '\2981';
font-size: var(--fs-s);
}
}
}
.ol-straight-left,
%ol-straight-left {
display: table;
list-style: none;
padding: 0;
& > li {
display: table-row;
counter-increment: table-ol;
&::before {
@include padding-inline-end(.5);
display: table-cell;
content: counter(table-ol) '.';
font-size: var(--fs-s);
text-align: end;
}
}
}
.ul-straight-left--off,
%ul-straight-left--off {
display: block;
list-style: inherit;
& > li {
display: list-item;
&::before {
content: '';
display: inline;
padding: inherit;
}
}
}

View file

@ -0,0 +1,37 @@
// Messages
.message,
%message {
padding: .5rem;
outline-width: 2px;
outline-style: solid;
width: 95%;
&.status {
background-color: var(--color-status-bg);
color: var(--color-status);
outline-color: var(--color-status);
}
&.warning {
background-color: var(--color-warning-bg);
color: var(--color-warning);
outline-color: var(--color-warning-border);
}
&.error {
background-color: var(--color-error-bg);
color: var(--color-error);
outline-color: var(--color-error);
}
&--highlight {
animation: 2s linear infinite outline-highlight;
}
@keyframes outline-highlight {
50% {
outline-width: .3rem;
}
}
}

View file

@ -0,0 +1,8 @@
// Style for meta content.
.meta,
%meta {
font-family: var(--ff-headings);
font-size: var(--fs-xs);
color: var(--color-text-meta);
}

View file

@ -0,0 +1,14 @@
// Do not print
//
// Removes an element from the print version of the web site.
//
// By importing these CSS rules in a file marked as media "all", we allow these
// print rules to be aggregated with other stylesheets, for improved front-end
// performance.
.print-none,
%print-none {
@media print {
display: none;
}
}

View file

@ -0,0 +1,34 @@
// Responsive video
//
// Using a wrapper div, embedded videos can be made responsive so that their
// intrinsic aspect ratio is preserved at any screen width. The
// `responsive-video__embed` class is optional if the embed is an `iframe`.
//
// .responsive-video--4-3 - A video with a 4:3 aspect ratio instead of the
// default 16:9 one.
.responsive-video,
%responsive-video {
--aspect-ratio: 9 / 16; // 16:9 aspect ratio
position: relative;
padding-bottom: calc(var(--aspect-ratio) * 100%); // 16:9 aspect ratio
padding-top: 25px; // Height of video controls
height: 0;
iframe {
@extend %responsive-video__embed;
}
&__embed {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
&--4-3 {
--aspect-ratio: 3 / 4; // 4:3 aspect ratio
}
}

View file

@ -0,0 +1,13 @@
@each $name, $space in $spacing {
.mt--#{$name} {
@include margin-block-start($space);
}
.mb--#{$name} {
@include margin-block-end($space);
}
.mtb--#{$name} {
@include margin-block($space);
}
}

View file

@ -0,0 +1,61 @@
.zebra-table,
%zebra-table {
--cell-padding: .5rem;
@include respond-to-max(s) {
--cell-padding: .3rem;
}
th,
td {
padding: var(--cell-padding);
}
thead {
tr {
background-color: var(--color-row-header);
}
}
tbody {
tr {
&:nth-child(odd) {
background-color: var(--color-row-odd);
}
&:nth-child(even) {
background-color: var(--color-row-even);
}
}
}
}
.responsive-table,
%responsive-table {
--gap: .5rem;
@include respond-to-max(s) {
th {
display: none;
}
td {
display: grid;
gap: var(--gap);
grid-template-columns: 12ch auto;
&::before {
content: attr(aria-label) ':';
font-weight: var(--fw-bold);
}
&:first-of-type {
padding-block-start: var(--gap);
}
&:last-of-type {
padding-block-end: var(--gap);
}
}
}
}

View file

@ -0,0 +1,8 @@
.tags,
%tags {
ul {
@extend %flex-inline;
@extend %flex-inline--inline;
margin-block: 0;
}
}

View file

@ -0,0 +1,16 @@
// Visually hidden
//
// Make an element visually hidden, but accessible to screen readers, etc.
.visually-hidden,
%visually-hidden {
&:not(:focus, :active) {
position: absolute;
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
width: 1px;
overflow: hidden;
white-space: nowrap;
}
}

View file

@ -0,0 +1,182 @@
// stylelint-disable indentation, declaration-colon-newline-after, no-duplicate-selectors
// Initial layout setup.
.layout {
&__page {
max-width: var(--max-page-width);
@include respond-to(s) {
margin-inline: auto;
min-height: 100vh;
min-height: 100svh;
}
}
&__header,
&__footer,
&__main,
&__navigation,
&__first-sidebar,
&__second-sidebar,
&__page-top,
&__page-bottom,
&__cookieconsent {
padding-inline: var(--gutters);
min-width: 0; // With display grid defaults to auto, making <pre> overflow.
}
}
// If page width is bigger then content with,
// setup grid with breakout and stretch for main section.
@if $max-page-width > $max-content-width {
.layout {
&__navigation > * {
max-width: var(--max-content-width);
@include respond-to(s) {
margin-inline: auto;
}
}
&__main,
&__grid {
display: grid;
// Writing "Min" instead of "min" to force use of css "min()" instead of sass "min()".
// stylelint-disable function-name-case
grid-template-columns:
[stretch-start] minmax(var(--gutters), 1fr)
[breakout-start] minmax(0, var(--breakout))
[content-start] Min(calc(100% - var(--gutters) * 2), var(--max-content-width)) [content-end]
minmax(0, var(--breakout)) [breakout-end]
minmax(var(--gutters), 1fr) [stretch-end];
// stylelint-enable function-name-case
padding-inline: 0;
// Stop content in main from streatching.
height: fit-content;
& > :not(.breakout, .stretch) {
grid-column: content;
}
& > .breakout {
grid-column: breakout;
}
& > .stretch {
grid-column: stretch;
padding-inline: var(--gutters);
}
}
}
}
// Setup template areas/rown/columns for page.
.layout {
&__page {
display: grid;
grid-template-areas: 'head'
'nav'
'top'
'main'
'side1'
'side2'
'bottom'
'foot'
'notice';
grid-template-rows: auto
auto
auto
1fr
auto
auto
auto
auto
auto;
grid-template-columns: 1fr;
}
@include respond-to(xl) {
&__page {
grid-template-rows: auto
auto
auto
1fr
auto
auto
auto;
}
&__sidebar-first {
grid-template-areas: 'head head'
'nav nav'
'side1 top'
'side1 main'
'side1 bottom'
'foot foot'
'notice notice';
grid-template-columns: 1fr
2fr;
}
&__sidebar-second {
grid-template-areas: 'head head'
'nav nav'
'top side2'
'main side2'
'bottom side2'
'foot foot'
'notice notice';
grid-template-columns: 2fr
1fr;
}
&__sidebar-two {
grid-template-areas: 'head head head'
'nav nav nav'
'side1 top side2'
'side1 main side2'
'side1 bottom side2'
'foot foot foot'
'notice notice notice';
grid-template-columns: 1fr
2fr
1fr;
}
}
&__header {
grid-area: head;
}
&__navigation {
grid-area: nav;
}
&__page-top {
grid-area: top;
}
&__main {
grid-area: main;
}
&__first-sidebar {
grid-area: side1;
}
&__second-sidebar {
grid-area: side2;
}
&__page-bottom {
grid-area: bottom;
}
&__footer {
grid-area: foot;
}
&__cookieconsent {
grid-area: notice;
}
}

View file

@ -0,0 +1,27 @@
@mixin respond-to($breakpoint) {
// If the key exists in the map
@if map-has-key($breakpoints, $breakpoint) {
// Prints a media query based on the value
@media (min-width: map-get($breakpoints, $breakpoint)) {
@content;
}
} @else {
@media (min-width: $breakpoint) {
@content;
}
}
}
@mixin respond-to-max($breakpoint) {
// If the key exists in the map
@if map-has-key($breakpoints, $breakpoint) {
// Prints a media query based on the value
@media (max-width: map-get($breakpoints, $breakpoint)) {
@content;
}
} @else {
@media (max-width: $breakpoint) {
@content;
}
}
}

View file

@ -0,0 +1,19 @@
// clearfix()
//
// Allows the bottom of an element to extend to the bottom of all floated
// children elements. @see http://nicolasgallagher.com/micro-clearfix-hack/
//
// We use the micro-clearfix, optimized for use in `@extend` where fewer `&` is
// better.
@mixin clearfix() {
&::before {
content: '';
display: table;
}
&::after {
content: '';
display: table;
clear: both;
}
}

View file

@ -0,0 +1,20 @@
// Output a horizontal grid to help with debugging typography.
@mixin debug-grid() {
@if $debug == true {
$grid-height: #{$base-line-height + 'rem'};
position: relative;
// stylelint-disable-next-line max-line-length
background-image: repeating-linear-gradient(180deg, $debug-color, $debug-color 1px, transparent 1px, transparent $grid-height);
&::after {
content: '';
position: absolute;
bottom: -1px;
left: 0;
height: 1px;
width: 100%;
background-color: $debug-color;
}
}
}

View file

@ -0,0 +1,4 @@
@mixin flex($c, $x) {
flex-basis: calc(100% / #{$c} - #{$x * $base-line-height + 'rem'});
flex-grow: 0;
}

View file

@ -0,0 +1,50 @@
// stylelint-disable function-url-quotes
// The relative path from the css directory to the sass directory.
$image-url-path-to-source: '../sass' !default;
// The relative path from the root sass directory to where your components usually lie.
$image-url-subdirectory: 'components' !default;
// image-url()
//
// If you include your images next to your component Sass files, you need to
// specify a url() to point from the generated CSS to the Sass source like this:
//
// ```css
// content: url(../sass/components/is-quite/long.svg);
// ```
//
// With the `image-url()` function the path to all your components is assumed to
// start with `../sass/components/` and you just need to give it the last, short
// bit of the path in your Sass code like this:
//
// ```scss
// content: image-url(is-quite/short.svg);
// ```
//
// If you want to point at an image that is not in the components sub-directory
// of your sass directory, you can override the default $subdirectory by
// passing it in as the first parameter of `image-url()` like this:
//
// ```scss
// content: image-url(base, grouping/blockquote.svg);
// ```
//
// which would output `url(../sass/base/grouping/blockquote.svg)`.
//
// $subdirectory = $image-url-subdirectory - Optional. The relative path from
// the root of your Sass source to the sub-directory where
// components usually lie.
// $path - Required. The path to the image relative to the
// `$subdirectory`.
// $path-to-source = $image-url-path-to-source - Optional. The relative path
// from the css build directory to the sass source directory.
@function image-url($subdirectory, $path: null, $path-to-source: $image-url-path-to-source) {
// If only 1 parameter is given, its value is intended for the $path.
@if type-of($path) == 'null' {
$path: $subdirectory;
$subdirectory: $image-url-subdirectory;
}
@return url(unquote($path-to-source + '/' + $subdirectory + '/' + $path));
}

View file

@ -0,0 +1,26 @@
// stylelint-disable scss/at-if-closing-brace-newline-after, scss/at-if-closing-brace-space-after
$include-rtl: true !default;
// rtl()
//
// Includes Right-To-Left language support by adding a selector of
// `[dir="rtl"]`.
//
// Can be turned off globally by setting `$include-rtl: false;`.
//
// $selector = ':dir(rtl)' - The RTL selector.
@mixin rtl($selector: ':dir(rtl)') {
@if $include-rtl {
@if & {
&#{$selector} {
@content;
}
}
@else {
#{$selector} {
@content;
}
}
}
}

View file

@ -0,0 +1,108 @@
@mixin spacing($property, $spacing, $unit) {
$converted-list: ();
@each $x in $spacing {
$xunit: $unit;
@if $x == 0 {
$xunit: '';
}
$spacing: #{$x * $base-line-height + $xunit};
$converted-list: join($converted-list, $spacing, $separator: space);
}
#{$property}: $converted-list;
}
@mixin gap($x, $unit: 'rem') {
@include spacing(gap, $x, $unit);
}
@mixin margin($x, $unit: 'rem') {
@include spacing(margin, $x, $unit);
}
@mixin margin-inline($x, $unit: 'rem') {
@include spacing(margin-inline, $x, $unit);
}
@mixin margin-inline-start($x, $unit: 'rem') {
@include spacing(margin-inline-start, $x, $unit);
}
@mixin margin-inline-end($x, $unit: 'rem') {
@include spacing(margin-inline-end, $x, $unit);
}
@mixin margin-block($x, $unit: 'rem') {
@include spacing(margin-block, $x, $unit);
}
@mixin margin-block-start($x, $unit: 'rem') {
@include spacing(margin-block-start, $x, $unit);
}
@mixin margin-block-end($x, $unit: 'rem') {
@include spacing(margin-block-end, $x, $unit);
}
@mixin margin-top($x, $unit: 'rem') {
@include spacing(margin-top, $x, $unit);
}
@mixin margin-bottom($x, $unit: 'rem') {
@include spacing(margin-bottom, $x, $unit);
}
@mixin margin-left($x, $unit: 'rem') {
@include spacing(margin-left, $x, $unit);
}
@mixin margin-right($x, $unit: 'rem') {
@include spacing(margin-right, $x, $unit);
}
@mixin padding($x, $unit: 'rem') {
@include spacing(padding, $x, $unit);
}
@mixin padding-inline($x, $unit: 'rem') {
@include spacing(padding-inline, $x, $unit);
}
@mixin padding-inline-start($x, $unit: 'rem') {
@include spacing(padding-inline-start, $x, $unit);
}
@mixin padding-inline-end($x, $unit: 'rem') {
@include spacing(padding-inline-end, $x, $unit);
}
@mixin padding-block($x, $unit: 'rem') {
@include spacing(padding-block, $x, $unit);
}
@mixin padding-block-start($x, $unit: 'rem') {
@include spacing(padding-block-start, $x, $unit);
}
@mixin padding-block-end($x, $unit: 'rem') {
@include spacing(padding-block-end, $x, $unit);
}
@mixin padding-top($x, $unit: 'rem') {
@include spacing(padding-top, $x, $unit);
}
@mixin padding-bottom($x, $unit: 'rem') {
@include spacing(padding-bottom, $x, $unit);
}
@mixin padding-left($x, $unit: 'rem') {
@include spacing(padding-left, $x, $unit);
}
@mixin padding-right($x, $unit: 'rem') {
@include spacing(padding-right, $x, $unit);
}

View file

@ -0,0 +1,160 @@
// The mobile navigation stylesheet for this theme.
@import 'init';
.main-menu,
.header__region { // stylelint-disable selector-class-pattern
display: none;
@include respond-to(s) {
display: block;
}
} // stylelint-enable selector-class-pattern
.mobile-nav {
position: absolute;
right: 0;
top: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
font-family: var(--ff-headings);
z-index: 20;
pointer-events: none;
@include respond-to(s) {
display: none;
}
&.js-nav-open {
position: fixed;
}
.language-icon {
fill: var(--color-text-bg);
}
&__cover {
position: absolute;
width: 100vw;
height: 100vh;
background-color: var(--color-mobile-menu-cover);
opacity: 0;
.js-nav-open & {
opacity: 1;
pointer-events: auto;
}
}
&__toggle {
display: flex;
align-items: center;
position: absolute;
top: var(--gutters);
right: var(--gutters);
margin: 0;
padding: 0 .3rem;
border-color: var(--color-button-text-hover);
font-weight: var(--fw-bold);
z-index: 22;
pointer-events: auto;
@include respond-to(s) {
display: none;
}
&:hover,
&:focus-visible {
svg {
fill: var(--color-button-text-hover);
}
&.button--outline {
border-color: var(--color-button-text-hover);
}
}
}
&__hamburger {
fill: var(--color-button-text);
width: 1.6rem;
margin-left: .1rem;
.button--outline & {
fill: var(--color-button);
}
rect {
transform-origin: center;
}
.js-nav-open & { // stylelint-disable max-nesting-depth
rect {
y: 45px;
&:nth-of-type(1) {
transform: rotate(45deg);
}
&:nth-of-type(2) {
opacity: 0;
}
&:nth-of-type(3) {
transform: rotate(-45deg);
}
}
} // stylelint-enable max-nesting-depth
}
&__sheet {
visibility: hidden;
background-color: var(--color-mobile-menu);
width: 90vw;
height: 100vh;
padding: 2.25rem;
transform: translateX(100vw);
z-index: 21;
.js-nav-open & {
visibility: visible;
pointer-events: auto;
box-shadow: -10px 0 10px -10px var(--color-nearblack);
transform: translateX(10vw);
}
}
&__region {
&:not(:empty) {
margin-bottom: .5rem;
}
}
&__navbar {
display: flex;
flex-direction: column;
padding-inline-start: 0;
margin-block: 0;
li {
list-style: none;
}
a {
display: inline-block;
padding-block: .5rem;
}
}
&__cover,
&__toggle,
&__hamburger rect,
&__sheet {
transition: all 130ms ease-in;
.js-nav-open & {
transition: all 330ms ease-out;
}
}
}

View file

@ -0,0 +1,6 @@
// Navbar
.navbar {
@extend %flex-inline;
margin-block: 0;
}

View file

@ -0,0 +1,32 @@
// Pager
//
// Paged navigation is a list of page numbers when more than 1 page of content
// is available.
.pagination,
.pager,
%pager {
@extend %flex-inline;
@extend %link-nav;
// Add vertical rhythm margins.
@include margin-block(1);
justify-content: center;
.page-item {
}
&__item,
.page-link {
padding-inline: 2px;
}
.active {
font-weight: var(--fw-bold);
}
.disabled {
.page-link {
@extend %disabled;
}
}
}

View file

@ -0,0 +1,47 @@
// stylelint-disable color-named
// The print stylesheet for this theme.
@import 'init';
@import 'components/print-none/print-none';
.pager,
%pager,
.mobile-nav,
aside,
nav,
footer {
@extend %print-none;
}
@media print {
html {
font-size: $print-font-size;
}
html,
body,
.page {
background-color: white;
border-color: black;
box-shadow: none;
color: black;
}
.main {
width: 100%;
}
// Underline all links.
:link,
:visited {
text-decoration: underline;
}
// Add visible title after abbreviations.
abbr[title] {
&::after {
content: ' (' attr(title) ')';
}
}
}

View file

@ -0,0 +1,72 @@
// stylelint-disable no-invalid-position-at-import-rule
// The main stylesheet for this theme.
// Colors and Sass
@import 'init';
// Declaring global CSS variables in :root.
@import 'root';
// Ensure fonts get loaded early to minimize front-end performance impact.
@import 'fonts';
// Reset browsers to some sane defaults.
@import 'reset';
// Base styles.
@import 'base/base';
// Layouts
@import 'layouts/layouts';
// Components
// Design components are reusable designs that can be applied using just the CSS
// class names specified in the component.
@import 'components/box/box';
@import 'components/button/button';
@import 'components/cards/cards';
@import 'components/center/center';
@import 'components/clearfix/clearfix';
@import 'components/cookieconsent/cookieconsent';
@import 'components/divider/divider';
@import 'components/disabled/disabled';
@import 'components/flex-group/flex-group';
@import 'components/flex-inline/flex-inline';
@import 'components/footer/footer';
@import 'components/grid-group/grid-group';
@import 'components/grid-stack/grid-stack';
@import 'components/header/header';
@import 'components/hidden/hidden';
@import 'components/highlight-mark/highlight-mark';
@import 'components/icon-inline/icon-inline';
@import 'components/language-selector/language-selector';
@import 'components/list-straight-left/list-straight-left';
@import 'components/messages/messages';
@import 'components/meta/meta';
@import 'components/responsive-video/responsive-video';
@import 'components/spacing/spacing';
@import 'components/tables/tables';
@import 'components/tags/tags';
@import 'components/visually-hidden/visually-hidden';
// Navigation
@import 'navigation/navbar/navbar';
@import 'navigation/pager/pager';
// Zen
@import 'zen';
// Custom
@import 'custom';