This commit is contained in:
2026-09-23 16:28:48 -07:00
commit 179a710a50
40 changed files with 30037 additions and 0 deletions
+759
View File
@@ -0,0 +1,759 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/404.html">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>Content not found.</h1>
<p>Sorry, can't find this page. Return <a href="/">home</a>.</p>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/404.html` was built on 2026-09-23T23:25:06.281Z -->
</body>
</html>
+793
View File
@@ -0,0 +1,793 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>accessibility | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="accessibility | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/accessibility/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1><span class="brand">Spoonfairies</span> accessibility</h1>
<section>
<h2 id="program-accessibility-statement">program accessibility statement</h2>
<p>tbd</p>
</section>
<section>
<h2 id="site-accessibility-statement">site accessibility statement</h2>
<p>This is an accessibility statement from <span class="brand">Spoonfairies</span>.</p>
<h3 id="measures-to-support-accessibility">measures to support accessibility</h3>
<p><span class="brand">Spoonfairies</span> takes the following measures to ensure accessibility:</p>
<ul>
<li>Include accessibility throughout our internal policies.</li>
<li>Integrate accessibility into our procurement practices.</li>
<li>Assign clear accessibility goals and responsibilities.</li>
<li>Center disabled people in our program.</li>
</ul>
<h3 id="conformance-status">conformance status</h3>
<p>The <a href="https://www.w3.org/WAI/standards-guidelines/wcag/" target="_blank" rel="external">Web Content Accessibility Guidelines (WCAG)</a> defines requirements for designers and developers to improve accessibility for people with disabilities. It defines three levels of conformance: Level A, Level AA, and Level AAA. <span class="brand">Spoonfairies</span> is, to the best of our knowledge, fully conformant with WCAG 2.2 level AA. Fully conformant means that the content fully conforms to the accessibility standard without any exceptions.</p>
<h3 id="feedback">feedback</h3>
<p>We welcome your feedback on the accessibility of <span class="brand">Spoonfairies</span>. Please let us know if you encounter accessibility barriers via <a href="https://leecat.art" target="_blank" rel="external">any of the contact methods listed for Lee Cattarin</a>.</p>
<h3 id="technical-specifications">technical specifications</h3>
<p>Accessibility of <span class="brand">Spoonfairies</span> relies on the following technologies to work with the particular combination of web browser and any assistive technologies or plugins installed on your computer:</p>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
<p>These technologies are relied upon for conformance with the accessibility standards used.</p>
<h3 id="assessment-approach">assessment approach</h3>
<p>We assessed the accessibility of <span class="brand">Spoonfairies</span> by the following approaches:</p>
<ul>
<li>Self-evaluation</li>
</ul>
<h3 id="date">date</h3>
<p>This statement was created on 4 February 2026 using the <a href="https://www.w3.org/WAI/planning/statements/" target="_blank" rel="external">W3C Accessibility Statement Generator Tool</a>.</p>
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/accessibility/` was built on 2026-09-23T23:25:06.281Z -->
</body>
</html>
+762
View File
@@ -0,0 +1,762 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>attribution | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="attribution | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/attribution/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>attribution</h1>
<p>This site is built using <a href="https://www.11ty.dev/" target="_blank" rel="external">Eleventy v3.1.5</a> by <a href="https://leecat.art" target="_blank" rel="external">Lee Cattarin</a>. It is hosted by <a href="https://heckin.technology/" target="_blank" rel="external">heckin' technology</a>, &quot;a small, weird, mostly indigenous, autistic game and software and art cooperative.&quot;</p>
<p>The font is <a href="https://brailleinstitute.org/freefont" target="_blank" rel="external">Atkinson Hyperlegible Next</a>, specifically designed for low-vision readers to improve character recognition.</p>
<p>v1 of this site was built from the <a href="https://github.com/11ty/eleventy-base-blog" target="_blank" rel="external">Eleventy base blog template</a>.</p>
<p>This site is created <a href="https://declare-ai.org/1.0.0/none.html" target="_blank" rel="external">without the use of generative AI</a>.</p>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/attribution/` was built on 2026-09-23T23:25:06.281Z -->
</body>
</html>
Executable
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

