2026-08-01 15:48:58 +00:00
<!doctype html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< link rel = "icon" type = "image/x-icon" href = "/favicon.ico" >
< title > loud table runner | hello hello</ title >
< meta name = "description" content = "Lee Cattarin... on the internet!" >
< link rel = "alternate" href = "/feed.xml" type = "application/atom+xml" title = "hello hello" >
< meta property = "og:title" content = "loud table runner | hello hello" >
< meta property = "og:type" content = "website" >
< meta property = "og:description" content = "Lee Cattarin... on the internet!" >
< meta property = "og:site_name" content = "hello hello" >
2026-08-26 23:55:56 +00:00
< meta property = "og:url" content = "https://leecat.art/loud-table-runner/" >
2026-08-01 15:48:58 +00:00
< meta property = "og:image" content = "/img/loud-table-runner.jpg" >
2026-08-01 15:50:30 +00:00
< meta property = "og:image:alt" content = "Folded long piece of fabric on a table. It is randomly mixed magenta, lime green, and wine purple, with occasional stripes of something glittery, fuzzy, or satiny in a variety of complementary colors. The ends have twisted fringe." >
2026-08-01 15:48:58 +00:00
< meta name = "generator" content = "Eleventy v3.1.2" >
< meta itemprop = "ai-content-declaration:version" content = "1.0.0" >
< meta itemprop = "ai-content-declaration:level" content = "none" >
< 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+Mono:ital,wght@0,200..800;1,200..800&family=Atkinson+Hyperlegible+Next:ital,wght@0,200..800;1,200..800&display=swap" rel = "stylesheet" >
< script src = "https://kit.fontawesome.com/884dded219.js" crossorigin = "anonymous" ></ script >
2026-09-08 17:40:59 +00:00
2026-09-11 18:57:10 +00:00
2026-08-01 15:48:58 +00:00
< style >. post-metadata {
display : flex ;
flex-flow : row wrap ;
justify-content : space-between ;
align-items : baseline ;
margin : 1.5 rem 0 .5 rem ;
}
. post-metadata p {
font-size : .9 rem ;
margin : 0 ;
}
. post-tags {
display : flex ;
flex-flow : row wrap ;
gap : .5 rem ;
list-style : none ;
margin : 0 ;
2026-08-25 20:13:52 +00:00
margin-left : auto ;
2026-08-01 15:48:58 +00:00
}
. post-tags li {
margin : 0 ;
}
. post-tags li a {
text-decoration : none ;
color : var ( -- color - teal );
padding : 0 .5 rem ;
border-radius : 1 rem ;
box-shadow : .15 rem .15 rem var ( -- color - shadow );
border : .08 rem solid var ( -- color - teal );
line-height : 2 ;
/* Click animation handling */
position : relative ;
top : 0 ;
left : 0 ;
transition : top .1 s ease-in , left .1 s ease-in ;
}
. post-tags li a : focus-visible {
outline : none ;
background-color : var ( -- color - teal );
color : var ( -- color - bg );
}
@ media ( any-hover : hover ) {
. post-tags li a : hover {
outline : none ;
background-color : var ( -- color - teal );
color : var ( -- color - bg );
}
}
@ media ( forced-colors : active ) {
. post-tags li a : focus-visible {
outline-offset : .08 rem ;
outline : .08 rem solid ;
}
@ media ( any-hover : hover ) {
. post-tags li a : hover {
outline-offset : .08 rem ;
outline : .08 rem solid ;
}
}
}
/* Click animation */
. post-tags li a : active {
top : .1 rem ;
left : .1 rem ;
box-shadow : .05 rem .05 rem var ( -- color - shadow );
}
# postlist ,
# taglist {
list-style : none ;
}
# postlist , . post ,
# taglist , . tag {
margin : 0 ;
}
/* Odd-numbered posts & tag layout/coloration */
. post : nth-child ( odd ) . postlink ,
. tag : nth-child ( odd ) . taglink {
grid-template-areas :
'img h2'
'img info'
'img .' ;
grid-template-columns : 45 % auto ;;
--color-primary : var ( -- color - teal );
--color-accent : var ( -- color - pink );
}
/* Even-numbered posts & tags layout/coloration */
. post : nth-child ( even ) . postlink ,
. tag : nth-child ( even ) . taglink {
grid-template-areas :
'h2 img'
'info img'
'. img' ;
grid-template-columns : auto 45 % ;
--color-primary : var ( -- color - pink );
--color-accent : var ( -- color - teal );
}
/* Layout for all posts on mobile */
@ media ( max-width : 650px ) {
. post : nth-child ( n ) . postlink ,
. tag : nth-child ( n ) . taglink {
grid-template-areas :
'img'
'h2'
'info' ;
grid-template-columns : auto ;
}
}
/* Link */
. postlink ,
. taglink {
display : grid ;
border : .25 rem solid var ( -- color - primary );
border-radius : 1.25 rem ;
box-shadow : .35 rem .35 rem var ( -- color - shadow );
margin : 2 rem 0 ;
text-decoration : none ;
/* Click animation handling */
position : relative ;
top : 0 ;
left : 0 ;
transition : top .05 s ease-in , left .05 s ease-in ;
}
. postlink : focus-visible ,
. taglink : focus-visible {
background-color : var ( -- color - primary );
outline : none ;
}
@ media ( any-hover : hover ) {
. postlink : hover ,
. taglink : hover {
background-color : var ( -- color - primary );
}
}
/* Forced colors */
@ media ( forced-colors : active ) {
. postlink : focus-visible ,
. taglink : focus-visible {
outline-offset : .25 rem ;
outline : .25 rem solid ;
}
@ media ( any-hover : hover ) {
. postlink : hover ,
. taglink : hover {
outline-offset : .25 rem ;
outline : .25 rem solid ;
}
}
}
/* Click animation */
. postlink : active ,
. taglink : active {
top : .2 rem ;
left : .2 rem ;
box-shadow : .15 rem .15 rem var ( -- color - shadow );
}
/* Post & tag elements */
. post h2 , . post img ,
. post ul , . post li ,
. tag h2 , . tag p ,
. tag img {
margin : 0 ;
}
. post h2 ,
. tag h2 {
grid-area : h2 ;
padding : .25 rem .5 rem ;
text-transform : uppercase ;
font-size : 1.5 rem ;
color : var ( -- color - primary );
border-radius : 1 rem 1 rem 0 0 ;
border-bottom : .25 rem solid var ( -- color - accent );
}
. post : nth-child ( even ) h2 ,
. tag : nth-child ( even ) h2 {
text-align : right ;
}
. postlink : focus-visible h2 ,
. taglink : focus-visible h2 {
color : var ( -- color - bg );
border-color : var ( -- color - bg );
}
@ media ( any-hover : hover ) {
. postlink : hover h2 ,
. taglink : hover h2 {
color : var ( -- color - bg );
border-color : var ( -- color - bg );
}
}
/* Images */
. post img ,
. tag-imgs {
grid-area : img ;
}
. blur {
filter : blur ( .75 rem );
clip-path : inset ( 0 round 1 rem );
}
. tag-imgs {
display : grid ;
grid-template-columns : repeat ( 2 , 1 fr );
gap : .15 rem ;
}
. tag-imgs img {
aspect-ratio : 3 / 2 ;
object-fit : cover ;
}
. missing-image {
width : 100 % ;
aspect-ratio : 3 / 2 ;
background-color : var ( -- color - bg - alt );
border-radius : 1 rem ;
}
. taglink : focus-visible . missing-image {
opacity : .7 ;
}
@ media ( any-hover : hover ) {
. taglink : hover . missing-image {
opacity : .7 ;
}
}
/* Post tags */
. postlist-tags {
grid-area : info ;
list-style : none ;
display : flex ;
flex-flow : row wrap ;
gap : .5 rem ;
padding : .5 rem ;
}
. post : nth-child ( odd ) . postlist-tags {
justify-content : flex-end ;
}
. postlist-tags li ,
. tagcount {
background-color : var ( -- color - primary );
color : var ( -- color - bg );
padding : 0 .5 rem ;
border-radius : 1 rem ;
}
. postlink : focus-visible . postlist-tags li ,
. taglink : focus-visible . tagcount {
background-color : var ( -- color - bg );
color : var ( -- color - primary );
}
@ media ( any-hover : hover ) {
. postlink : hover . postlist-tags li ,
. taglink : hover . tagcount {
background-color : var ( -- color - bg );
color : var ( -- color - primary );
}
}
/* Tag count */
. tag p {
grid-area : info ;
padding : .5 rem ;
}
. tag : nth-child ( odd ) p {
text-align : right ;
}
img [ tabindex = "0" ] {
cursor : pointer ;
}
img [ tabindex = "0" ] : focus-visible {
outline : .15 rem solid var ( -- color - teal );
}
dialog {
margin : auto ;
flex-flow : column ;
background : transparent ;
border : none ;
position : absolute ;
}
dialog [ open ] {
display : flex ;
}
dialog :: backdrop {
background-color : rgba ( from var ( -- color - bg ) r g b / .8 );
backdrop-filter : blur ( 4 px );
}
body : has ( dialog [ open ]) {
overflow : hidden ;
}
. close-dialog {
background-color : rgba ( from var ( -- color - teal ) r g b / .35 );
font-size : 1.5 rem ;
padding : 0 .5 rem .15 rem ;
border-radius : 1 rem ;
color : var ( -- color - teal );
box-shadow : .15 rem .15 rem var ( -- color - shadow );
border : .08 rem solid var ( -- color - teal );
align-self : flex-end ;
justify-self : flex-start ;
margin : 0 .1 rem ;
/* Click animation handling */
position : relative ;
top : 1 rem ;
left : -.15 rem ;
transition : top .1 s ease-in , left .1 s ease-in ;
}
. close-dialog : focus-visible {
outline : none ;
background-color : var ( -- color - teal );
color : var ( -- color - bg );
}
@ media ( any-hover : hover ) {
. close-dialog : hover {
outline : none ;
background-color : var ( -- color - teal );
color : var ( -- color - bg );
}
}
@ media ( forced-colors : active ) {
. close-dialog : focus-visible {
outline-offset : .08 rem ;
outline : .08 rem solid ;
}
@ media ( any-hover : hover ) {
. close-dialog : hover {
outline-offset : .08 rem ;
outline : .08 rem solid ;
}
}
}
/* Click animation */
. close-dialog : active {
top : 1.1 rem ;
left : -.05 rem ;
box-shadow : .05 rem .05 rem var ( -- color - shadow );
}
. modal-img {
2026-08-21 00:13:19 +00:00
max-height : calc ( 100 vh - 2 rem );
2026-08-01 15:48:58 +00:00
object-fit : contain ;
width : auto ;
max-width : 90 % ;
margin : 0 auto ;
}
: root {
color-scheme : light dark ;
--font-family : 'Atkinson Hyperlegible Next' , sans-serif ;
--font-family-code : 'Atkinson Hyperlegible Mono' , monospace ;
--color-dark : #2e303e ;
--color-dark-alt : #3c3f52 ;
--color-light : #ebeeef ;
--color-light-alt : #dbe1e3 ;
--color-teal-dark : #18737b ;
--color-teal-light : #25b0bc ;
--color-pink-dark : #94195d ;
--color-pink-light : #ee9fcb ;
--color-shadow : rgba ( 2 , 10 , 40 , .25 );
/* Used for syntax highlighting */
--color-red-light : #f195aa ;
--color-orange-light : #fab795 ;
--color-yellow-light : #fbe6bc ;
--color-green-light : #29d398 ;
--color-blue-light : #26bbd9 ;
--color-purple-light : #ddaeea ;
--color-grey-light : #b9c3c6 ;
--color-red-dark : #991433 ;
--color-orange-dark : #883206 ;
--color-yellow-dark : #6a4906 ;
--color-green-dark : #125940 ;
--color-blue-dark : #125663 ;
--color-purple-dark : #722999 ;
--color-grey-dark : #4a4b64 ;
--color-text : light-dark ( var ( -- color - dark ), var ( -- color - light ));
--color-bg : light-dark ( var ( -- color - light ), var ( -- color - dark ));
--color-text-alt : light-dark ( var ( -- color - dark - alt ), var ( -- color - light - alt ));
--color-bg-alt : light-dark ( var ( -- color - light - alt ), var ( -- color - dark - alt ));
--color-teal : light-dark ( var ( -- color - teal - dark ), var ( -- color - teal - light ));
--color-pink : light-dark ( var ( -- color - pink - dark ), var ( -- color - pink - light ));
--color-red : light-dark ( var ( -- color - red - dark ), var ( -- color - red - light ));
--color-orange : light-dark ( var ( -- color - orange - dark ), var ( -- color - orange - light ));
--color-yellow : light-dark ( var ( -- color - yellow - dark ), var ( -- color - yellow - light ));
--color-green : light-dark ( var ( -- color - green - dark ), var ( -- color - green - light ));
--color-blue : light-dark ( var ( -- color - blue - dark ), var ( -- color - blue - light ));
--color-purple : light-dark ( var ( -- color - purple - dark ), var ( -- color - purple - light ));
--color-grey : light-dark ( var ( -- color - grey - dark ), var ( -- color - grey - light ));
}
2026-09-09 20:38:19 +00:00
: root : has ( # theme-light : checked ) {
color-scheme : light ;
}
: root : has ( # theme-dark : checked ) {
color-scheme : dark ;
}
2026-08-01 15:48:58 +00:00
/* Base */
* {
box-sizing : border-box ;
margin : 0 ;
padding : 0 ;
}
body {
font-family : var ( -- font - family );
color : var ( -- color - text );
background-color : var ( -- color - bg );
}
main {
width : 60 vw ;
max-width : 1000 px ;
margin : 0 auto ;
scroll-margin-top : 7 rem ;
}
@ media ( max-width : 1050px ) {
main {
width : 75 vw ;
}
}
@ media ( max-width : 650px ) {
main {
width : 92 vw ;
}
}
/* Headers */
h1 , h2 , h3 , h4 , h5 , h6 {
line-height : 1.25 ;
color : var ( -- color - teal );
}
h1 {
margin-top : 3 rem ;
font-size : 3.5 rem ;
text-align : center ;
}
h2 , h3 , h4 , h5 , h6 {
scroll-margin-top : 5 rem ;
}
h2 {
margin-top : 2 rem ;
font-size : 2.2 rem ;
}
h3 {
margin-top : 1.5 rem ;
font-size : 1.6 rem ;
}
@ media ( max-width : 650px ) {
h1 { font-size : 2.8 rem ; }
h2 { font-size : 1.8 rem ; }
h3 { font-size : 1.35 rem ; }
}
h4 , h5 , h6 {
margin-top : 1 rem ;
font-size : 1.2 rem ;
}
/* Images */
img {
display : block ;
max-width : 100 % ;
height : auto ;
border-radius : 1 rem ;
margin : 0 auto ;
}
/* Paragraphs */
p {
margin : 1.25 rem 0 ;
line-height : 1.4 ;
}
strong ,
b {
font-weight : 900 ;
}
/* Links */
a {
color : var ( -- color - text );
border-radius : .25 rem ;
text-decoration : underline ;
text-decoration-style : solid ;
text-decoration-thickness : .2 em ;
text-decoration-color : var ( -- color - teal );
transition : text - decoration-thickness .5 s ;
}
a : focus-visible {
text-decoration : none ;
outline : .15 rem solid var ( -- color - teal );
}
@ media ( any-hover : hover ) {
a : hover {
text-decoration-thickness : .4 em ;
}
}
a : active {
text-decoration-thickness : .4 em ;
}
/* Heading anchors */
a . ha ,
span . ha-placeholder {
color : var ( -- color - pink );
font-size : .8 em ;
vertical-align : .1 em ;
}
span . ha-placeholder {
opacity : .55 ;
}
/* Lists */
:: marker {
color : var ( -- color - pink );
}
ul , ol , dl , li {
margin-left : 1 rem ;
}
@ media ( max-width : 650px ) {
ul , ol , dl {
margin-left : 0 ;
}
}
li {
2026-09-09 20:38:19 +00:00
line-height : 1.2 ;
2026-08-01 15:48:58 +00:00
margin-top : .65 rem ;
margin-bottom : .65 rem ;
}
li ul , li ol {
margin : .5 rem 0 ;
2026-09-08 17:34:46 +00:00
margin-left : 1 rem ;
}
@ media ( max-width : 650px ) {
li ul , li ol {
margin-left : 0 ;
}
2026-08-01 15:48:58 +00:00
}
dt {
font-weight : 900 ;
margin-top : .5 rem ;
}
dd {
margin-left : 2 rem ;
margin-bottom : .75 rem ;
}
/* Blockquotes */
blockquote {
margin : .5 rem 0 ;
padding : 0 1 rem ;
border-radius : .25 rem 1 rem 1 rem .25 rem ;
line-height : 1.25 ;
border-left : .5 rem solid var ( -- color - pink );
}
blockquote ,
blockquote p ,
blockquote ol ,
blockquote ul {
background-color : var ( -- color - bg - alt );
padding : .5 rem ;
}
blockquote p {
margin : 0 ;
}
/* Tables */
table {
width : 100 % ;
border-spacing : 0 ; /* border collapse doesn't play nice with radii */
border-radius : .3 rem ;
border : thin solid var ( -- color - pink );
2026-08-06 18:38:23 +00:00
margin : 1.25 rem 0 ;
2026-08-01 15:48:58 +00:00
}
th {
color : var ( -- color - bg );
background-color : var ( -- color - pink );
}
th code {
color : var ( -- color - text ); /* Yes, I actually do this somewhere */
}
th , td {
padding : .5 rem ;
text-align : left ;
}
tr : nth-child ( even ) { background-color : var ( -- color - bg - alt ); }
th : not ( : first-child ) { border-left : thin solid var ( -- color - bg ); }
th : first-child { border-top-left-radius : .25 rem ; }
th : last-child { border-top-right-radius : .25 rem ; }
td : not ( : first-child ) { border-left : thin solid var ( -- color - pink ); }
/* Times */
time {
color : var ( -- color - grey );
}
/* Horizontal rules */
hr {
border : .25 rem solid var ( -- color - pink );
margin : 2 rem 0 ;
}
/* Used on home, reference, gallery pages */
. centered {
text-align : center ;
}
/* Currently only used for resume, but it's generalizable */
. upper {
text-transform : uppercase ;
}
/* Header */
header {
background-color : var ( -- color - bg );
padding : .75 rem 0 ;
border-bottom : thick solid var ( -- color - teal );
box-shadow : 0 .25 rem .15 rem var ( -- color - shadow );
2026-09-11 18:57:10 +00:00
display : grid ;
grid-template-columns : auto ;
2026-08-01 15:48:58 +00:00
}
/* Header links, pagination links */
header a ,
. pagination a ,
. webring ul a {
border-radius : 1 rem ;
border : .125 rem solid var ( -- color - pink );
color : var ( -- color - pink );
text-decoration : none ;
padding : 0 .25 rem ;
box-shadow : .15 rem .15 rem var ( -- color - shadow );
font-size : 1.2 rem ;
/* Click animation handling */
position : relative ;
top : 0 ;
left : 0 ;
transition : top .05 s ease-in , left .05 s ease-in ;
}
header a ,
. pagination . older a ,
. webring . prev a ,
. webring . rand a {
padding-right : .35 rem ;
}
. pagination . newer a ,
. webring . next a ,
. webring . rand a {
padding-left : .35 rem ;
}
header a : focus-visible ,
. pagination a : focus-visible ,
. webring ul a : focus-visible {
color : var ( -- color - bg );
border-color : var ( -- color - pink );
background-color : var ( -- color - pink );
outline : none ;
}
@ media ( any-hover : hover ) {
header a : hover ,
. pagination a : hover ,
. webring ul a : hover {
color : var ( -- color - bg );
border-color : var ( -- color - pink );
background-color : var ( -- color - pink );
}
}
@ media ( forced-colors : active ) {
header a : focus-visible ,
. pagination a : focus-visible ,
. webring ul a : focus-visible {
outline-offset : .125 rem ;
outline : .125 rem solid ;
}
@ media ( any-hover : hover ) {
header a : hover ,
. pagination a : hover ,
. webring ul a : hover {
outline-offset : .125 rem ;
outline : .125 rem solid ;
}
}
}
/* Click animation */
header a : active ,
. pagination a : active ,
. webring ul a : active {
top : .1 rem ;
left : .1 rem ;
box-shadow : .05 rem .05 rem var ( -- color - shadow );
}
/* Current page */
header a [ aria-current = "page" ] {
border-color : var ( -- color - teal );
color : var ( -- color - teal );
}
header a [ aria-current = "page" ] : focus-visible {
color : var ( -- color - bg );
border-color : var ( -- color - teal );
background-color : var ( -- color - teal );
}
@ media ( any-hover : hover ) {
header a [ aria-current = "page" ] : hover {
color : var ( -- color - bg );
background-color : var ( -- color - teal );
border-color : var ( -- color - teal );
}
}
/* Header link icons, pagination icons */
header i ,
. pagination i ,
. webring ul i {
color : var ( -- color - teal );
}
header i ,
. pagination . older i ,
. webring . prev i ,
. webring . rand i : nth-child ( 1 ) {
padding-left : .25 rem ;
}
. pagination . newer i ,
. webring . next i ,
. webring . rand i : nth-child ( 2 ) {
padding-right : .25 rem ;
}
header a [ aria-current = "page" ] i {
color : var ( -- color - pink );
}
header a : focus-visible i ,
a [ aria-current = "page" ] a : focus-visible i ,
. pagination a : focus-visible i ,
. webring ul a : focus-visible i {
color : var ( -- color - bg );
}
@ media ( any-hover : hover ) {
header a : hover i ,
header a [ aria-current = "page" ] : hover i ,
. pagination a : hover i ,
. webring ul a : hover i {
color : var ( -- color - bg );
}
}
/* Skip link */
# skip {
left : -999 px ;
position : absolute ;
top : auto ;
width : 1 px ;
height : 1 px ;
overflow : hidden ;
z-index : -99 ;
}
# skip : focus-visible {
display : inline-block ;
left : auto ;
top : auto ;
width : auto ;
height : auto ;
overflow : auto ;
2026-09-11 18:57:10 +00:00
margin : -.125 rem 10 % ;
2026-08-01 15:48:58 +00:00
z-index : 999 ;
}
/* Nav */
header ul {
display : flex ;
list-style : none ;
gap : 1 rem ;
justify-content : center ;
}
header ul ,
header li {
margin : 0 ;
}
@ media ( max-width : 650px ) {
. menu-text {
display : none ; /* Icons only on small screens */
}
header a {
padding : .15 rem .5 rem ;
}
header i {
padding : 0 ;
}
}
/* Footer */
footer {
padding : 1 rem 0 ;
font-size : .9 rem ;
border-top : thick solid var ( -- color - pink );
margin-top : 2 rem ;
}
footer ul {
display : flex ;
list-style : none ;
gap : .5 rem ;
justify-content : center ;
margin : 0 ;
}
footer li {
margin : 0 ;
}
footer li : nth-child ( 2 ) :: before ,
footer li : nth-child ( 2 ) :: after {
content : " ● " / "" ;
color : var ( -- color - teal );
}
@ media ( max-width : 650px ) {
footer ul {
flex-flow : column ;
text-align : center ;
}
footer li : nth-child ( 2 ) :: before ,
footer li : nth-child ( 2 ) :: after {
content : none ;
}
}
footer a {
text-decoration-color : var ( -- color - pink );
}
footer a : focus-visible {
outline-color : var ( -- color - pink );
}
2026-09-09 20:38:19 +00:00
/* color picker */
# theme {
display : flex ;
justify-content : center ;
margin : .5 rem auto 0 ;
padding : 0 .75 rem .5 rem ;
width : fit-content ;
border : .125 rem solid var ( -- color - teal );
border-radius : 2 rem ;
}
# theme legend {
margin : 0 auto ;
color : var ( -- color - teal );
}
footer label {
cursor : pointer ;
border : .125 rem solid var ( -- color - pink );
padding : 0 .25 rem ;
color : var ( -- color - pink );
background-color : var ( -- color - bg ); /* this stops the box shadows from showing through */
box-shadow : .15 em .15 em var ( -- color - shadow );
/* Click animation handling */
position : relative ;
top : 0 ;
left : 0 ;
transition : top .05 s ease-in , left .05 s ease-in ;
}
footer input : checked + label {
color : var ( -- color - blue );
border-color : var ( -- color - blue );
}
footer label i {
color : var ( -- color - teal );
}
footer input : checked + label i {
color : var ( -- color - pink );
}
@ media ( any-hover : hover ) {
footer label : hover ,
footer input : checked + label : hover ,
footer label : hover i ,
footer input : checked + label : hover i {
color : var ( -- color - bg );
}
footer label : hover {
background-color : var ( -- color - pink );
}
footer input : checked + label : hover {
background-color : var ( -- color - teal );
}
}
footer input : focus-visible + label ,
footer input : focus-visible + label i {
color : var ( -- color - bg );
background-color : var ( -- color - pink );
border-color : var ( -- color - pink );
}
footer input : checked : focus-visible + label ,
footer input : checked : focus-visible + label i {
color : var ( -- color - bg );
background-color : var ( -- color - teal );
border-color : var ( -- color - teal );
}
footer label : active {
top : .09 em ;
left : .09 em ;
box-shadow : .05 em .05 em var ( -- color - shadow );
}
label . theme-light {
border-top-left-radius : 1 rem ;
border-bottom-left-radius : 1 rem ;
border-right : none ;
padding-left : .35 rem ;
}
label . theme-auto {
}
label . theme-dark {
border-top-right-radius : 1 rem ;
border-bottom-right-radius : 1 rem ;
border-left : none ;
padding-right : .35 rem ;
}
footer input {
/* To allow screen reader to still access these. */
/* From https://lyra.horse/blog/2025/08/you-dont-need-js/ */
opacity : 0 ;
position : absolute ;
pointer-events : none ;
}
2026-08-01 15:48:58 +00:00
/* Pagination */
. pagination ,
. pagination li {
margin : 0 ;
}
. pagination {
display : grid ;
grid-template-columns : repeat ( 2 , 1 fr );
grid-template-areas : "older newer" ;
list-style : none ;
margin-top : 3 rem ;
}
@ media ( max-width : 650px ) {
. post-pagination {
grid-template-columns : 1 fr ;
grid-template-areas :
"older"
"newer" ;
gap : .75 rem ;
}
}
. pagination . older {
grid-area : older ;
}
. pagination . newer {
grid-area : newer ;
text-align : right ;
}
/* webring navigation */
. webring {
margin-bottom : 3 rem ;
}
. webring ul {
display : flex ;
flex-flow : row wrap ;
list-style : none ;
2026-08-28 19:00:43 +00:00
justify-content : center ;
gap : .5 rem ;
2026-08-01 15:48:58 +00:00
}
. webring ul ,
. webring li {
margin-left : 0 ;
}
2026-09-11 18:57:10 +00:00
/* Handle color schemes */
: root : has ( # theme-light : checked ) . dark {
display : none ;
}
: root : has ( # theme-dark : checked ) . light {
display : none ;
}
@ media ( prefers-color-scheme : light ) {
: root : not ( : has ( # theme-dark : checked )) . dark {
display : none ;
}
}
@ media ( prefers-color-scheme : dark ) {
: root : not ( : has ( # theme-light : checked )) . light {
display : none ;
}
}
. searchbox {
margin : 1 rem auto 0 ;
}
pagefind-searchbox {
/* Shadows */
--pf-scroll-shadow : var ( -- color - shadow ) !important ;
--pf-shadow-sm : .15 rem .15 rem 0 var ( -- color - shadow ) !important ;
--pf-shadow-md : .25 rem .25 rem 0 var ( -- color - shadow ) !important ;
--pf-shadow-lg : 1 rem 1 rem 0 var ( -- color - shadow ) !important ;
/* Typography */
--pf-font : var ( -- font - family ) !important ;
/* Border */
--pf-border-radius : 1.5 rem !important ;
/* Focus */
--pf-outline-width : .125 rem !important ;
--pf-outline-offset : 0 !important ;
/* Width */
--pf-searchbox-max-width : min ( 550 px , 92 vw ) !important ;
}
. light pagefind-searchbox {
--pf-text : var ( -- color - dark ) !important ;
--pf-text-secondary : var ( -- color - dark - alt ) !important ;
--pf-text-muted : var ( -- color - dark - alt ) !important ;
--pf-background : var ( -- color - light - alt ) !important ;
--pf-border : var ( -- color - pink - dark ) !important ;
--pf-border-focus : var ( -- color - pink - dark ) !important ;
--pf-skeleton : var ( -- color - light ) !important ;
--pf-skeleton-shine : var ( -- color - dark ) !important ;
--pf-hover : var ( -- color - light ) !important ;
--pf-mark : var ( -- color - teal - dark ) !important ;
--pf-outline-focus : var ( -- color - teal - dark ) !important ;
/* Error */
--pf-error-bg : var ( -- color - light - alt ) !important ;
--pf-error-border : var ( -- color - red - dark ) !important ;
--pf-error-text : var ( -- color - red - dark ) !important ;
--pf-error-text-secondary : var ( -- color - red - dark ) !important ;
}
. dark pagefind-searchbox {
--pf-text : var ( -- color - light ) !important ;
--pf-text-secondary : var ( -- color - light - alt ) !important ;
--pf-text-muted : var ( -- color - light - alt ) !important ;
--pf-background : var ( -- color - dark - alt ) !important ;
--pf-border : var ( -- color - pink - light ) !important ;
--pf-border-focus : var ( -- color - pink - light ) !important ;
--pf-skeleton : var ( -- color - dark ) !important ;
--pf-skeleton-shine : var ( -- color - dark ) !important ;
--pf-hover : var ( -- color - dark ) !important ;
--pf-mark : var ( -- color - teal - light ) !important ;
--pf-outline-focus : var ( -- color - teal - light ) !important ;
/* Error */
--pf-error-bg : var ( -- color - dark - alt ) !important ;
--pf-error-border : var ( -- color - red - light ) !important ;
--pf-error-text : var ( -- color - red - light ) !important ;
--pf-error-text-secondary : var ( -- color - red - light ) !important ;
}
pagefind-searchbox input {
border-width : .125 rem !important ;
}
pagefind-searchbox input : not ( : focus-visible ) {
box-shadow : var ( -- pf - shadow - md ) !important ;
}
. pf-searchbox-dropdown ,
. pf-searchbox-footer {
border-width : .125 rem !important ;
}
. pf-error {
margin-top : .5 rem !important ;
}
2026-09-08 17:40:59 +00:00
/* Adapted from PrismJS 1.30.0 Tomorrow Night theme
https://prismjs.com/download
*/
code ,
pre ,
code [ class *= language- ],
pre [ class *= language- ] {
font-family : var ( -- font - family - code );
background-color : var ( -- color - bg - alt );
font-size : .9 em ;
text-shadow : 0 1 px var ( -- color - shadow );
-moz- tab-size : 4 ;
-o- tab-size : 4 ;
tab-size : 4 ;
-webkit- hyphens : none ;
-moz- hyphens : none ;
-ms- hyphens : none ;
hyphens : none ;
}
pre ,
pre [ class *= language- ] {
margin : 1 rem 0 ;
padding : 1 rem ;
line-height : 1.5 ;
white-space : pre-wrap ;
word-break : break-word ;
overflow-wrap : break-word ;
border-radius : .5 rem ;
overflow : auto ;
}
: not ( pre )> code ,
: not ( pre )> code [ class *= language- ] {
padding : .2 rem ;
border-radius : .25 rem ;
white-space : normal ;
}
/* Selected text */
code :: -moz-selection ,
code :: -moz-selection ,
pre :: -moz-selection ,
pre :: -moz-selection ,
code [ class *= language- ] :: -moz-selection ,
code [ class *= language- ] :: -moz-selection ,
pre [ class *= language- ] :: -moz-selection ,
pre [ class *= language- ] :: -moz-selection ,
code :: selection ,
code :: selection ,
pre :: selection ,
pre :: selection ,
code [ class *= language- ] :: selection ,
code [ class *= language- ] :: selection ,
pre [ class *= language- ] :: selection ,
pre [ class *= language- ] :: selection {
text-shadow : none ;
background-color : var ( -- color - bg );
}
/* Syntax highlighting */
. token . namespace {
opacity : .7 ;
}
. token . bold ,
. token . important {
font-weight : 700
}
. token . italic {
font-style : italic
}
. token . block-comment ,
. token . cdata ,
. token . comment ,
. token . doctype ,
. token . prolog ,
. token . punctuation {
color : var ( -- color - grey );
}
. token . attr-name ,
. token . deleted ,
. token . namespace ,
. token . tag {
color : var ( -- color - red );
}
. token . boolean ,
. token . function ,
. token . number {
color : var ( -- color - orange );
}
. token . class-name ,
. token . constant ,
. token . property ,
. token . symbol {
color : var ( -- color - yellow );
}
. token . attr-value ,
. token . char ,
. token . regex ,
. token . string ,
. token . variable ,
. token . inserted {
color : var ( -- color - green );
}
. token . entity ,
. token . operator ,
. token . url ,
. token . function-name {
color : var ( -- color - blue );
}
. token . atrule ,
. token . builtin ,
. token . important ,
. token . keyword ,
. token . selector {
color : var ( -- color - purple );
}
2026-08-01 15:48:58 +00:00
@ media print {
/* Nav elements */
header ,
footer ,
nav {
display : none !important ;
}
/* Base */
body {
background-color : #fff ;
color : #000 ;
}
main {
width : 95 vw ;
}
h1 , h2 , h3 , h4 , h5 , h6 {
color : #000 ;
}
/* Links */
/* Hover is not really necessary, but it's annoying when testing otherwise */
a ,
a : hover {
text-decoration-style : dotted ;
text-decoration-thickness : .1 rem ;
text-decoration-color : #000 ;
}
a :: after {
content : " (" attr ( href ) ")" ;
}
/* Code */
code ,
pre ,
code [ class *= language- ],
pre [ class *= language- ] {
text-shadow : none ;
background-color : var ( -- color - light );
color : #000 !important ;
}
. token . namespace {
opacity : 1 ;
}
. token . block-comment ,
. token . cdata ,
. token . comment ,
. token . doctype ,
. token . prolog ,
. token . punctuation ,
. token . attr-name ,
. token . deleted ,
. token . namespace ,
. token . tag ,
. token . boolean ,
. token . function ,
. token . number ,
. token . class-name ,
. token . constant ,
. token . property ,
. token . symbol ,
. token . attr-value ,
. token . char ,
. token . regex ,
. token . string ,
. token . variable ,
. token . inserted ,
. token . entity ,
. token . operator ,
. token . url ,
. token . function-name ,
. token . atrule ,
. token . builtin ,
. token . important ,
. token . keyword ,
. token . selector {
color : #000 ;
}
}</ style >
2026-09-09 20:38:19 +00:00
2026-08-01 15:48:58 +00:00
< 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 );
}
}
}
/* no longer used, using aria-labelledby instead - see getAnchorElement
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 . innerHTML = content ; // CHANGED HERE
}
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 aria-labelledby= ${ heading . id } > ${ content } </span>` ; // CHANGED HERE
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 }
/* don't even bother on mobile */
if ( window . innerWidth > 650 ) {
const dialog = document . querySelector ( "dialog" );
const closeButton = document . querySelector ( ".close-dialog" );
const hero = document . querySelector ( ".hero" );
hero . tabIndex = 0 ;
hero . addEventListener ( "click" , ( e ) => dialog . showModal ());
hero . addEventListener ( "keydown" , ( e ) => {
if ( e . key === "Enter" || e . key === " " ) {
e . preventDefault ();
dialog . showModal ();
}
});
closeButton . addEventListener ( "click" , ( e ) => dialog . close ());
closeButton . addEventListener ( "keydown" , ( e ) => {
if ( e . key === "Enter" || e . key === " " ) {
e . preventDefault ();
dialog . close ();
}
});
2026-09-09 20:38:19 +00:00
}
const THEME = "theme" ;
const saveTheme = ( themeValue ) => {
localStorage . setItem ( THEME , themeValue );
};
const themeLight = document . getElementById ( "theme-light" );
themeLight . addEventListener ( "input" , ( e ) => {
saveTheme ( themeLight . value );
});
const themeAuto = document . getElementById ( "theme-auto" );
themeAuto . addEventListener ( "input" , ( e ) => {
saveTheme ( themeAuto . auto );
});
const themeDark = document . getElementById ( "theme-dark" );
themeDark . addEventListener ( "input" , ( e ) => {
saveTheme ( themeDark . value );
});
var currentThemeValue = localStorage . getItem ( THEME );
switch ( currentThemeValue ) {
case "light" :
themeLight . checked = true ;
2026-09-09 21:03:37 +00:00
themeAuto . checked = false ;
2026-09-09 20:38:19 +00:00
break ;
case "dark" :
themeDark . checked = true ;
2026-09-09 21:03:37 +00:00
themeAuto . checked = false ;
2026-09-09 20:38:19 +00:00
break ;
2026-09-09 21:03:37 +00:00
case "auto" :
2026-09-09 20:38:19 +00:00
default :
themeAuto . checked = true ;
2026-08-01 15:48:58 +00:00
}</ script >
2026-09-11 18:57:10 +00:00
< link href = "/pagefind/pagefind-component-ui.css" rel = "stylesheet" >
< script src = "/pagefind/pagefind-component-ui.js" type = "module" ></ script >
2026-08-01 15:48:58 +00:00
</ head >
< body >
< header >
< a href = "#main" id = "skip" title = "skip to main content" >
< i class = "fa-solid fa-forward" aria-hidden = "true" ></ i > skip
</ a >
< nav aria-label = "main navigation" >
< ul >
< li >
< a href = "/reference/" title = "read reference posts" >
< i class = "fa-regular fa-folder-open" aria-hidden = "true" ></ i >
< span class = "menu-text" > reference</ span >
</ a >
</ li >
< li >
< a href = "/gallery/" title = "view the gallery" >
< i class = "fa-regular fa-images" aria-hidden = "true" ></ i >
< span class = "menu-text" > gallery</ span >
</ a >
</ li >
< li >
< a href = "/" title = "home" >
< i class = "fa fa-solid fa-crow" aria-hidden = "true" ></ i >
< span class = "menu-text" > home</ span >
</ a >
</ li >
< li >
< a href = "/about/" title = "about Lee" >
< i class = "fa-regular fa-user" aria-hidden = "true" ></ i >
< span class = "menu-text" > about</ span >
</ a >
</ li >
< li >
< a href = "/contact/" title = "contact Lee" >
< i class = "fa-solid fa-envelope-open-text" aria-hidden = "true" ></ i >
< span class = "menu-text" > contact</ span >
</ a >
</ li >
</ ul >
</ nav >
2026-09-11 18:57:10 +00:00
< div class = "dark searchbox" data-pf-theme = "dark" >
< pagefind-searchbox ></ pagefind-searchbox >
</ div >
< div class = "light searchbox" >
< pagefind-searchbox ></ pagefind-searchbox >
</ div >
2026-08-01 15:48:58 +00:00
</ header >
2026-09-11 18:57:10 +00:00
< main id = "main" data-pagefind-body = "" >
2026-08-01 15:48:58 +00:00
< heading-anchors content = "<i class='fa-solid fa-anchor'></i>" >
< article >
< h1 id = "loud-table-runner" > loud table runner</ h1 >
< div class = "post-metadata" >
< p >
posted on
< time datetime = "2026-08-01" > August 1, 2026</ time >
by Lee Cattarin
</ p >
< ul class = "post-tags" >
< li >
< a href = "/tags/weaving/" > weaving</ a >
</ li >
</ ul >
</ div >
< dialog closedby = "any" aria-label = "image modal" tabindex = "-1" >
< button class = "close-dialog" autofocus = "" aria-label = "close the image modal" > × </ button >
2026-08-01 15:50:30 +00:00
< img class = "modal-img" src = "/img/loud-table-runner.jpg" alt = "Folded long piece of fabric on a table. It is randomly mixed magenta, lime green, and wine purple, with occasional stripes of something glittery, fuzzy, or satiny in a variety of complementary colors. The ends have twisted fringe." loading = "lazy" decoding = "async" width = "1000" height = "750" >
2026-08-01 15:48:58 +00:00
</ dialog >
2026-08-01 15:50:30 +00:00
< img class = "hero" src = "/img/loud-table-runner.jpg" alt = "Folded long piece of fabric on a table. It is randomly mixed magenta, lime green, and wine purple, with occasional stripes of something glittery, fuzzy, or satiny in a variety of complementary colors. The ends have twisted fringe." loading = "lazy" decoding = "async" width = "1000" height = "750" >
2026-08-01 15:48:58 +00:00
< p > Yarn: < a href = "https://woolery.com/products/circulo-natural-cotton-maxcolor-4-6-yarn" target = "_blank" rel = "external" > Circulo Natural Cotton Maxcolor 4/6 Yarn</ a > with occasional stripes of < a href = "https://woolery.com/products/feza-alp-premier-yarn" target = "_blank" rel = "external" > Fez Alpa</ a > .</ p >
< p > About 11" wide and 5' long including tassels.</ p >
</ article >
< nav aria-label = "pagination" >
< ol class = "pagination post-pagination" >
< li class = "older" >
< a href = "/log-cabin-dishtowels/" >
< i class = "fa-solid fa-hand-point-left" aria-hidden = "true" ></ i > log cabin dishtowels
</ a >
</ li >
2026-08-06 18:38:23 +00:00
< li class = "newer" >
< a href = "/visual-site-builders-and-accessibility/" >
visual site builders and accessibility < i class = "fa-solid fa-hand-point-right" aria-hidden = "true" ></ i >
</ a >
</ li >
2026-08-01 15:48:58 +00:00
</ ol >
</ nav >
< hr >
2026-08-21 00:13:19 +00:00
< section class = "related-posts" >
< h2 data-ha-exclude = "" id = "related-posts" > related posts</ h2 >
< ol id = "postlist" >
2026-09-09 20:38:19 +00:00
< li class = "post" >
< a class = "postlink" href = "/pink-lime-and-grey-shawl/" >
< h2 data-ha-exclude = "" id = "pink-lime-and-grey-shawl" > pink, lime, and grey shawl </ h2 >
< ul class = "postlist-tags" >
< li > weaving</ li >
</ ul >
< img src = "/img/pink-lime-grey-shawl.jpg" alt = "2 image collage. Top image shows a shawl folded once on a large table, with three cones of yarn on top. It is plain weave with lime and pink warp and grey weft with alternating lime and pink stripes, and has about 4 inches of fringe at both ends. Bottom image is a closer picture of the weave." loading = "lazy" decoding = "async" width = "1000" height = "1777" >
</ a >
</ li >
2026-09-10 21:23:21 +00:00
< li class = "post" >
< a class = "postlink" href = "/rainbow-shawl/" >
< h2 data-ha-exclude = "" id = "rainbow-shawl" > rainbow shawl </ h2 >
< ul class = "postlist-tags" >
< li > weaving</ li >
</ ul >
< img src = "/img/rainbow-shawl.jpg" alt = "a woven shawl draped over a tree. the warp is a six-stripe rainbow, while the weft is a variety of neutral beige-brown tones, resulting in a muted rainbow." loading = "lazy" decoding = "async" width = "1000" height = "1333" >
</ a >
</ li >
2026-09-11 18:57:10 +00:00
< li class = "post" >
< a class = "postlink" href = "/houndstooth-dishtowels/" >
< h2 data-ha-exclude = "" id = "houndstooth-dishtowels" > houndstooth dishtowels </ h2 >
< ul class = "postlist-tags" >
< li > weaving</ li >
</ ul >
< img src = "/img/houndstooth-dishtowels.jpg" alt = "A two image collage. Image one shows a laid out dishtowel with two folded ones and several weaving shuttles (the pieces that hold the yarn to weave with) on top in the same colors as the towels. The pattern is a small houndstooth, repeated interlocking diamonds in dark and light tones. The dark tone is always navy; the light tones are either beige, yellow, or crossed beige and yellow depending on the section of the towel. All towels have an inch and a half fringe along the long edges. Image two is a close up of the pattern." loading = "lazy" decoding = "async" width = "1000" height = "750" >
</ a >
</ li >
2026-08-21 00:13:19 +00:00
</ ol >
</ section >
2026-08-01 15:48:58 +00:00
</ heading-anchors >
</ main >
< footer >
< ul >
< li >
< a href = "/colophon/" >
colophon
</ a >
</ li >
< li >
< a href = "/" title = "go home" aria-label = "go home | hello hello from Lee Cattarin, copyright 2022-2026" >
hello hello from Lee Cattarin, © 2022-2026</ a >
</ li >
< li >
< a href = "https://heckin.technology/inherentlee/leecat.art" title = "source code" aria-label = "source code" target = "_blank" rel = "external" >
src
</ a >
</ li >
</ ul >
2026-09-09 20:38:19 +00:00
< fieldset id = "theme" >
< legend > color scheme</ legend >
< input type = "radio" id = "theme-light" name = "theme" value = "light" >
< label class = "theme-light" for = "theme-light" >
< i class = "fa-regular fa-sun" aria-hidden = "true" ></ i >
light
</ label >
2026-09-09 21:03:37 +00:00
< input type = "radio" id = "theme-auto" name = "theme" value = "auto" checked = "" >
2026-09-09 20:38:19 +00:00
< label class = "theme-auto" for = "theme-auto" >
auto
</ label >
< input type = "radio" id = "theme-dark" name = "theme" value = "dark" >
< label class = "theme-dark" for = "theme-dark" >
dark
< i class = "fa-regular fa-moon" aria-hidden = "true" ></ i >
</ label >
</ fieldset >
2026-08-01 15:48:58 +00:00
</ footer >
2026-09-11 18:57:10 +00:00
<!-- This page `/loud-table-runner/` was built on 2026-09-11T18:56:54.969Z -->
2026-08-01 15:48:58 +00:00
</ body >
</ html >