a lot of stylin and a little scriptin

This commit is contained in:
Rhiannon Morris 2020-07-17 12:29:13 +02:00
parent 3635f04e8f
commit 64e00f83f1
16 changed files with 555 additions and 82 deletions

View file

@ -5,30 +5,44 @@ INFONAME = info.yaml
# SMALL = thumbnails, MED = single pages (link to full size)
SMALL := 200
MED := 1200
MED := 1000
MAKEPAGES = $(TMPDIR)/make-pages
YAMLS != find $(DATADIR) -iname "*.yaml"
YAMLS != find $(DATADIR) -name $(INFONAME)
all: make-pages $(BUILDDIR)/index.html
SCRIPTS := $(wildcard script/*.js)
STYLES := $(wildcard style/*.css style/*.png)
FONTS := $(shell find fonts \
-iname '*.eot' -or -iname '*.svg' -or \
-iname '*.ttf' -or -iname '*.woff' -or \
-iname '*.woff2' -or -iname '*.css')
STATIC := $(SCRIPTS) $(STYLES) $(FONTS)
BSTATIC := $(patsubst %,$(BUILDDIR)/%,$(STATIC))
all: make-pages $(BUILDDIR)/index.html $(BSTATIC)
$(BUILDDIR)/%: %
echo "[copy] "$@
mkdir -p $(dir $@)
cp $< $@
$(BUILDDIR)/index.html: $(DATADIR)/galleries.yaml $(MAKEPAGES)
echo "[index]"
mkdir -p $(dir $@)
$(MAKEPAGES) index $< -o $@
$(MAKEPAGES) $(MPFLAGS) index $< -o $@
$(MAKEPAGES): make-pages
$(MAKEPAGES): make-pages/*.hs make-pages/make-pages.cabal
echo "[make-pages]"
mkdir -p $(dir $@)
cabal v2-build all -O0
cabal v2-build all -O0 -j
find dist-newstyle -name make-pages -executable -type f \
-exec cp {} $@ \;
$(TMPDIR)/galleries.d: $(DATADIR)/galleries.yaml $(MAKEPAGES)
echo "[gallery-deps] "$@
echo "[deps] "$@
mkdir -p $(dir $@)
$(MAKEPAGES) depend-gallery $< -o $@ \
$(MAKEPAGES) $(MPFLAGS) depend-gallery $< -o $@ \
-B $(BUILDDIR) -D $(DATADIR) -T $(TMPDIR) -I $(INFONAME)
-include $(TMPDIR)/galleries.d

View file

@ -64,7 +64,8 @@ dependGallery' (GalleryInfo {title, prefix, filters}) infos' build data_ tmp =
$@path: $@files'
echo "[gallery] "$$@
mkdir -p $$(dir $$@)
$$(MAKEPAGES) gallery -t "$*title" -o "$$@" $$<
$$(MAKEPAGES) $$(MPFLAGS) gallery -t "$*title" -o "$$@" \
$$(filter $$(DATADIR)/%/$$(INFONAME),$$^)
$rules
@ -79,29 +80,29 @@ makeRules :: FilePath -- ^ prefix
-> Builder
makeRules prefix filters build data_ tmp = [b|@0
$@buildPrefix/%/index.html: $@data_/%/info.yaml
echo "[single] "$$@
echo "[single] "$$@
mkdir -p $$(dir $$@)
$$(MAKEPAGES) single "$$<" -o "$$@" $flags
$$(MAKEPAGES) $$(MPFLAGS) single "$$<" -o "$$@" $flags
$@tmpPrefix/%.d: $@data_/%/info.yaml
echo "[deps] "$$@
echo "[deps] "$$@
mkdir -p $$(dir $$@)
$$(MAKEPAGES) depend-single $flags \
$$(MAKEPAGES) $$(MPFLAGS) depend-single $flags \
-o "$$@" -p "$@prefix" -B "$@build" -D "$@data_" $$<
$@buildPrefix/%: $@data_/%
echo "[copy] "$$@
echo "[copy] "$$@
mkdir -p $$(dir $$@)
cp "$$<" "$$@"
$@buildPrefix/%_small.png: $@data_/%.png
echo "[resize] "$$@
echo "[resize] "$$@
mkdir -p $$(dir $$@)
convert -resize '$$(SMALL)x$$(SMALL)^' \
-gravity center -crop 1:1+0 "$$<" "$$@"
$@buildPrefix/%_med.png: $@data_/%.png
echo "[resize] "$$@
echo "[resize] "$$@
mkdir -p $$(dir $$@)
convert -resize '$$(MED)x$$(MED)>' "$$<" "$$@"
|]

View file

@ -21,6 +21,7 @@ make' title infos = [b|@0
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<link rel=stylesheet href=/style/gallery.css>
<title>$*title</title>

View file

@ -14,6 +14,7 @@ make' ginfos = [b|@0
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<link rel=stylesheet href=/style/index.css>
<title>gallery list</title>
@ -31,9 +32,11 @@ make' ginfos = [b|@0
items = map makeItem ginfos
makeItem :: GalleryInfo -> Builder
makeItem (GalleryInfo {title, prefix}) = [b|@4
<li>
<a href="$@prefix">
$*title
</a>
makeItem (GalleryInfo {title, prefix, filters}) = [b|@4
<li$nsfw><a href=$@prefix>$*title</a>
|]
where
nsfw = if hasNsfw filters then " class=nsfw" else ""
hasNsfw :: GalleryFilters -> Bool
hasNsfw (GalleryFilters {nsfw}) = nsfw /= Just False

View file

@ -1,3 +1,4 @@
{-# OPTIONS_GHC -fdefer-typed-holes #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Info
(Info (..), Artist (..), Image (..), Link (..),
@ -27,11 +28,11 @@ data Info =
date :: !Day,
title :: !(Maybe Text),
artist :: !(Maybe Artist), -- nothing = me, obv
warning :: !(Maybe Text),
tags :: ![Text],
nsfwTags :: ![Text],
description :: !(Maybe Text),
images :: ![Image],
background :: !(Maybe Text),
thumb' :: !(Maybe FilePath),
links :: ![Link]
}
@ -46,9 +47,10 @@ data Artist =
data Image =
Image {
label :: !Text,
path :: !FilePath,
nsfw :: !Bool
label :: !Text,
path :: !FilePath,
nsfw :: !Bool,
warning :: !(Maybe Text)
}
deriving (Eq, Show)
@ -80,11 +82,11 @@ instance FromYAML Info where
Info <$> m .: "date"
<*> m .:? "title"
<*> m .:? "artist"
<*> m .:? "warning"
<*> m .:? "tags" .!= []
<*> m .:? "nsfw-tags" .!= []
<*> m .:? "description"
<*> m .: "images"
<*> m .:? "background"
<*> m .:? "thumb"
<*> m .:? "links" .!= []
@ -95,10 +97,29 @@ instance FromYAML Artist where
Artist <$> m .: "name" <*> m .:? "url"
instance FromYAML Image where
parseYAML = labelledOptNsfw Image "path" "path"
parseYAML y = do
Pair label rest <- parseYAML y
asStr label rest <|> asObj label rest
where
asStr label = YAML.withStr "path" \(Text.unpack -> path) ->
pure $ Image {label, path, nsfw = False, warning = Nothing}
asObj label = YAML.withMap "image info" \m -> do
path <- m .: "path"
nsfw <- m .:? "nsfw" .!= False
warning <- m .:? "warning"
pure $ Image {label, path, nsfw, warning}
instance FromYAML Link where
parseYAML = labelledOptNsfw Link "url" "url"
parseYAML y = do
Pair title rest <- parseYAML y
asStr title rest <|> asObj title rest
where
asStr title = YAML.withStr "url" \url ->
pure $ Link {title, url, nsfw = False}
asObj title = YAML.withMap "link info" \m -> do
url <- m .: "url"
nsfw <- m .:? "nsfw" .!= False
pure $ Link {title, url, nsfw}
data GalleryInfo =
@ -166,33 +187,6 @@ instance (FromYAML a, FromYAML b) => FromYAML (Pair a b) where
_ -> fail "expected exactly one pair"
data OptNsfw a = NoNsfw !a | WithNsfw !a !Bool
appOptNsfw :: (a -> Bool -> b) -> OptNsfw a -> b
appOptNsfw f (NoNsfw x) = f x False
appOptNsfw f (WithNsfw x n) = f x n
labelledOptNsfw :: FromYAML a
=> (Text -> a -> Bool -> b)
-> String -- ^ name in \"expected\" message
-> Text -- ^ field name
-> YAML.Node YAML.Pos -> YAML.Parser b
labelledOptNsfw f name field y = do
Pair l n' <- parseYAML y
n <- parseOptNsfw name field n'
pure $ appOptNsfw (f l) n
parseOptNsfw :: FromYAML a
=> String -- ^ name in \"expected\" message
-> Text -- ^ field name
-> YAML.Node YAML.Pos -> YAML.Parser (OptNsfw a)
parseOptNsfw name field y = yes y <|> no y where
yes = YAML.withMap (name <> " & nsfw") \m ->
WithNsfw <$> m .: field
<*> m .:? "nsfw" .!= False
no = fmap NoNsfw . parseYAML
instance FromYAML Day where
parseYAML = YAML.withStr "date" \str ->
case readMaybe $ Text.unpack str of

View file

@ -30,29 +30,38 @@ make nsfw = toLazyText . make' nsfw
make' :: Bool -> Info -> Builder
make' nsfw (Info {date, title, artist, tags, nsfwTags,
description, images, links}) = [b|@0
description, images, background, links}) = [b|@0
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<link rel=stylesheet href=/style/single.css>
$titleTag
<header>
$titleHeader
$artistTag
<h2 class=date>$formattedDate</date>
<h2 class=date>$formattedDate</h2>
$buttonBar
</header>
<script async src=/script/single.js></script>
<main>
<a href="$@path0">
<img id=it src="$@path0'">
</a>
<figure id=mainfig$dataBg>
$warning'
<a id=mainlink href="$@path0">
<img id=mainimg src="$@path0'">
</a>
</figure>
$descSection
<section class=info>
$descSection
$tagsList
$tagsList
$linksList
$linksList
</section>
</main>
<footer>
@ -70,13 +79,21 @@ make' nsfw (Info {date, title, artist, tags, nsfwTags,
formattedDate = formatDate date
buttonBar = makeButtonBar (fromMaybe (Strict.pack path0) title) nsfw images
path0 = #path $ head images
image0 = head images
path0 = #path image0
path0' = pageFile path0
descSection = ifJust description makeDesc
tagsList = makeTags nsfw tags nsfwTags
linksList = extLinks nsfw links
dataBg = ifJust background \bg -> [b| data-bg="$*bg"|]
warning' = ifJust (#warning image0) \w -> [b|@4
<figcaption id=cw>
$*w
</figcaption>
|]
makeArtist :: Artist -> Builder
makeArtist (Artist {name, url}) =
[b|<h2 class=artist>by $artistLink</h2>|]
@ -86,11 +103,13 @@ makeArtist (Artist {name, url}) =
Nothing -> [b|$*name|]
makeDesc :: Strict.Text -> Builder
makeDesc desc = [b|@2
<div class=desc>
<h2>description</h2>
$4*desc
</div>
makeDesc desc = [b|@4
<section class=desc>
<h2>about</h2>
<div>
$8*desc
</div>
</section>
|]
ifJust :: Monoid b => Maybe a -> (a -> b) -> b
@ -106,9 +125,8 @@ makeButtonBar title nsfw allImages =
0 -> throw $ NoEligibleImages title
1 -> ""
_ -> [b|@2
<nav id=variants class=buttonbar>
<h2>alts</h2>
<ul id=variantlist>
<nav class=alts>
<ul id=altlist>
$6.alts
</ul>
</nav>
@ -119,10 +137,11 @@ makeButtonBar title nsfw allImages =
alts = map (uncurry altButton) $ zip [0..] images
altButton :: Int -> Image -> Builder
altButton i (Image {label, path, nsfw}) = [b|@6
altButton i (Image {label, path, nsfw, warning}) = [b|@6
<li$nsfwClass>
<input type=radio$checked id="$idLabel" name=variant
autocomplete=off value="$@path'">
autocomplete=off value="$@path'"
data-link="$@path"$warning'>
<label for="$idLabel">$*label</label>
|]
where
@ -130,6 +149,7 @@ altButton i (Image {label, path, nsfw}) = [b|@6
checked = if i == 0 then " checked" else ""
idLabel = escId label
path' = pageFile path
warning' = ifJust warning \w -> [b| data-warning="$*w"|]
escId :: Strict.Text -> Builder
escId = foldMap esc1 . Strict.unpack where
@ -140,13 +160,13 @@ escId = foldMap esc1 . Strict.unpack where
makeTags :: Bool -> [Strict.Text] -> [Strict.Text] -> Builder
makeTags nsfw sfwTags nsfwTags =
if null tags then "" else [b|@2
<div class=tags>
if null tags then "" else [b|@4
<section class=tags>
<h2>tags</h2>
<ul>
$6.tagList
$8.tagList
</ul>
</div>
</section>
|]
where
tagList = map makeTag tags
@ -155,13 +175,13 @@ makeTags nsfw sfwTags nsfwTags =
extLinks :: Bool -> [Link] -> Builder
extLinks nsfw allLinks =
if null links then "" else [b|@2
<div class=links>
if null links then "" else [b|@4
<section class=links>
<h2>links</h2>
<ul>
$6.linkList
$8.linkList
</ul>
</div>
</section>
|]
where
links = if nsfw then allLinks else filter #sfw allLinks

55
script/single.js Normal file
View file

@ -0,0 +1,55 @@
function defined(x) {
return x !== null && typeof x !== 'undefined';
}
function getById(id) { return document.getElementById(id); }
function setImage(src, href, cw) {
let mainfig = getById('mainfig');
let mainimg = getById('mainimg');
let mainlink = getById('mainlink');
let caption = getById('cw');
if (defined(caption) && defined(cw)) {
caption.innerHTML = cw;
} else if (defined(caption)) {
mainfig.removeChild(caption);
} else if (defined(cw)) {
let newCaption = document.createElement('figcaption');
newCaption.id = 'cw';
newCaption.innerHTML = cw;
newCaption.onclick = openCW;
mainfig.insertBefore(newCaption, mainlink);
}
mainimg.src = src;
mainlink.href= href;
}
function activateButton(button) {
setImage(button.value, button.dataset.link, button.dataset.warning);
}
function openCW() {
let mainfig = getById('mainfig');
let caption = getById('cw');
if (defined(caption)) {
mainfig.removeChild(caption);
}
}
function setup() {
for (let button of document.querySelectorAll('#altlist input')) {
button.onchange = function(e) {
if (button.checked) activateButton(button);
};
}
let caption = getById('cw');
if (defined(caption)) {
caption.onclick = openCW;
}
}
window.onload = setup;

BIN
style/18_plus.png (Stored with Git LFS) Normal file

Binary file not shown.

1
style/18_plus.svg Normal file
View file

@ -0,0 +1 @@
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.41421" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><clipPath id="a"><path clip-rule="evenodd" d="m0 0h32v32h-32z"/></clipPath><metadata/><path d="m0 0h32v32h-32z" fill="none"/><g clip-path="url(#a)"><circle cx="16" cy="16" r="16"/><circle cx="16" cy="16" fill="#e02a33" r="14"/><circle cx="16" cy="16" r="12"/><g fill="#fff" fill-rule="nonzero"><path d="m8.523 12.595-1.975 1.43v-2.418l1.975-1.481h2.23v11.748h-2.23z"/><path d="m16.321 22.061c-.693 0-1.311-.139-1.856-.417s-.974-.678-1.286-1.2-.468-1.124-.468-1.805v-.392c0-.533.125-1.024.375-1.472.249-.449.601-.803 1.055-1.064-.363-.216-.655-.52-.877-.911-.221-.392-.332-.843-.332-1.354v-.306c0-.579.139-1.113.418-1.601.278-.488.672-.877 1.183-1.166.511-.29 1.112-.434 1.805-.434.692 0 1.297.144 1.813.434.516.289.911.678 1.183 1.166.273.488.409 1.022.409 1.601v.306c0 .499-.114.948-.341 1.345s-.516.704-.868.92c.454.272.803.632 1.047 1.081.244.448.366.928.366 1.438v.392c0 .692-.156 1.3-.468 1.822s-.743.922-1.294 1.2c-.55.278-1.172.417-1.864.417zm.017-7.236c.386 0 .692-.128.919-.383s.341-.582.341-.979v-.323c0-.375-.117-.687-.349-.937-.233-.25-.537-.374-.911-.374-.375 0-.679.124-.911.374-.233.25-.349.562-.349.937v.323c0 .409.113.738.34.988.227.249.534.374.92.374zm0 5.346c.442 0 .797-.141 1.064-.425s.4-.664.4-1.141v-.409c0-.454-.133-.823-.4-1.106-.267-.284-.622-.426-1.064-.426-.432 0-.784.142-1.056.426-.272.283-.409.652-.409 1.106v.409c0 .465.131.843.392 1.132.261.29.619.434 1.073.434z"/><path d="m22.834 16.943h-2.073v-1.886h2.073v-2.073h1.886v2.073h2.073v1.886h-2.073v2.073h-1.886z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
style/18_plus_small.png (Stored with Git LFS) Normal file

Binary file not shown.

109
style/base.css Normal file
View file

@ -0,0 +1,109 @@
@import url(../fonts/muller/muller.css);
html {
--thumb-size: 200px;
--page-size: 1000px;
--back-dark: hsl(129, 54%, 54%);
--back-light: hsl(119, 69%, 69%);
--dark-tum: hsl(41, 41%, 79%);
--light-tum: hsl(47, 59%, 85%);
--lighter-tum: hsl(47, 74%, 89%);
--text-hue: 42;
--text: hsl(var(--text-hue), 25%, 24%);
--text-link: hsl(111, 30%, 42%);
--shadow: hsla(42, 25%, 24%, 40%);
--bheight: 121px;
--bplacement: 60vh;
background:
url(border.png) left 0% bottom calc(var(--bplacement) - var(--bheight))
repeat-x fixed,
linear-gradient(to top,
transparent var(--bplacement),
var(--back-light) var(--bplacement),
var(--back-dark))
fixed,
url(spots.png) repeat fixed,
linear-gradient(to top,
var(--dark-tum) 0vh,
var(--lighter-tum) var(--bplacement))
fixed;
color: var(--text);
font-family: Muller;
font-size: 16pt;
--red: hsla(340, 100%, 70%, 60%);
--green: hsla(93, 100%, 63%, 60%);
--yellow: hsla(60, 100%, 70%, 60%);
}
body {
margin: 2rem auto;
padding: 1em 1em 1.5em 1em;
border: 5px solid var(--dark-tum);
box-shadow: 0px 0px 50px var(--shadow);
background: var(--lighter-tum);
}
b { font-weight: 600; }
b b { font-weight: 900; }
h1, h2, h3 { font-weight: 900; }
h1 { font-size: 150%; }
h2 { font-size: 130%; }
h3 { font-size: 100%; }
h4 { font-size: 100%; font-weight: 600; }
header {
position: relative;
text-align: center;
margin: 0 0 1em 0;
--small: 90%;
}
header h1 {
font-size: 300%;
font-weight: 100;
margin: 0;
}
a {
color: var(--text-link);
font-weight: 500;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
ul {
padding-left: 1em;
}
ul > li {
list-style: '— ';
padding-left: 0;
}
section + section { margin-top: 1em; }
section > section + section { margin-top: 0.75em; }
h1[id] a, h2[id] a, h3[id] a, h4[id] a, h5[id] a {
color: inherit;
font-weight: inherit;
text-decoration: none;
}
h1[id]:hover::after,
h2[id]:hover::after,
h3[id]:hover::after,
h4[id]:hover::after,
h5[id]:hover::after {
content: ' §';
opacity: 60%;
}

BIN
style/border.png (Stored with Git LFS) Normal file

Binary file not shown.

65
style/gallery.css Normal file
View file

@ -0,0 +1,65 @@
@import url(base.css);
body {
max-width: 50em;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, var(--image-size));
grid-gap: 1.5em;
justify-content: center;
justify-items: center;
align-items: center;
--image-size: 200px;
--border-thickness: 2px;
padding: 0;
margin: 0;
}
.item {
list-style: none;
padding: 0;
margin: 0;
position: relative;
width: calc(var(--image-size) + 2 * var(--border-thickness));
height: calc(var(--image-size) + 2 * var(--border-thickness));
}
figure {
margin: 0;
padding: 0;
}
.item * {
transition: all 0.2s ease-in-out;
}
.item img {
border: 2px solid var(--text);
box-shadow: 0 0 10px var(--shadow);
}
.item figcaption {
width: calc(100% - 4 * var(--border-thickness));
margin: 0;
padding: var(--border-thickness);
position: absolute;
left: 0;
bottom: 0;
background: hsl(0, 0%, 100%, 75%);
text-shadow: 0 0 2px white;
border: 2px solid var(--text);
}
.item:hover img {
filter: contrast(120%);
}
.item:hover figcaption {
opacity: 20%;
transform: translate(-5%, 80%) rotateZ(7deg);
}

57
style/index.css Normal file
View file

@ -0,0 +1,57 @@
@import url(base.css);
body {
width: 40em;
}
.gallery-list {
display: grid;
grid-template-columns: repeat(2, 50%);
margin: 0;
padding: 0;
font-size: 150%;
font-weight: 600;
}
.gallery-list a {
display: block;
font-weight: inherit;
color: var(--text);
padding: 0.5em;
transition: all 0.25s ease-in-out;
}
.gallery-list a:hover {
transform: scale(110%);
text-decoration: none;
}
.gallery-list li {
list-style: none;
text-align: center;
background: var(--green);
}
.gallery-list li:nth-child(2n) {
border-left: 2px solid hsla(0, 0%, 100%, 30%);
}
.gallery-list li:nth-child(2n+1) {
border-right: 2px solid hsla(0, 0%, 100%, 30%);
}
.gallery-list .nsfw {
background: var(--red);
}
.nsfw a:after {
content: url(18_plus.png);
padding-left: 0.15em;
vertical-align: middle;
opacity: 75%;
}

141
style/single.css Normal file
View file

@ -0,0 +1,141 @@
@import url(base.css);
body {
max-width: calc(var(--page-size) + 200px);
position: relative;
}
.date, .artist {
font-weight: 400;
position: absolute;
top: 0.1em;
margin: 0;
padding: 0;
font-size: 100%;
font-style: oblique;
}
.date { right: 0.1em; }
.artist { left: 0.1em; }
#mainfig {
justify-content: center;
border: 2px solid var(--text);
margin: auto;
height: min-content;
width: min-content;
overflow: hidden;
position: relative;
}
#mainimg {
display: block;
}
#cw {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
font-size: 250%;
font-weight: 900;
color: white;
background: hsla(var(--text-hue), 35%, 15%, 80%);
mix-blend-mode: multiply;
display: flex;
justify-content: center;
align-items: center;
}
#cw::before {
content: 'cw:\A0'; /* nsbp */
font-weight: 600;
}
#cw + * img {
filter: blur(50px);
}
figcaption p {
margin: 0;
}
.info {
margin: 1em auto;
width: var(--page-size);
}
.info > section {
display: grid;
grid-gap: 1em;
grid-template-columns: 10em calc(var(--page-size) - 11em);
justify-content: center;
align-items: baseline;
margin: 1em;
}
.info h2 {
font-size: inherit;
font-weight: 500;
margin: 0;
justify-self: end;
}
.info ul, .alts ul {
display: flex;
align-items: center;
flex-wrap: wrap;
}
.alts ul {
justify-content: center;
}
.alts [type=checkbox], .alts [type=radio] {
display: none;
}
.alts :checked + label {
background: var(--yellow);
border-color: var(--text);
}
.alts .nsfw label::after {
content: url(18_plus_small.png);
vertical-align: middle;
padding-left: 0.15em;
}
.info ul {
padding: 0;
margin: 0;
}
.info li, .alts li {
list-style: none;
}
.info li, .alts label {
padding: 0 0.5em;
margin: 0 0.25em;
background: var(--light-tum);
border: 1px solid var(--dark-tum);
border-radius: 5px;
}
.info p:first-child {
margin-top: 0;
}
.info p {
margin: 0.25em 0;
}
footer {
font-size: 90%;
font-style: oblique;
text-align: center;
}

BIN
style/spots.png (Stored with Git LFS) Normal file

Binary file not shown.