From 0111a1b06da1bfb0ec1eff46befe28387745ca17 Mon Sep 17 00:00:00 2001 From: prosolis <5590409+prosolis@users.noreply.github.com> Date: Sun, 24 May 2026 22:43:03 -0700 Subject: [PATCH] Local mode, Makefile, image fixes, Pete avatar - Add -local flag: web/RSS-only mode that skips Matrix login and posting, so the web UI can be exercised against live feeds without credentials - Add Makefile (build/local/seed/test/clean) that handles Tailwind + go build in one shot - Fix Guardian thumbnails: NormalizeImageURL was rewriting width=1200 onto signed i.guim.co.uk URLs, invalidating the s= signature and returning 401. Leave signed URLs alone and pick the widest media:content variant up front instead - Use pete.avif as the header logo, favicon, and footer mark; drop the unused leaf.svg --- Makefile | 25 +++++++++++++++ README.md | 1 + internal/ingestion/image.go | 7 +++++ internal/ingestion/parser.go | 37 ++++++++++++++++------ internal/web/static/css/output.css | 2 +- internal/web/static/img/leaf.svg | 4 --- internal/web/static/img/pete.avif | Bin 0 -> 7991 bytes internal/web/templates/layout.html | 7 +++-- main.go | 48 +++++++++++++++++++++++++++++ pete.avif | Bin 0 -> 7991 bytes 10 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 Makefile delete mode 100644 internal/web/static/img/leaf.svg create mode 100644 internal/web/static/img/pete.avif create mode 100644 pete.avif diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..be83144 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +.PHONY: build css go-build local seed test clean + +build: css go-build + +css: node_modules + npm run build:css + +node_modules: package.json package-lock.json + npm install + @touch node_modules + +go-build: + go build -tags goolm -o pete . + +local: build + ./pete -local + +seed: build + ./pete -seed + +test: + go test ./... + +clean: + rm -f pete internal/web/static/css/output.css diff --git a/README.md b/README.md index cc0bbf4..7fe7b6e 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ With a 4-hour cadence Pete will post at most 6 stories/day, so set `posting.dail | `-config ` | Path to config file (default: `config.toml`) | | `-seed` | Ingest all current feed items as seen without posting, then exit | | `-test` | Post one story to verify the full pipeline, then exit | +| `-local` | Web/RSS-only mode: poll feeds and serve the web UI on `web.listen_addr`. Skips Matrix login and posting — useful for local testing | ## Docker diff --git a/internal/ingestion/image.go b/internal/ingestion/image.go index e5e1bc3..3f036db 100644 --- a/internal/ingestion/image.go +++ b/internal/ingestion/image.go @@ -24,6 +24,13 @@ func NormalizeImageURL(raw string) string { if q.Get("width") == "" { return raw } + // The Guardian signs each (width, quality, fit, …) combination with `s=`. + // Changing width without re-signing yields a 401 "invalid signature", + // so leave signed URLs alone — the parser is now responsible for picking + // the widest media:content variant up front. + if q.Get("s") != "" { + return raw + } q.Set("width", "1200") u.RawQuery = q.Encode() return u.String() diff --git a/internal/ingestion/parser.go b/internal/ingestion/parser.go index 20c2043..bfa0b3d 100644 --- a/internal/ingestion/parser.go +++ b/internal/ingestion/parser.go @@ -6,10 +6,12 @@ import ( "log/slog" "net/http" "regexp" + "strconv" "strings" "time" "github.com/mmcdole/gofeed" + ext "github.com/mmcdole/gofeed/extensions" ) const userAgent = "Pete/1.0 (newsbot; +https://github.com/reala-misaki/pete)" @@ -88,21 +90,19 @@ func extractLede(desc string) string { // scraped from content:encoded / description (catches feeds like Ars that // embed the lead image in the article body but not as a media:* element). func extractImageURL(item *gofeed.Item) string { - // Check media content (common in RSS 2.0 with media namespace) + // Check media content (common in RSS 2.0 with media namespace). + // When multiple media:content variants are advertised (Guardian RSS lists + // 140/460/700/1200…) we want the widest signed URL we can find. if item.Extensions != nil { if media, ok := item.Extensions["media"]; ok { if contents, ok := media["content"]; ok { - for _, c := range contents { - if url := c.Attrs["url"]; url != "" { - return url - } + if url := widestURL(contents); url != "" { + return url } } if thumbs, ok := media["thumbnail"]; ok { - for _, t := range thumbs { - if url := t.Attrs["url"]; url != "" { - return url - } + if url := widestURL(thumbs); url != "" { + return url } } // media:group wraps nested media:content / media:thumbnail in some feeds @@ -143,6 +143,25 @@ func extractImageURL(item *gofeed.Item) string { return "" } +// widestURL picks the entry with the largest declared width attribute, falling +// back to the first URL if none have a parsable width. +func widestURL(entries []ext.Extension) string { + best := "" + bestW := -1 + for _, e := range entries { + url := e.Attrs["url"] + if url == "" { + continue + } + w, _ := strconv.Atoi(e.Attrs["width"]) + if w > bestW { + best = url + bestW = w + } + } + return best +} + func firstImgSrc(htmlBody string) string { if htmlBody == "" { return "" diff --git a/internal/web/static/css/output.css b/internal/web/static/css/output.css index f26b5ba..f21eee3 100644 --- a/internal/web/static/css/output.css +++ b/internal/web/static/css/output.css @@ -1 +1 @@ -*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}body{font-family:Nunito,system-ui,sans-serif}html{scroll-behavior:smooth}.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.-right-6{right:-1.5rem}.-top-6{top:-1.5rem}.-z-10{z-index:-10}.mx-auto{margin-left:auto;margin-right:auto}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-4{margin-bottom:1rem}.mb-8{margin-bottom:2rem}.mr-1{margin-right:.25rem}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-\[16\/10\]{aspect-ratio:16/10}.h-12{height:3rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-full{width:100%}.max-w-6xl{max-width:72rem}.max-w-xl{max-width:36rem}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-full{border-radius:9999px}.border-2{border-width:2px}.border-dashed{border-style:dashed}.bg-\[color\:var\(--bg\)\]{background-color:var(--bg)}.bg-\[color\:var\(--bg-grad\)\]{background-color:var(--bg-grad)}.bg-\[color\:var\(--card\)\]{background-color:var(--card)}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.pb-10{padding-bottom:2.5rem}.pb-24{padding-bottom:6rem}.pb-4{padding-bottom:1rem}.pt-8{padding-top:2rem}.text-center{text-align:center}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-\[12rem\]{font-size:12rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.text-\[color\:var\(--ink\)\]{color:var(--ink)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/85{color:hsla(0,0%,100%,.85)}.decoration-4{text-decoration-thickness:4px}.underline-offset-2{text-underline-offset:2px}.underline-offset-4{text-underline-offset:4px}.opacity-20{opacity:.2}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-1000{transition-duration:1s}.duration-500{transition-duration:.5s}.font-display{font-family:Fredoka,Nunito,system-ui,sans-serif;letter-spacing:-.01em}.shadow-pete{box-shadow:0 4px 0 rgba(60,40,20,.1),0 8px 24px rgba(60,40,20,.08)}.shadow-pete-lg{box-shadow:0 6px 0 rgba(60,40,20,.12),0 16px 32px rgba(60,40,20,.12)}.bg-theme-gaming{background-color:#4caf7d}.bg-theme-tech{background-color:#5aa9e6}.bg-theme-politics{background-color:#e07a5f}.text-theme-gaming{color:#2d8a5a}.text-theme-tech{color:#2f7fb8}.text-theme-politics{color:#b8523a}.decoration-theme-gaming{text-decoration-color:#4caf7d}.decoration-theme-tech{text-decoration-color:#5aa9e6}.decoration-theme-politics{text-decoration-color:#e07a5f}.border-theme-gaming{border-color:#4caf7d}.border-theme-tech{border-color:#5aa9e6}.border-theme-politics{border-color:#e07a5f}.line-clamp-3{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}:root,html[data-phase=day]{--bg:#fff7e4;--bg-grad:#ffeec2;--card:#fff;--ink:#3a2e1f;--accent:#f2a541}html[data-phase=dawn]{--bg:#ffe7d6;--bg-grad:#ffc9c9;--card:#fff4ea;--ink:#4a2e2a;--accent:#ff8a65}html[data-phase=dusk]{--bg:#ffd6a8;--bg-grad:#f7a07e;--card:#fff1de;--ink:#3d2417;--accent:#e6553a}html[data-phase=night]{--bg:#1a1f3a;--bg-grad:#2a3358;--card:#2d365a;--ink:#f1ecd8;--accent:#f9d976}.hover\:-translate-y-0\.5:hover{--tw-translate-y:-0.125rem}.hover\:-translate-y-0\.5:hover,.hover\:-translate-y-1:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:-translate-y-1:hover{--tw-translate-y:-0.25rem}.hover\:underline:hover{text-decoration-line:underline}.hover\:shadow-pete-lg:hover{box-shadow:0 6px 0 rgba(60,40,20,.12),0 16px 32px rgba(60,40,20,.12)}.group:hover .group-hover\:-rotate-6{--tw-rotate:-6deg}.group:hover .group-hover\:-rotate-6,.group:hover .group-hover\:scale-105{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:scale-105{--tw-scale-x:1.05;--tw-scale-y:1.05}.group:hover .group-hover\:underline{text-decoration-line:underline}@media (min-width:640px){.sm\:mb-14{margin-bottom:3.5rem}.sm\:inline{display:inline}.sm\:inline-flex{display:inline-flex}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:gap-2{gap:.5rem}.sm\:p-10{padding:2.5rem}.sm\:pt-12{padding-top:3rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-5xl{font-size:3rem;line-height:1}.sm\:text-6xl{font-size:3.75rem;line-height:1}.sm\:text-lg{font-size:1.125rem;line-height:1.75rem}}@media (min-width:1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}} \ No newline at end of file +*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}body{font-family:Nunito,system-ui,sans-serif}html{scroll-behavior:smooth}.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.-right-6{right:-1.5rem}.-top-6{top:-1.5rem}.-z-10{z-index:-10}.mx-auto{margin-left:auto;margin-right:auto}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-4{margin-bottom:1rem}.mb-8{margin-bottom:2rem}.mr-1{margin-right:.25rem}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.aspect-\[16\/10\]{aspect-ratio:16/10}.h-12{height:3rem}.h-5{height:1.25rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-5{width:1.25rem}.w-full{width:100%}.max-w-6xl{max-width:72rem}.max-w-xl{max-width:36rem}.-translate-y-0{--tw-translate-y:-0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-full{border-radius:9999px}.border-2{border-width:2px}.border-dashed{border-style:dashed}.bg-\[color\:var\(--bg\)\]{background-color:var(--bg)}.bg-\[color\:var\(--bg-grad\)\]{background-color:var(--bg-grad)}.bg-\[color\:var\(--card\)\]{background-color:var(--card)}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.pb-10{padding-bottom:2.5rem}.pb-24{padding-bottom:6rem}.pb-4{padding-bottom:1rem}.pt-8{padding-top:2rem}.text-center{text-align:center}.align-\[-4px\]{vertical-align:-4px}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-\[12rem\]{font-size:12rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.text-\[color\:var\(--ink\)\]{color:var(--ink)}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.text-white\/85{color:hsla(0,0%,100%,.85)}.decoration-4{text-decoration-thickness:4px}.underline-offset-2{text-underline-offset:2px}.underline-offset-4{text-underline-offset:4px}.opacity-20{opacity:.2}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-1000{transition-duration:1s}.duration-500{transition-duration:.5s}.font-display{font-family:Fredoka,Nunito,system-ui,sans-serif;letter-spacing:-.01em}.shadow-pete{box-shadow:0 4px 0 rgba(60,40,20,.1),0 8px 24px rgba(60,40,20,.08)}.shadow-pete-lg{box-shadow:0 6px 0 rgba(60,40,20,.12),0 16px 32px rgba(60,40,20,.12)}.bg-theme-gaming{background-color:#4caf7d}.bg-theme-tech{background-color:#5aa9e6}.bg-theme-politics{background-color:#e07a5f}.text-theme-gaming{color:#2d8a5a}.text-theme-tech{color:#2f7fb8}.text-theme-politics{color:#b8523a}.decoration-theme-gaming{text-decoration-color:#4caf7d}.decoration-theme-tech{text-decoration-color:#5aa9e6}.decoration-theme-politics{text-decoration-color:#e07a5f}.border-theme-gaming{border-color:#4caf7d}.border-theme-tech{border-color:#5aa9e6}.border-theme-politics{border-color:#e07a5f}.line-clamp-3{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}:root,html[data-phase=day]{--bg:#fff7e4;--bg-grad:#ffeec2;--card:#fff;--ink:#3a2e1f;--accent:#f2a541}html[data-phase=dawn]{--bg:#ffe7d6;--bg-grad:#ffc9c9;--card:#fff4ea;--ink:#4a2e2a;--accent:#ff8a65}html[data-phase=dusk]{--bg:#ffd6a8;--bg-grad:#f7a07e;--card:#fff1de;--ink:#3d2417;--accent:#e6553a}html[data-phase=night]{--bg:#1a1f3a;--bg-grad:#2a3358;--card:#2d365a;--ink:#f1ecd8;--accent:#f9d976}.hover\:-translate-y-0\.5:hover{--tw-translate-y:-0.125rem}.hover\:-translate-y-0\.5:hover,.hover\:-translate-y-1:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:-translate-y-1:hover{--tw-translate-y:-0.25rem}.hover\:underline:hover{text-decoration-line:underline}.hover\:shadow-pete-lg:hover{box-shadow:0 6px 0 rgba(60,40,20,.12),0 16px 32px rgba(60,40,20,.12)}.group:hover .group-hover\:-rotate-6{--tw-rotate:-6deg}.group:hover .group-hover\:-rotate-6,.group:hover .group-hover\:scale-105{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:scale-105{--tw-scale-x:1.05;--tw-scale-y:1.05}.group:hover .group-hover\:underline{text-decoration-line:underline}@media (min-width:640px){.sm\:mb-14{margin-bottom:3.5rem}.sm\:inline{display:inline}.sm\:inline-flex{display:inline-flex}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:gap-2{gap:.5rem}.sm\:p-10{padding:2.5rem}.sm\:pt-12{padding-top:3rem}.sm\:text-3xl{font-size:1.875rem;line-height:2.25rem}.sm\:text-5xl{font-size:3rem;line-height:1}.sm\:text-6xl{font-size:3.75rem;line-height:1}.sm\:text-lg{font-size:1.125rem;line-height:1.75rem}}@media (min-width:1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}} \ No newline at end of file diff --git a/internal/web/static/img/leaf.svg b/internal/web/static/img/leaf.svg deleted file mode 100644 index b54336c..0000000 --- a/internal/web/static/img/leaf.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/internal/web/static/img/pete.avif b/internal/web/static/img/pete.avif new file mode 100644 index 0000000000000000000000000000000000000000..e19100469ba2f187aef4c67e371c9ff65e73238e GIT binary patch literal 7991 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 - +