+812
View File
@@ -0,0 +1,812 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>get involved | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="get involved | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/get-involved/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/" aria-current="page">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>get involved with <span class="brand">Spoonfairies</span></h1>
<section>
<h2 id="location">location</h2>
<p><span class="brand">Spoonfairies</span> is currently focused on Seattle and the Puget Sound, though we can accept digital-only providers from all over. If you're outside of this region and would like to offer physical services, please <a href="/team#core">talk to someone on the core team</a> about extending <span class="brand">Spoonfairies</span>' reach.</p>
</section>
<section>
<h2 id="our-values">our values</h2>
<p>We ask that all providers and clients uphold our core values as part of their participation.</p>
<ul class="long-items">
<li>
<strong>Community:</strong> we aim to create, nurture, and sustain a
community of providers actively seeking to promote collective wellness,
healing, and support for marginalized people.
</li>
<li>
<strong>Adaptability:</strong> we embrace change and challenges with
enthusiasm and creativity. Our core purpose is to cater our model to meet
the needs of those in our community, ever growing and furthering the goals
of social equitability, justice, and wellness. This means our model and all
outreach should be accessible across all identities & needs.
</li>
<li>
<strong>Love:</strong> we approach all interactions wholeheartedly, with
the primary purpose of extending love and kindness into our community.
</li>
<li>
<strong>Health:</strong> we disrupt the cycle of capitalist exploitation
by honoring the health and wellness of our providers and members; we honor
our own health needs and actively encourage our community to prioritize
their well-being over capitalist interest by facilitating livable wages,
communal support, and collective healing.
</li>
<li>
<strong>Dignity:</strong> we create systems and processes that allow for
providers to fully experience the diverse complexities of everyday life.
We believe that every person deserves to have livable wages and sustainable
work/life balance, and we celebrate our providers' "no".
</li>
</ul>
</section>
<section>
<h2 id="as-a-provider">as a provider</h2>
<p>Sign up using <a href="https://airtable.com/appTNSejknPJEEdrN/pagzaSgmO9bnFVgTt/form" target="_blank" rel="external">our sign-up form</a> — or <a href="mailto:tech@spoonfairies.help?subject=Spoonfairies signup"> email Lee</a> if Airtable (our form provider) is inaccessible to you.</p>
</section>
<section>
<h2 id="as-a-client">as a client</h2>
<p>View the <a href="/providers">provider directory</a> or <a href="/services">browse by service</a> to find relevant providers.</p>
<p>If a given provider does not have a contact method that works for you, reach out to <a href="/team">someone on the team</a> and we'll get in contact with them for you.</p>
<p>Overwhelmed by choices? <a href="mailto:info@spoonfairies.help?subject=Spoonfairies service and provider discovery">Email Bex</a> if you need help navigating providers and services.</p>
</section>
<section>
<h2 id="testimonials">testimonials</h2>
<p>Clients and providers are strongly encouraged to submit testimonials about their experiences with a given provider or with the Spoonfairies program as a whole.</p>
<p>You can submit a testimonial using our <a href="https://airtable.com/appTNSejknPJEEdrN/pagBkMSqVTVXDCkAa/form" target="_blank" rel="external">testimonial form</a> — or <a href="mailto:tech@spoonfairies.help?subject=Spoonfairies testimonials">email Lee</a> if Airtable (our form provider) is inaccessible to you.</p>
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/get-involved/` was built on 2026-09-23T23:25:06.281Z -->
</body>
</html>
+845
View File
@@ -0,0 +1,845 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<section>
<h1>about <span class="brand">Spoonfairies</span></h1>
<p><span class="brand">Spoonfairies</span> is a project to connect people: those who need help and those who can provide it, with the ability to move fluidly between these groups or occupy both.</p>
<p><span class="brand">Spoonfairies</span> is currently focused on Seattle and the Puget Sound region, but digital-only participation can come from all over.</p>
</section>
<section>
<h2 id="ethos">ethos</h2>
<h3 id="universal-worth">universal worth</h3>
<p>Everyone needs and deserves help, and everyone has skills that can better their community. Everyone deserves access to the support and income they need to live their best life.</p>
<h3 id="person-centered-pricing">person-centered pricing</h3>
<p>We are all of equal value and deserve living wages for expending our time and energy. No service is inherently worth any more than another because no person or their time is worth more than another’s.</p>
<h3 id="alternatives-to-capitalism">alternatives to capitalism</h3>
<p>We must build our own support system to build and keep wealth within our communities and provide the services and infrastructures we need to survive.</p>
</section>
<section>
<h2 id="spoonfairies-can-look-like..."><span class="brand">Spoonfairies</span> can look like...</h2>
<h3 id="client">client</h3>
<ul>
<li>J has a sister with long COVID who needs help with some household tasks. He wants to gift her 5 hrs of cleaning services, so he sets her up with a <span class="brand">Spoonfairies</span> provider he's already arranged payment with</li>
<li>M is a busy parent who can forget to take care of herself. She signs up for a weekly check-in service to ensure her own goals move forward</li>
<li>X is a tech worker who hates going to the grocery store. Ze finds a provider to help with weekly grocery delivery and a monthly Costco run</li>
</ul>
<h3 id="provider">provider</h3>
<ul>
<li>L is a stay at home parent with ADHD who loves to cook and provides weekly meal prep &amp; delivery for 25 neurodivergent queerdos in her area at good hourly wage</li>
<li>Q, a car mechanic, owns a queer/neurodivergent friendly business. She offers 10 hrs of services per month to <span class="brand">Spoonfairies</span> clients at friends-and-family rates</li>
<li>D has a part-time job bookkeeping for a larger firm. In their free time, they use their skills to provide monthly accounting services to a handful of clients’ small businesses in exchange for business discounts</li>
</ul>
<h3 id="or-both">or both</h3>
<ul>
<li>Z, an agoraphobic autistic with OCD who is excellent at organization and graphic design, provides admin design services and receives grocery/med delivery and occasional cleaning help.</li>
<li>C is on disability and navigating income/wealth cap. Xe runs virtual body doubling services and barters some of xe's work for other services.</li>
</ul>
</section>
<section>
<h2 id="example-services">example services</h2>
<h3 id="executive-function">executive function</h3>
<h4 id="recurring">recurring</h4>
<ul>
<li>Weekly check-ins – &quot;Life Boss&quot;</li>
<li>Life coach – neurodivergent strategies &amp; resources</li>
</ul>
<h4 id="on-demand">on demand</h4>
<ul>
<li>Body doubling/errand hangs</li>
<li>Custom organizers/graphics for household/personal routines</li>
<li>Neurodivergent advocate/educator (landlords, bosses, families/partners)</li>
</ul>
<h3 id="physical-%26-mental-health">physical &amp; mental health</h3>
<h4 id="recurring-1">recurring</h4>
<ul>
<li>Prescription pick-up/renewal reminders</li>
<li>Transportation to/from appointments</li>
<li>Medical advocacy at appointments</li>
<li>Peer counseling</li>
</ul>
<h4 id="on-demand-1">on demand</h4>
<ul>
<li>Provider research</li>
<li>Appointment scheduling</li>
<li>Benefits navigation</li>
</ul>
<h3 id="home-and-personal-spaces">home and personal spaces</h3>
<h4 id="recurring-2">recurring</h4>
<ul>
<li>Recurring cleaning/chore help</li>
<li>Recurring grocery delivery/meal plan/prep</li>
<li>Recurring appliance/vehicle maintenance</li>
</ul>
<h4 id="on-demand-2">on demand</h4>
<ul>
<li>Organization/room design</li>
<li>De-funk your space</li>
</ul>
<h3 id="administrative">administrative</h3>
<h4 id="recurring-3">recurring</h4>
<ul>
<li>Email/calendar management</li>
<li>Scheduling support</li>
<li>Budget tracking/personal finance support</li>
</ul>
<h4 id="on-demand-3">on demand</h4>
<ul>
<li>Event planning</li>
<li>Job search support</li>
<li>Travel booking/vacation planning</li>
</ul>
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/` was built on 2026-09-23T23:25:06.281Z -->
</body>
</html>
+770
View File
@@ -0,0 +1,770 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>privacy | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="privacy | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/privacy/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>privacy</h1>
<section>
<h2 id="provider-privacy">provider privacy</h2>
<p>Providers sign up via Airtable. <a href="https://www.airtable.com/company/privacy#a-use-of-content" target="_blank" rel="external">Read more on Airtable's privacy policy with regard to user content</a>.</p>
<p>Airtable access is limited to the <a href="/team#core">core <span class="brand">Spoonfairies</span> organizing team</a>.</p>
<p>Sign-up makes clear what provided information is available on our public-facing website. No other information is provided to prospective clients or other parties.</p>
<p>Providers may <a href="/team#core">reach out to someone on the core team</a> at any time regarding removal from the site and deletion of their information.</p>
</section>
<section>
<h2 id="client-privacy">client privacy</h2>
<p>Clients reach out directly to providers using published contact information. No client information is handled by the <span class="brand">Spoonfairies</span> team.</p>
<p><strong>For providers:</strong> if you are looking for places to store client data, we recommend <a href="https://cryptpad.fr/" target="_blank" rel="external">CryptPad</a> which is a fully encrypted and privacy-conscious alternative to services like Google Drive. It offers 1GB of free storage, or further storage on subscription plans.</p>
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/privacy/` was built on 2026-09-23T23:25:06.281Z -->
</body>
</html>
+812
View File
@@ -0,0 +1,812 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bex M. | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="Bex M. | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/providers/bex-m/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<article>
<h1>Bex M.
<span class="pronouns">vey/she</span>
</h1>
<div class="post-metadata">
<p class="post-time">last updated <time datetime="2026-02-09">February 9, 2026</time></p>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/tutoring/" class="post-tag" title="browse providers who offer tutoring">tutoring</a>, </li>
<li><a href="/services/project-management/" class="post-tag" title="browse providers who offer project management">project management</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/event-planning/" class="post-tag" title="browse providers who offer event planning">event planning</a></li>
</ul>
<p class="location">Phinney Ridge</p>
</div>
<h2 id="bio">bio</h2>
<p>fox fairy with background in education, administration, and social work.</p>
<h2 id="services">services</h2>
<ul>
<li>weekly check-in/project management services</li>
<li>K-12 tutoring, particular expertise in English and physics</li>
<li>administrative support (drafting, copy editing, scheduling, travel &amp; event planning)</li>
</ul>
<h3 id="payment">payment</h3>
<ul>
<li>sliding scale $30-50/hr, billable by quarter hour</li>
<li>services swap/skill share</li>
<li>pro bono option available as needed</li>
</ul>
<h3 id="time-constraints">time constraints</h3>
<p>5 hrs per week max (under current circumstances)</p>
<h2>contact information</h2>
<ul class="contacts">
<li>
<a href="mailto:fairy.lady@gmail.com?subject=Spoonfairies" target="_blank">fairy.lady [at] gmail [dot] com</a>
</li>
</ul>
</article>
<section class="related-providers">
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/providers/bex-m/` was built on 2026-09-23T23:25:06.285Z -->
</body>
</html>
+808
View File
@@ -0,0 +1,808 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Blythe S. | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="Blythe S. | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/providers/blythe-s/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<article>
<h1>Blythe S.
<span class="pronouns">she/her</span>
</h1>
<div class="post-metadata">
<p class="post-time">last updated <time datetime="2026-03-17">March 17, 2026</time></p>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/hairdressing/" class="post-tag" title="browse providers who offer hairdressing">hairdressing</a>, </li>
<li><a href="/services/hygiene/" class="post-tag" title="browse providers who offer hygiene">hygiene</a></li>
</ul>
<p class="location">West Seattle</p>
</div>
<h2 id="bio">bio</h2>
<p>I am an ally, friend and professional hairdresser. I am happiest when interacting with and learning about new people. I do my best to listen and observe as I get to know people.</p>
<h2 id="services">services</h2>
<p>I can do haircutting and styling. I may be able to offer more if I learn of people’s different needs. I can also give personal hygiene products for those in need.</p>
<h3 id="payment">payment</h3>
<p>Pro bono</p>
<h3 id="time-constraints">time constraints</h3>
<p>Appointment only, not available Monday eve or Sunday.</p>
<h2>contact information</h2>
<ul class="contacts">
<li>
<a href="mailto:glamouramalola@msn.com?subject=Spoonfairies" target="_blank">glamouramalola [at] msn [dot] com</a>
</li>
<li>
<a href="tel:206-910-8239" target="_blank">206-910-8239</a>
</li>
</ul>
</article>
<section class="related-providers">
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/providers/blythe-s/` was built on 2026-09-23T23:25:06.285Z -->
</body>
</html>
+802
View File
@@ -0,0 +1,802 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Brooke O. | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="Brooke O. | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/providers/brooke-o/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<article>
<h1>Brooke O.
<span class="pronouns">it/its</span>
</h1>
<div class="post-metadata">
<p class="post-time">last updated <time datetime="2026-02-09">February 9, 2026</time></p>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/seamstress/" class="post-tag" title="browse providers who offer seamstress">seamstress</a>, </li>
<li><a href="/services/repair/" class="post-tag" title="browse providers who offer repair">repair</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a></li>
</ul>
<p class="location">Vashon</p>
</div>
<h2 id="bio">bio</h2>
<p>I am a self-taught seamstress and fashion-minded punk. I have been stitching my jackets back together for as long as they've been falling apart, generally with a mind towards visible mending and eye-catching colors.</p>
<h2 id="services">services</h2>
<p>Clothing/textile repair and upcycling, with a strong preference for jackets and/or heavier fabrics</p>
<h3 id="payment">payment</h3>
<p>cash/barter</p>
<h2>contact information</h2>
<ul class="contacts">
<li>
<a href="mailto:bsosment@gmail.com?subject=Spoonfairies" target="_blank">bsosment [at] gmail [dot] com</a>
</li>
</ul>
</article>
<section class="related-providers">
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/providers/brooke-o/` was built on 2026-09-23T23:25:06.285Z -->
</body>
</html>
+905
View File
@@ -0,0 +1,905 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/providers/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/" aria-current="page">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>all providers</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/blythe-s/" class="providerlist-link" aria-label="Blythe S.
she/her
is based out of West Seattle
">
Blythe S.
<span class="pronouns">she/her</span>
<span class="location">West Seattle</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/hairdressing/" class="post-tag" title="browse providers who offer hairdressing">hairdressing</a>, </li>
<li><a href="/services/hygiene/" class="post-tag" title="browse providers who offer hygiene">hygiene</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/rain-v/" class="providerlist-link" aria-label="Rain V.
she/they
is based out of Redmond
">
Rain V.
<span class="pronouns">she/they</span>
<span class="location">Redmond</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/funds/" class="post-tag" title="browse providers who offer funds">funds</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a>, </li>
<li><a href="/services/errands/" class="post-tag" title="browse providers who offer errands">errands</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/roz-m/" class="providerlist-link" aria-label="Roz M.
she/her
is based out of Wallingford
">
Roz M.
<span class="pronouns">she/her</span>
<span class="location">Wallingford</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/body-doubling/" class="post-tag" title="browse providers who offer body doubling">body doubling</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/medical-advocate/" class="post-tag" title="browse providers who offer medical advocate">medical advocate</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/lee-c/" class="providerlist-link" aria-label="Lee C.
ze/he
is digital-only">
Lee C.
<span class="pronouns">ze/he</span>
<span class="online">digital-only</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/brooke-o/" class="providerlist-link" aria-label="Brooke O.
it/its
is based out of Vashon
">
Brooke O.
<span class="pronouns">it/its</span>
<span class="location">Vashon</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/seamstress/" class="post-tag" title="browse providers who offer seamstress">seamstress</a>, </li>
<li><a href="/services/repair/" class="post-tag" title="browse providers who offer repair">repair</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/bex-m/" class="providerlist-link" aria-label="Bex M.
vey/she
is based out of Phinney Ridge
">
Bex M.
<span class="pronouns">vey/she</span>
<span class="location">Phinney Ridge</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/tutoring/" class="post-tag" title="browse providers who offer tutoring">tutoring</a>, </li>
<li><a href="/services/project-management/" class="post-tag" title="browse providers who offer project management">project management</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/event-planning/" class="post-tag" title="browse providers who offer event planning">event planning</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/providers/` was built on 2026-09-23T23:25:06.280Z -->
</body>
</html>
+819
View File
@@ -0,0 +1,819 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Lee C. | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="Lee C. | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/providers/lee-c/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<article>
<h1>Lee C.
<span class="pronouns">ze/he</span>
</h1>
<div class="post-metadata">
<p class="post-time">last updated <time datetime="2026-02-09">February 9, 2026</time></p>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
<p class="online">digital-only</p>
</div>
<h2 id="bio">bio</h2>
<p>multidisciplinary artist and crafter. reluctant computer toucher. big fan of birds.</p>
<h2 id="services">services</h2>
<p>web dev with a focus on accessibility, incl. accessibility reviews for your existing website. spreadsheets galore. basic logos, functional leatherwork, block printed clothing with <a href="https://leecat.art/tag/print" target="_blank">existing designs</a> or your own design (takes more work and resources, add'l cost).</p>
<h3 id="payment">payment</h3>
<p>sliding scale or skill swap</p>
<h3 id="time-constraints">time constraints</h3>
<p>*shrug emoji*</p>
<h2>contact information</h2>
<ul class="contacts">
<li>
<a href="https://signal.me/#eu/PcJ86iNQeAbC-SFbxqI00gFQb6zL4Y6QDCsFDU2mokM4K40djsdNYa3hJAee79ll" target="_blank">inherentlee.13 on signal</a>
</li>
<li>
<a href="mailto:lee.cattarin@gmail.com?subject=Spoonfairies" target="_blank">lee.cattarin [at] gmail [dot] com</a>
</li>
<li>
<a href="https://leecat.art/contact" target="_blank">leecat.art/contact</a>
</li>
</ul>
</article>
<section class="related-providers">
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/providers/lee-c/` was built on 2026-09-23T23:25:06.285Z -->
</body>
</html>
+804
View File
@@ -0,0 +1,804 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Rain V. | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="Rain V. | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/providers/rain-v/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<article>
<h1>Rain V.
<span class="pronouns">she/they</span>
</h1>
<div class="post-metadata">
<p class="post-time">last updated <time datetime="2026-02-13">February 13, 2026</time></p>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/funds/" class="post-tag" title="browse providers who offer funds">funds</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a>, </li>
<li><a href="/services/errands/" class="post-tag" title="browse providers who offer errands">errands</a></li>
</ul>
<p class="location">Redmond</p>
</div>
<h2 id="bio">bio</h2>
<p>I have many crafting hobbies such as woodworking and CNC, but I'm too busy and tired to have much time for them. such is life. I'm a software engineer by trade, living the corpo life I guess ᕕ( ᐛ )ᕗ</p>
<h2 id="services">services</h2>
<p>mainly money tbh, and I can help with things if you're near Redmond or Bellevue and it doesn't take a lot of time.</p>
<h3 id="payment">payment</h3>
<p>praise? barter? (clean my place or body doubling with my partner Milo to help him sort and organize his stuff, little art commissions might be cool) or help someone else in this community for me ❤️</p>
<h3 id="time-constraints">time constraints</h3>
<p>1-2 hours per week, generally low availability so flexibility and planning ahead helps</p>
<h2>contact information</h2>
<ul class="contacts">
<li>
rainybean on discord
</li>
</ul>
</article>
<section class="related-providers">
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/providers/rain-v/` was built on 2026-09-23T23:25:06.286Z -->
</body>
</html>
+823
View File
@@ -0,0 +1,823 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Roz M. | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="Roz M. | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/providers/roz-m/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<article>
<h1>Roz M.
<span class="pronouns">she/her</span>
</h1>
<div class="post-metadata">
<p class="post-time">last updated <time datetime="2026-02-09">February 9, 2026</time></p>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/body-doubling/" class="post-tag" title="browse providers who offer body doubling">body doubling</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/medical-advocate/" class="post-tag" title="browse providers who offer medical advocate">medical advocate</a></li>
</ul>
<p class="location">Wallingford</p>
</div>
<h2 id="bio">bio</h2>
<p>Roz Martinez is a Seattle-based artist working predominantly in graphite and ink. She grew up on the east coast, learning how to express herself visually from her mother and grandmother, both of whom studied art extensively.</p>
<h2 id="services">services</h2>
<ul>
<li>Body Doubling</li>
<li>Art/Design: commissions, teaching, hosting art parties</li>
<li>Mending/sewing</li>
<li>Admin: email drafting, phone calls &amp; scripting, desktop research</li>
<li>Medical advocate/companion</li>
</ul>
<h3 id="payment">payment</h3>
<p>Open to any upon negotiation</p>
<h3 id="time-constraints">time constraints</h3>
<p>Can dedicate 1 day per week to <span class="brand">Spoonfairies</span> and other projects</p>
<h2>contact information</h2>
<ul class="contacts">
<li>
<a href="mailto:rozmartinez@gmail.com?subject=Spoonfairies" target="_blank">rozmartinez [at] gmail [dot] com</a>
</li>
<li>
<a href="https://www.rozmartinezfineart.com/" target="_blank">rozmartinezfineart.com</a>
</li>
<li>
<a href="https://bsky.app/profile/rozmartinez.bsky.social" target="_blank">rozmartinez.bsky.social on bsky</a>
</li>
</ul>
</article>
<section class="related-providers">
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/providers/roz-m/` was built on 2026-09-23T23:25:06.286Z -->
</body>
</html>
+151
View File
@@ -0,0 +1,151 @@
# Sourced from https://codeberg.org/superseriousbusiness/gotosocial/
# AI scrapers and the like.
# https://github.com/ai-robots-txt/ai.robots.txt/
User-agent: AddSearchBot
User-agent: AI2Bot
User-agent: AI2Bot-DeepResearchEval
User-agent: Ai2Bot-Dolma
User-agent: aiHitBot
User-agent: amazon-kendra
User-agent: Amazonbot
User-agent: AmazonBuyForMe
User-agent: Andibot
User-agent: Anomura
User-agent: anthropic-ai
User-agent: Applebot
User-agent: Applebot-Extended
User-agent: atlassian-bot
User-agent: Awario
User-agent: bedrockbot
User-agent: bigsur.ai
User-agent: Bravebot
User-agent: Brightbot 1.0
User-agent: BuddyBot
User-agent: Bytespider
User-agent: CCBot
User-agent: Channel3Bot
User-agent: ChatGLM-Spider
User-agent: ChatGPT Agent
User-agent: ChatGPT-User
User-agent: Claude-SearchBot
User-agent: Claude-User
User-agent: Claude-Web
User-agent: ClaudeBot
User-agent: Cloudflare-AutoRAG
User-agent: CloudVertexBot
User-agent: cohere-ai
User-agent: cohere-training-data-crawler
User-agent: Cotoyogi
User-agent: Crawl4AI
User-agent: Crawlspace
User-agent: Datenbank Crawler
User-agent: DeepSeekBot
User-agent: Devin
User-agent: Diffbot
User-agent: DuckAssistBot
User-agent: Echobot Bot
User-agent: EchoboxBot
User-agent: FacebookBot
User-agent: facebookexternalhit
User-agent: Factset_spyderbot
User-agent: FirecrawlAgent
User-agent: FriendlyCrawler
User-agent: Gemini-Deep-Research
User-agent: Google-CloudVertexBot
User-agent: Google-Extended
User-agent: Google-Firebase
User-agent: Google-NotebookLM
User-agent: GoogleAgent-Mariner
User-agent: GoogleOther
User-agent: GoogleOther-Image
User-agent: GoogleOther-Video
User-agent: GPTBot
User-agent: iAskBot
User-agent: iaskspider
User-agent: iaskspider/2.0
User-agent: IbouBot
User-agent: ICC-Crawler
User-agent: ImagesiftBot
User-agent: imageSpider
User-agent: img2dataset
User-agent: ISSCyberRiskCrawler
User-agent: Kangaroo Bot
User-agent: KlaviyoAIBot
User-agent: KunatoCrawler
User-agent: laion-huggingface-processor
User-agent: LAIONDownloader
User-agent: LCC
User-agent: LinerBot
User-agent: Linguee Bot
User-agent: LinkupBot
User-agent: Manus-User
User-agent: meta-externalagent
User-agent: Meta-ExternalAgent
User-agent: meta-externalfetcher
User-agent: Meta-ExternalFetcher
User-agent: meta-webindexer
User-agent: MistralAI-User
User-agent: MistralAI-User/1.0
User-agent: MyCentralAIScraperBot
User-agent: netEstate Imprint Crawler
User-agent: NotebookLM
User-agent: NovaAct
User-agent: OAI-SearchBot
User-agent: omgili
User-agent: omgilibot
User-agent: OpenAI
User-agent: Operator
User-agent: PanguBot
User-agent: Panscient
User-agent: panscient.com
User-agent: Perplexity-User
User-agent: PerplexityBot
User-agent: PetalBot
User-agent: PhindBot
User-agent: Poggio-Citations
User-agent: Poseidon Research Crawler
User-agent: QualifiedBot
User-agent: QuillBot
User-agent: quillbot.com
User-agent: SBIntuitionsBot
User-agent: Scrapy
User-agent: SemrushBot-OCOB
User-agent: SemrushBot-SWA
User-agent: ShapBot
User-agent: Sidetrade indexer bot
User-agent: Spider
User-agent: TerraCotta
User-agent: Thinkbot
User-agent: TikTokSpider
User-agent: Timpibot
User-agent: TwinAgent
User-agent: VelenPublicWebCrawler
User-agent: WARDBot
User-agent: Webzio-Extended
User-agent: webzio-extended
User-agent: wpbot
User-agent: WRTNBot
User-agent: YaK
User-agent: YandexAdditional
User-agent: YandexAdditionalBot
User-agent: YouBot
User-agent: ZanistaBot
Disallow: /
# Marketing/SEO "intelligence" data scrapers
User-agent: AwarioRssBot
User-agent: AwarioSmartBot
User-agent: DataForSeoBot
User-agent: magpie-crawler
User-agent: Meltwater
User-agent: peer39_crawler
User-agent: peer39_crawler/1.0
User-agent: PiplBot
User-agent: scoop.it
User-agent: Seekr
Disallow: /
# Rules for everything else
User-agent: *
Crawl-delay: 500
+814
View File
@@ -0,0 +1,814 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged admin | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged admin | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/admin/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged admin</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/roz-m/" class="providerlist-link" aria-label="Roz M.
she/her
is based out of Wallingford
">
Roz M.
<span class="pronouns">she/her</span>
<span class="location">Wallingford</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/body-doubling/" class="post-tag" title="browse providers who offer body doubling">body doubling</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/medical-advocate/" class="post-tag" title="browse providers who offer medical advocate">medical advocate</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/bex-m/" class="providerlist-link" aria-label="Bex M.
vey/she
is based out of Phinney Ridge
">
Bex M.
<span class="pronouns">vey/she</span>
<span class="location">Phinney Ridge</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/tutoring/" class="post-tag" title="browse providers who offer tutoring">tutoring</a>, </li>
<li><a href="/services/project-management/" class="post-tag" title="browse providers who offer project management">project management</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/event-planning/" class="post-tag" title="browse providers who offer event planning">event planning</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/admin/` was built on 2026-09-23T23:25:06.323Z -->
</body>
</html>
+816
View File
@@ -0,0 +1,816 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged art | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged art | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/art/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged art</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/roz-m/" class="providerlist-link" aria-label="Roz M.
she/her
is based out of Wallingford
">
Roz M.
<span class="pronouns">she/her</span>
<span class="location">Wallingford</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/body-doubling/" class="post-tag" title="browse providers who offer body doubling">body doubling</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/medical-advocate/" class="post-tag" title="browse providers who offer medical advocate">medical advocate</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/lee-c/" class="providerlist-link" aria-label="Lee C.
ze/he
is digital-only">
Lee C.
<span class="pronouns">ze/he</span>
<span class="online">digital-only</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/art/` was built on 2026-09-23T23:25:06.335Z -->
</body>
</html>
+791
View File
@@ -0,0 +1,791 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged body doubling | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged body doubling | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/body-doubling/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged body doubling</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/roz-m/" class="providerlist-link" aria-label="Roz M.
she/her
is based out of Wallingford
">
Roz M.
<span class="pronouns">she/her</span>
<span class="location">Wallingford</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/body-doubling/" class="post-tag" title="browse providers who offer body doubling">body doubling</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/medical-advocate/" class="post-tag" title="browse providers who offer medical advocate">medical advocate</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/body-doubling/` was built on 2026-09-23T23:25:06.341Z -->
</body>
</html>
+815
View File
@@ -0,0 +1,815 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged clothing | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged clothing | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/clothing/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged clothing</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/lee-c/" class="providerlist-link" aria-label="Lee C.
ze/he
is digital-only">
Lee C.
<span class="pronouns">ze/he</span>
<span class="online">digital-only</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/brooke-o/" class="providerlist-link" aria-label="Brooke O.
it/its
is based out of Vashon
">
Brooke O.
<span class="pronouns">it/its</span>
<span class="location">Vashon</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/seamstress/" class="post-tag" title="browse providers who offer seamstress">seamstress</a>, </li>
<li><a href="/services/repair/" class="post-tag" title="browse providers who offer repair">repair</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/clothing/` was built on 2026-09-23T23:25:06.328Z -->
</body>
</html>
+815
View File
@@ -0,0 +1,815 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged computers | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged computers | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/computers/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged computers</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/rain-v/" class="providerlist-link" aria-label="Rain V.
she/they
is based out of Redmond
">
Rain V.
<span class="pronouns">she/they</span>
<span class="location">Redmond</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/funds/" class="post-tag" title="browse providers who offer funds">funds</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a>, </li>
<li><a href="/services/errands/" class="post-tag" title="browse providers who offer errands">errands</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/lee-c/" class="providerlist-link" aria-label="Lee C.
ze/he
is digital-only">
Lee C.
<span class="pronouns">ze/he</span>
<span class="online">digital-only</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/computers/` was built on 2026-09-23T23:25:06.336Z -->
</body>
</html>
+790
View File
@@ -0,0 +1,790 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged errands | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged errands | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/errands/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged errands</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/rain-v/" class="providerlist-link" aria-label="Rain V.
she/they
is based out of Redmond
">
Rain V.
<span class="pronouns">she/they</span>
<span class="location">Redmond</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/funds/" class="post-tag" title="browse providers who offer funds">funds</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a>, </li>
<li><a href="/services/errands/" class="post-tag" title="browse providers who offer errands">errands</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/errands/` was built on 2026-09-23T23:25:06.344Z -->
</body>
</html>
+790
View File
@@ -0,0 +1,790 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged event planning | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged event planning | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/event-planning/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged event planning</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/bex-m/" class="providerlist-link" aria-label="Bex M.
vey/she
is based out of Phinney Ridge
">
Bex M.
<span class="pronouns">vey/she</span>
<span class="location">Phinney Ridge</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/tutoring/" class="post-tag" title="browse providers who offer tutoring">tutoring</a>, </li>
<li><a href="/services/project-management/" class="post-tag" title="browse providers who offer project management">project management</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/event-planning/" class="post-tag" title="browse providers who offer event planning">event planning</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/event-planning/` was built on 2026-09-23T23:25:06.324Z -->
</body>
</html>
+790
View File
@@ -0,0 +1,790 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged funds | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged funds | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/funds/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged funds</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/rain-v/" class="providerlist-link" aria-label="Rain V.
she/they
is based out of Redmond
">
Rain V.
<span class="pronouns">she/they</span>
<span class="location">Redmond</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/funds/" class="post-tag" title="browse providers who offer funds">funds</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a>, </li>
<li><a href="/services/errands/" class="post-tag" title="browse providers who offer errands">errands</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/funds/` was built on 2026-09-23T23:25:06.343Z -->
</body>
</html>
+788
View File
@@ -0,0 +1,788 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged hairdressing | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged hairdressing | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/hairdressing/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged hairdressing</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/blythe-s/" class="providerlist-link" aria-label="Blythe S.
she/her
is based out of West Seattle
">
Blythe S.
<span class="pronouns">she/her</span>
<span class="location">West Seattle</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/hairdressing/" class="post-tag" title="browse providers who offer hairdressing">hairdressing</a>, </li>
<li><a href="/services/hygiene/" class="post-tag" title="browse providers who offer hygiene">hygiene</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/hairdressing/` was built on 2026-09-23T23:25:06.345Z -->
</body>
</html>
+788
View File
@@ -0,0 +1,788 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged hygiene | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged hygiene | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/hygiene/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged hygiene</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/blythe-s/" class="providerlist-link" aria-label="Blythe S.
she/her
is based out of West Seattle
">
Blythe S.
<span class="pronouns">she/her</span>
<span class="location">West Seattle</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/hairdressing/" class="post-tag" title="browse providers who offer hairdressing">hairdressing</a>, </li>
<li><a href="/services/hygiene/" class="post-tag" title="browse providers who offer hygiene">hygiene</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/hygiene/` was built on 2026-09-23T23:25:06.346Z -->
</body>
</html>
+830
View File
@@ -0,0 +1,830 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>services | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="services | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/" aria-current="page">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>all services</h1>
<p>Services are listed alphabetically.</p>
<ul class="service-list">
<li class="service"><a href="/services/admin/" title="browse providers who offer admin">admin</a></li>
<li class="service"><a href="/services/art/" title="browse providers who offer art">art</a></li>
<li class="service"><a href="/services/body-doubling/" title="browse providers who offer body doubling">body doubling</a></li>
<li class="service"><a href="/services/clothing/" title="browse providers who offer clothing">clothing</a></li>
<li class="service"><a href="/services/computers/" title="browse providers who offer computers">computers</a></li>
<li class="service"><a href="/services/errands/" title="browse providers who offer errands">errands</a></li>
<li class="service"><a href="/services/event-planning/" title="browse providers who offer event planning">event planning</a></li>
<li class="service"><a href="/services/funds/" title="browse providers who offer funds">funds</a></li>
<li class="service"><a href="/services/hairdressing/" title="browse providers who offer hairdressing">hairdressing</a></li>
<li class="service"><a href="/services/hygiene/" title="browse providers who offer hygiene">hygiene</a></li>
<li class="service"><a href="/services/logos/" title="browse providers who offer logos">logos</a></li>
<li class="service"><a href="/services/medical-advocate/" title="browse providers who offer medical advocate">medical advocate</a></li>
<li class="service"><a href="/services/mending/" title="browse providers who offer mending">mending</a></li>
<li class="service"><a href="/services/project-management/" title="browse providers who offer project management">project management</a></li>
<li class="service"><a href="/services/providers/" title="browse providers who offer providers">providers</a></li>
<li class="service"><a href="/services/repair/" title="browse providers who offer repair">repair</a></li>
<li class="service"><a href="/services/seamstress/" title="browse providers who offer seamstress">seamstress</a></li>
<li class="service"><a href="/services/software/" title="browse providers who offer software">software</a></li>
<li class="service"><a href="/services/spreadsheets/" title="browse providers who offer spreadsheets">spreadsheets</a></li>
<li class="service"><a href="/services/tutoring/" title="browse providers who offer tutoring">tutoring</a></li>
<li class="service"><a href="/services/web-accessibility/" title="browse providers who offer web accessibility">web accessibility</a></li>
<li class="service"><a href="/services/webdev/" title="browse providers who offer webdev">webdev</a></li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/` was built on 2026-09-23T23:25:06.280Z -->
</body>
</html>
+792
View File
@@ -0,0 +1,792 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged logos | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged logos | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/logos/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged logos</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/lee-c/" class="providerlist-link" aria-label="Lee C.
ze/he
is digital-only">
Lee C.
<span class="pronouns">ze/he</span>
<span class="online">digital-only</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/logos/` was built on 2026-09-23T23:25:06.334Z -->
</body>
</html>
+791
View File
@@ -0,0 +1,791 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged medical advocate | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged medical advocate | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/medical-advocate/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged medical advocate</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/roz-m/" class="providerlist-link" aria-label="Roz M.
she/her
is based out of Wallingford
">
Roz M.
<span class="pronouns">she/her</span>
<span class="location">Wallingford</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/body-doubling/" class="post-tag" title="browse providers who offer body doubling">body doubling</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/medical-advocate/" class="post-tag" title="browse providers who offer medical advocate">medical advocate</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/medical-advocate/` was built on 2026-09-23T23:25:06.342Z -->
</body>
</html>
+814
View File
@@ -0,0 +1,814 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged mending | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged mending | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/mending/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged mending</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/roz-m/" class="providerlist-link" aria-label="Roz M.
she/her
is based out of Wallingford
">
Roz M.
<span class="pronouns">she/her</span>
<span class="location">Wallingford</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/body-doubling/" class="post-tag" title="browse providers who offer body doubling">body doubling</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/medical-advocate/" class="post-tag" title="browse providers who offer medical advocate">medical advocate</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/brooke-o/" class="providerlist-link" aria-label="Brooke O.
it/its
is based out of Vashon
">
Brooke O.
<span class="pronouns">it/its</span>
<span class="location">Vashon</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/seamstress/" class="post-tag" title="browse providers who offer seamstress">seamstress</a>, </li>
<li><a href="/services/repair/" class="post-tag" title="browse providers who offer repair">repair</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/mending/` was built on 2026-09-23T23:25:06.329Z -->
</body>
</html>
+790
View File
@@ -0,0 +1,790 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged project management | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged project management | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/project-management/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged project management</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/bex-m/" class="providerlist-link" aria-label="Bex M.
vey/she
is based out of Phinney Ridge
">
Bex M.
<span class="pronouns">vey/she</span>
<span class="location">Phinney Ridge</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/tutoring/" class="post-tag" title="browse providers who offer tutoring">tutoring</a>, </li>
<li><a href="/services/project-management/" class="post-tag" title="browse providers who offer project management">project management</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/event-planning/" class="post-tag" title="browse providers who offer event planning">event planning</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/project-management/` was built on 2026-09-23T23:25:06.322Z -->
</body>
</html>
+906
View File
@@ -0,0 +1,906 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged providers | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged providers | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/providers/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged providers</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/blythe-s/" class="providerlist-link" aria-label="Blythe S.
she/her
is based out of West Seattle
">
Blythe S.
<span class="pronouns">she/her</span>
<span class="location">West Seattle</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/hairdressing/" class="post-tag" title="browse providers who offer hairdressing">hairdressing</a>, </li>
<li><a href="/services/hygiene/" class="post-tag" title="browse providers who offer hygiene">hygiene</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/rain-v/" class="providerlist-link" aria-label="Rain V.
she/they
is based out of Redmond
">
Rain V.
<span class="pronouns">she/they</span>
<span class="location">Redmond</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/funds/" class="post-tag" title="browse providers who offer funds">funds</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a>, </li>
<li><a href="/services/errands/" class="post-tag" title="browse providers who offer errands">errands</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/roz-m/" class="providerlist-link" aria-label="Roz M.
she/her
is based out of Wallingford
">
Roz M.
<span class="pronouns">she/her</span>
<span class="location">Wallingford</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/body-doubling/" class="post-tag" title="browse providers who offer body doubling">body doubling</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/medical-advocate/" class="post-tag" title="browse providers who offer medical advocate">medical advocate</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/lee-c/" class="providerlist-link" aria-label="Lee C.
ze/he
is digital-only">
Lee C.
<span class="pronouns">ze/he</span>
<span class="online">digital-only</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/brooke-o/" class="providerlist-link" aria-label="Brooke O.
it/its
is based out of Vashon
">
Brooke O.
<span class="pronouns">it/its</span>
<span class="location">Vashon</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/seamstress/" class="post-tag" title="browse providers who offer seamstress">seamstress</a>, </li>
<li><a href="/services/repair/" class="post-tag" title="browse providers who offer repair">repair</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/bex-m/" class="providerlist-link" aria-label="Bex M.
vey/she
is based out of Phinney Ridge
">
Bex M.
<span class="pronouns">vey/she</span>
<span class="location">Phinney Ridge</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/tutoring/" class="post-tag" title="browse providers who offer tutoring">tutoring</a>, </li>
<li><a href="/services/project-management/" class="post-tag" title="browse providers who offer project management">project management</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/event-planning/" class="post-tag" title="browse providers who offer event planning">event planning</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/providers/` was built on 2026-09-23T23:25:06.280Z -->
</body>
</html>
+790
View File
@@ -0,0 +1,790 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged repair | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged repair | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/repair/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged repair</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/brooke-o/" class="providerlist-link" aria-label="Brooke O.
it/its
is based out of Vashon
">
Brooke O.
<span class="pronouns">it/its</span>
<span class="location">Vashon</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/seamstress/" class="post-tag" title="browse providers who offer seamstress">seamstress</a>, </li>
<li><a href="/services/repair/" class="post-tag" title="browse providers who offer repair">repair</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/repair/` was built on 2026-09-23T23:25:06.326Z -->
</body>
</html>
+790
View File
@@ -0,0 +1,790 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged seamstress | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged seamstress | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/seamstress/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged seamstress</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/brooke-o/" class="providerlist-link" aria-label="Brooke O.
it/its
is based out of Vashon
">
Brooke O.
<span class="pronouns">it/its</span>
<span class="location">Vashon</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/seamstress/" class="post-tag" title="browse providers who offer seamstress">seamstress</a>, </li>
<li><a href="/services/repair/" class="post-tag" title="browse providers who offer repair">repair</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/mending/" class="post-tag" title="browse providers who offer mending">mending</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/seamstress/` was built on 2026-09-23T23:25:06.325Z -->
</body>
</html>
+815
View File
@@ -0,0 +1,815 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged software | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged software | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/software/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged software</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/rain-v/" class="providerlist-link" aria-label="Rain V.
she/they
is based out of Redmond
">
Rain V.
<span class="pronouns">she/they</span>
<span class="location">Redmond</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/funds/" class="post-tag" title="browse providers who offer funds">funds</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a>, </li>
<li><a href="/services/errands/" class="post-tag" title="browse providers who offer errands">errands</a></li>
</ul>
</li>
<li class="providerlist-item">
<a href="/providers/lee-c/" class="providerlist-link" aria-label="Lee C.
ze/he
is digital-only">
Lee C.
<span class="pronouns">ze/he</span>
<span class="online">digital-only</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/software/` was built on 2026-09-23T23:25:06.338Z -->
</body>
</html>
+792
View File
@@ -0,0 +1,792 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged spreadsheets | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged spreadsheets | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/spreadsheets/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged spreadsheets</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/lee-c/" class="providerlist-link" aria-label="Lee C.
ze/he
is digital-only">
Lee C.
<span class="pronouns">ze/he</span>
<span class="online">digital-only</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/spreadsheets/` was built on 2026-09-23T23:25:06.332Z -->
</body>
</html>
+790
View File
@@ -0,0 +1,790 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged tutoring | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged tutoring | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/tutoring/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged tutoring</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/bex-m/" class="providerlist-link" aria-label="Bex M.
vey/she
is based out of Phinney Ridge
">
Bex M.
<span class="pronouns">vey/she</span>
<span class="location">Phinney Ridge</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/tutoring/" class="post-tag" title="browse providers who offer tutoring">tutoring</a>, </li>
<li><a href="/services/project-management/" class="post-tag" title="browse providers who offer project management">project management</a>, </li>
<li><a href="/services/admin/" class="post-tag" title="browse providers who offer admin">admin</a>, </li>
<li><a href="/services/event-planning/" class="post-tag" title="browse providers who offer event planning">event planning</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/tutoring/` was built on 2026-09-23T23:25:06.314Z -->
</body>
</html>
+792
View File
@@ -0,0 +1,792 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged web accessibility | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged web accessibility | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/web-accessibility/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged web accessibility</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/lee-c/" class="providerlist-link" aria-label="Lee C.
ze/he
is digital-only">
Lee C.
<span class="pronouns">ze/he</span>
<span class="online">digital-only</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/web-accessibility/` was built on 2026-09-23T23:25:06.331Z -->
</body>
</html>
+792
View File
@@ -0,0 +1,792 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>providers tagged webdev | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="providers tagged webdev | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/services/webdev/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>providers tagged webdev</h1>
<ul class="providerlist">
<li class="providerlist-item">
<a href="/providers/lee-c/" class="providerlist-link" aria-label="Lee C.
ze/he
is digital-only">
Lee C.
<span class="pronouns">ze/he</span>
<span class="online">digital-only</span>
</a>
<p class="visually-hidden">services this provider offers are </p>
<ul class="taglist">
<li><a href="/services/providers/" class="post-tag" title="browse providers who offer providers">providers</a>, </li>
<li><a href="/services/webdev/" class="post-tag" title="browse providers who offer webdev">webdev</a>, </li>
<li><a href="/services/web-accessibility/" class="post-tag" title="browse providers who offer web accessibility">web accessibility</a>, </li>
<li><a href="/services/spreadsheets/" class="post-tag" title="browse providers who offer spreadsheets">spreadsheets</a>, </li>
<li><a href="/services/logos/" class="post-tag" title="browse providers who offer logos">logos</a>, </li>
<li><a href="/services/clothing/" class="post-tag" title="browse providers who offer clothing">clothing</a>, </li>
<li><a href="/services/art/" class="post-tag" title="browse providers who offer art">art</a>, </li>
<li><a href="/services/computers/" class="post-tag" title="browse providers who offer computers">computers</a>, </li>
<li><a href="/services/software/" class="post-tag" title="browse providers who offer software">software</a></li>
</ul>
</li>
</ul>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/services/webdev/` was built on 2026-09-23T23:25:06.330Z -->
</body>
</html>
+124
View File
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://spoonfairies.help/providers/bex-m/</loc>
<lastmod>2026-02-09</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/providers/brooke-o/</loc>
<lastmod>2026-02-09</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/providers/lee-c/</loc>
<lastmod>2026-02-09</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/providers/roz-m/</loc>
<lastmod>2026-02-09</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/providers/rain-v/</loc>
<lastmod>2026-02-13</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/providers/blythe-s/</loc>
<lastmod>2026-03-17</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/</loc>
<lastmod>2026-09-23</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/accessibility/</loc>
<lastmod>2026-09-23</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/attribution/</loc>
<lastmod>2026-09-23</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/get-involved/</loc>
<lastmod>2026-09-23</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/privacy/</loc>
<lastmod>2026-09-23</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/providers/</loc>
<lastmod>2026-09-23</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/services/providers/</loc>
<lastmod>2026-09-23</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/services/</loc>
<lastmod>2026-09-23</lastmod>
</url>
<url>
<loc>https://spoonfairies.help/team/</loc>
<lastmod>2026-09-23</lastmod>
</url>
</urlset>
+767
View File
@@ -0,0 +1,767 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>team | Spoonfairies</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<!-- Meta -->
<link rel="canonical" href="/">
<meta name="description" content="find the services you need from others who need you">
<meta name="robots" content="index,follow">
<meta property="og:title" content="team | Spoonfairies">
<meta property="og:type" content="article">
<meta property="og:url" content="https://spoonfairies.help/team/">
<meta property="og:description" content="find the services you need from others who need you">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<meta property="og:image" content="https://spoonfairies.help/favicon.ico">
<meta property="og:image:alt" content="the Spoonfairies logo, a spoon with wings">
<meta name="generator" content="Eleventy v3.1.5">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="">
<link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel="stylesheet">
<!-- CSS -->
<style>:root {
color-scheme: light dark;
--font-family: "Atkinson Hyperlegible Next", sans-serif;
/* Theme colors */
--color-light: #fbe8fd;
--color-dark: #110526;
--color-pink-dark: #741189;
--color-pink-light: #d972ef;
--color-purple-dark: #421397;
--color-purple-light: #9d6ff4;
--color-blue-dark: #1243a7;
--color-blue-light: #6586ea;
/* light/dark mode resolved colors */
--color-bg: light-dark(var(--color-light), var(--color-dark));
--color-text: light-dark(var(--color-dark), var(--color-light));
--color-pink: light-dark(var(--color-pink-dark), var(--color-pink-light));
--color-purple: light-dark(var(--color-purple-dark), var(--color-purple-light));
--color-blue: light-dark(var(--color-blue-dark), var(--color-blue-light));
}
/* numbered components are from https://www.joshwcomeau.com/css/custom-css-reset/ */
*, *::before, *::after {
box-sizing: border-box; /* 1. Use a more-intuitive box-sizing model */
}
#root, #__next {
isolation: isolate; /* 10. Create a root stacking context */
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords; /* 3. Enable keyword animations */
}
}
html,
body {
padding: 0;
margin: 0 auto;
font-family: var(--font-family);
color: var(--color-text);
background-color: var(--color-bg);
}
html {
overflow-y: scroll;
}
body {
max-width: 40rem;
line-height: 1.5; /* 4. Increase line-height */
-webkit-font-smoothing: antialiased; /* 5. Improve text rendering */
}
main {
padding: 1rem;
}
section + section {
margin-top: 4rem;;
}
img, picture, video, canvas, svg {
display: block; /* 6. Improve media defaults */
max-width: 100%; /* 6. Improve media defaults */
height: auto; /* 6. Improve media defaults */
}
input, button, textarea, select {
font: inherit; /* 7. Inherit fonts for form controls */
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word; /* 8. Avoid text overflows */
}
p {
text-wrap: pretty; /* 9. Improve line wrapping */
}
p:last-child {
margin-bottom: 0;
}
p {
line-height: 1.5;
}
p + p {
margin-top: 2rem;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance; /* 9. Improve line wrapping */
}
h1 {
font-size: 2.5rem;
margin-top: 0;
}
h2 {
font-size: 1.9rem;
padding-bottom: .1rem;
border-bottom: .1rem solid var(--color-pink);
}
h3 {
font-size: 1.5rem;
padding-bottom: .05rem;
border-bottom: .05rem solid var(--color-pink);
}
h4 {
font-size: 1.2rem;
}
li {
line-height: 1.5;
}
.long-items li + li {
margin-top: .75rem;
}
a {
color: var(--color-text);
text-decoration-thickness: .2rem;
text-decoration-color: var(--color-blue);
border-radius: .1rem;
outline-offset: .1rem;
}
a:visited {
text-decoration-color: var(--color-purple);
}
a:hover,
a:active {
text-decoration-color: var(--color-pink);
}
a:focus-visible {
text-decoration: none;
outline: .15rem solid var(--color-pink);
}
a.ha {
color: var(--color-pink);
outline-offset: 0;
}
span.ha-placeholder {
opacity: .55;
}
/* https://www.a11yproject.com/posts/how-to-hide-content/ */
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
/* name coloration */
.brand {
color: var(--color-pink);
font-weight: bold;
}
/* provider pronouns */
.pronouns::after {
content: ")" / "";
}
.pronouns::before {
content: "(pronouns: " / "pronouns: ";
}
.pronouns {
color: var(--color-text);
opacity: .75;
font-size: .8em;
}
/* location spans */
.location::before {
content: "📍" / "is based out of ";
}
.online::before {
content: "🌐" / "is ";
}
.location,
.online {
margin: 0;
text-align: right;
color: var(--color-text);
font-size: 1rem;
font-weight: bold;
}
/* Posts list */
.providerlist {
padding: 0;
}
.providerlist-item {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 1rem;
}
.providerlist-item + .providerlist-item {
border-top: .1rem dotted;
margin-top: 2.25rem;
padding-top: 1.5rem;
}
.providerlist-link {
font-size: 1.35rem; /* 19px /16 */
font-weight: 700;
flex-basis: 100%;
border-bottom: .05rem solid var(--color-pink);
text-decoration: none;
color: var(--color-blue);
display: inline-flex;
align-items: baseline;
column-gap: .5rem;
flex-flow: row wrap;
}
.providerlist-link:visited {
color: var(--color-purple);
}
.providerlist-link:hover,
.providerlist-link:active {
color: var(--color-pink);
}
.providerlist-link:focus-visible {
border-bottom-color: var(--color-bg);
}
.providerlist-link .location,
.providerlist-link .online {
flex-grow: 5;
}
.providerlist-item-active .providerlist-link {
font-weight: bold;
}
/* Tags */
.post-tag {
display: inline-block;
font-style: italic;
}
/* Tags list */
.taglist {
display: inline-flex;
flex-wrap: wrap;
column-gap: .5rem;
list-style: none;
padding: 0;
margin: 0;
}
/* related providers section on provider pages */
.related-providers {
border-top: .1rem dotted;
padding-top: 1rem;
margin-top: 4rem;
}
/* services page */
.service-list {
display: flex;
flex-flow: row wrap;
padding-left: 0;
column-gap: 1rem;
row-gap: 2rem;
margin-top: 3rem;
}
.service {
list-style: none;
}
.service a {
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
.service a:focus-visible {
border-color: var(--color-bg);
}
/* post metadata */
.post-metadata {
display: flex;
flex-flow: column nowrap;
align-items: flex-end;
gap: .5rem;
}
.post-time {
font-size: .9rem;
opacity: .75;
margin: 0;
}
@media (max-width: 500px) {
.post-metadata .taglist {
justify-content: flex-end;
}
}
/* provider contact info */
.contacts {
text-align: center;
padding: 0;
}
.contacts li {
list-style: none;
}
.contacts li + li {
padding-top: .75rem;
}
/* team page specific */
.team-contact {
display: block;
text-align: center;
}
header {
border-bottom: .2rem dotted;
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
#skip-link {
text-decoration: none;
background: var(--color-bg);
color: var(--color-text);
padding: 0.5rem 1rem;
outline-offset: 0;
border-radius: .25rem;
}
/* Prevent visually-hidden skip link fom pushing content around when focused */
#skip-link.visually-hidden:focus {
position: absolute;
top: 1rem;
left: 1rem;
/* Ensure it is positioned on top of everything else when it is shown */
z-index: 999;
}
/* logo and title */
.home-link {
font-weight: 700;
border-radius: .25rem;
display: flex;
gap: .5rem;
outline-offset: .25rem;
text-underline-offset: .2rem;
}
.home-link:link:not(:hover) {
text-decoration: none;
}
a[href].home-link:focus-visible {
outline-width: .25rem;
}
header img {
height: 3rem !important;
width: 3rem !important;
border-radius: .5rem;
}
header h2 {
margin: 0;
outline-offset: .25rem;
border: none;
text-transform: lowercase;
color: var(--color-pink);
}
header a:has(h2):hover {
text-decoration-color: var(--color-text);
}
/* Nav */
.nav {
display: flex;
gap: .5rem 1rem;
padding: 0;
margin: 0;
list-style: none;
}
.nav-item {
display: inline-block;
}
.nav a[href][aria-current="page"] {
text-decoration: underline;
text-decoration-thickness: .2rem;
}
.nav a[href][aria-current="page"]:hover {
text-decoration-color: var(--color-pink);
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
gap: 1rem;
border-top: .2rem dotted;
margin-top: 2.25rem;
padding-top: 2rem;
padding-left: 0;
}
.pagination li {
list-style: none;
}
.pagination li:not(:has(a)),
.pagination a {
display: block;
border: .1rem dotted;
padding: .5rem;
border-radius: .75rem;
}
/* Footer */
footer {
border-top: .2rem dotted;
margin-top: 1.5rem;
padding: 1rem 0;
text-align: center;
}
.footer-links {
display: flex;
gap: 1rem;
justify-content: space-between;
}
footer p {
margin: 0;
}
footer .year {
width: 30%;
padding-top: .5rem;
margin: 1rem auto;
border-top: .05rem solid;
}
@media (max-width: 500px) {
.footer-links {
flex-flow: column;
gap: .1rem;
align-items: center;
}
footer .year {
width: 65%;
}
}</style>
<!-- JS -->
<script type="module">// Thank you to https://github.com/daviddarnes/heading-anchors
// Thank you to https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
let globalInstanceIndex = 0;
class HeadingAnchors extends HTMLElement {
static register(tagName = "heading-anchors", registry = window.customElements) {
if(registry && !registry.get(tagName)) {
registry.define(tagName, this);
}
}
static attributes = {
exclude: "data-ha-exclude",
prefix: "prefix",
content: "content",
}
static classes = {
anchor: "ha",
placeholder: "ha-placeholder",
srOnly: "ha-visualhide",
}
static defaultSelector = "h2,h3,h4,h5,h6";
static css = `
.${HeadingAnchors.classes.srOnly} {
clip: rect(0 0 0 0);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: var(--ha_offsetx);
top: var(--ha_offsety);
text-decoration: none;
opacity: 0;
}
.${HeadingAnchors.classes.placeholder} {
opacity: .3;
}
.${HeadingAnchors.classes.anchor}:is(:focus-within, :hover) {
opacity: 1;
}
.${HeadingAnchors.classes.anchor},
.${HeadingAnchors.classes.placeholder} {
display: inline-block;
padding: 0 .25em;
/* Disable selection of visually hidden label */
-webkit-user-select: none;
user-select: none;
}
@supports (anchor-name: none) {
.${HeadingAnchors.classes.anchor} {
position: absolute;
left: anchor(left);
top: anchor(top);
}
}`;
get supports() {
return "replaceSync" in CSSStyleSheet.prototype;
}
get supportsAnchorPosition() {
return CSS.supports("anchor-name: none");
}
constructor() {
super();
if(!this.supports) {
return;
}
let sheet = new CSSStyleSheet();
sheet.replaceSync(HeadingAnchors.css);
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
this.headingStyles = {};
this.instanceIndex = globalInstanceIndex++;
}
connectedCallback() {
if (!this.supports) {
return;
}
this.headings.forEach((heading, index) => {
if(!heading.hasAttribute(HeadingAnchors.attributes.exclude)) {
let anchor = this.getAnchorElement(heading);
let placeholder = this.getPlaceholderElement();
// Prefers anchor position approach for better accessibility
// https://amberwilson.co.uk/blog/are-your-anchor-links-accessible/
if(this.supportsAnchorPosition) {
let anchorName = `--ha_${this.instanceIndex}_${index}`;
placeholder.style.setProperty("anchor-name", anchorName);
anchor.style.positionAnchor = anchorName;
}
heading.appendChild(placeholder);
heading.after(anchor);
}
});
}
// Polyfill-only
positionAnchorFromPlaceholder(placeholder) {
if(!placeholder) {
return;
}
let heading = placeholder.closest("h1,h2,h3,h4,h5,h6");
if(!heading.nextElementSibling) {
return;
}
// TODO next element could be more defensive
this.positionAnchor(heading.nextElementSibling);
}
// Polyfill-only
positionAnchor(anchor) {
if(!anchor || !anchor.previousElementSibling) {
return;
}
// TODO previous element could be more defensive
let heading = anchor.previousElementSibling;
this.setFontProp(heading, anchor);
if(this.supportsAnchorPosition) {
// quit early
return;
}
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
anchor.style.setProperty("--ha_offsetx", `${placeholder.offsetLeft}px`);
anchor.style.setProperty("--ha_offsety", `${placeholder.offsetTop}px`);
}
}
setFontProp(heading, anchor) {
let placeholder = heading.querySelector(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
let style = getComputedStyle(placeholder);
let props = ["font-weight", "font-size", "line-height", "font-family"];
let [weight, size, lh, family] = props.map(name => style.getPropertyValue(name));
anchor.style.setProperty("font", `${weight} ${size}/${lh} ${family}`);
let vars = style.getPropertyValue("font-variation-settings");
if(vars) {
anchor.style.setProperty("font-variation-settings", vars);
}
}
}
getAccessibleTextPrefix() {
// Useful for i18n
return this.getAttribute(HeadingAnchors.attributes.prefix) || "Jump to section titled";
}
getContent() {
if(this.hasAttribute(HeadingAnchors.attributes.content)) {
return this.getAttribute(HeadingAnchors.attributes.content);
}
return "#";
}
// Placeholder nests inside of heading
getPlaceholderElement() {
let ph = document.createElement("span");
ph.setAttribute("aria-hidden", true);
ph.classList.add(HeadingAnchors.classes.placeholder);
let content = this.getContent();
if(content) {
ph.textContent = content;
}
ph.addEventListener("mouseover", (e) => {
let placeholder = e.target.closest(`.${HeadingAnchors.classes.placeholder}`);
if(placeholder) {
this.positionAnchorFromPlaceholder(placeholder);
}
});
return ph;
}
getAnchorElement(heading) {
let anchor = document.createElement("a");
anchor.href = `#${heading.id}`;
anchor.classList.add(HeadingAnchors.classes.anchor);
let content = this.getContent();
anchor.innerHTML = `<span class="${HeadingAnchors.classes.srOnly}">${this.getAccessibleTextPrefix()}: ${heading.textContent}</span>${content ? `<span aria-hidden="true">${content}</span>` : ""}`;
anchor.addEventListener("focus", e => {
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
if(anchor) {
this.positionAnchor(anchor);
}
});
anchor.addEventListener("mouseover", (e) => {
// when CSS anchor positioning is supported, this is only used to set the font
let anchor = e.target.closest(`.${HeadingAnchors.classes.anchor}`);
this.positionAnchor(anchor);
});
return anchor;
}
get headings() {
return this.querySelectorAll(this.selector.split(",").map(entry => `${entry.trim()}[id]`));
}
get selector() {
return this.getAttribute("selector") || HeadingAnchors.defaultSelector;
}
}
HeadingAnchors.register();
export { HeadingAnchors }</script>
</head>
<body>
<header>
<a href="/" class="home-link" title="home page">
<img src="/.11ty/image/?src=src%2Flogo.jpg&width=585&format=jpeg&via=transform" alt="the Spoonfairies logo, showing a spoon with fairy wings" loading="lazy" decoding="async" width="585" height="585">
<h2>Spoonfairies</h2>
</a>
<nav aria-label="main navigation">
<ul class="nav">
<li class="nav-item"><a href="/providers/">all providers</a></li>
<li class="nav-item"><a href="/services/">all services</a></li>
<li class="nav-item"><a href="/get-involved/">get involved</a></li>
</ul>
</nav>
</header>
<main id="main">
<h1>our team</h1>
<section>
<h2 id="core">core</h2>
<h3 id="organizer-bex">organizer Bex</h3>
<p>Bex is an educator, social worker, and artist committed to creating a better world for queer and disabled people. Vey have been a Seattle renter since the early 2010s, dreaming and scheming more liberated futures for us all, while knitting socks and admiring the cutest kitties on the planet.</p>
<p><a class="team-contact" href="mailto:info@spoonfairies.help?subject=Spoonfairies">email Bex about <span class="brand">Spoonfairies</span></a></p>
<h3 id="developer-lee">developer Lee</h3>
<p>Lee is a multidisciplinary artist and software engineer who works across many media. In the artistic space, ze creates block prints, leatherwork, handspun yarn, knits, and more; technologically, hir skills range from front-end web development with a focus on accessibility to back-end infrastructure and devOps. You can find Lee online at <a href="https://leecat.art" target="_blank" rel="external">leecat.art</a>.</p>
<p><a class="team-contact" href="mailto:tech@spoonfairies.help?subject=Spoonfairies">email Lee about <span class="brand">Spoonfairies</span></a></p>
</section>
</main>
<footer>
<div class="footer-links">
<p><a href="/attribution" title="site attribution">attribution</a></p>
<p><a href="/team" title="meet or contact the Spoonfairies team">team</a></p>
<p><a href="/privacy" title="data privacy">privacy</a></p>
<p><a href="/accessibility" title="accessibility statements">accessibility</a></p>
<p><a href="https://heckin.technology/inherentlee/spoonfairies" target="_blank" title="source code">source</a></p>
</div>
<p class="year"><a href="/" title="home page">Spoonfairies 2026</a></p>
</footer>
<!-- This page `/team/` was built on 2026-09-23T23:25:06.281Z -->
</body>
</html>