772cb47d69
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
430 lines
23 KiB
Svelte
430 lines
23 KiB
Svelte
<script>
|
||
import { onMount } from 'svelte';
|
||
import { getJSON } from '$lib/api.js';
|
||
|
||
// /home3 — the Claude Design "Frame A" direction (editorial, with colour), rebuilt in
|
||
// our codebase with our real logo + self-hosted fonts, wired to live data. Hidden
|
||
// prototype (noindex), alongside /home2 so we can compare.
|
||
let news = $state(null); // {id, title, summary, image}
|
||
let art = $state(null); // {title, artist, year, image}
|
||
|
||
// headline truncated on a whole-word boundary (no mid-word ellipsis)
|
||
function clampWords(s, max = 48) {
|
||
if (!s || s.length <= max) return s;
|
||
const cut = s.slice(0, max);
|
||
const i = cut.lastIndexOf(' ');
|
||
return (i > 0 ? cut.slice(0, i) : cut).replace(/[\s,;:.]+$/, '') + '…';
|
||
}
|
||
let headline = $derived(clampWords(news?.title ?? 'What went right this week: the good news that actually matters'));
|
||
|
||
// small-joys shelf: 3 cells shown two at a time, rotated by the reader (no auto-motion)
|
||
const JOY_ACCENTS = ['#4f7da8', '#b06a86', '#b06a45'];
|
||
let joyIdx = $state(0);
|
||
const prevJoy = () => (joyIdx = (joyIdx + 2) % 3);
|
||
const nextJoy = () => (joyIdx = (joyIdx + 1) % 3);
|
||
|
||
onMount(async () => {
|
||
try {
|
||
const a = await getJSON('/api/art/today');
|
||
if (a) art = { title: a.title, artist: a.artist, year: a.date_text, image: a.image_url };
|
||
} catch { /* fall back to gradient swatch */ }
|
||
|
||
let homeq = '';
|
||
try {
|
||
const hv = localStorage.getItem('goodnews:home') || '';
|
||
const hs = localStorage.getItem('goodnews:homeScope') || 'nearby';
|
||
if (hv && hs !== 'world') homeq = `&home=${encodeURIComponent(hv)}&scope=${hs}`;
|
||
} catch { /* global brief */ }
|
||
try {
|
||
const it = (await getJSON(`/api/brief?limit=1${homeq}`))?.items?.[0];
|
||
if (it) news = { id: it.id, title: it.title, summary: it.summary || it.description || '', image: it.image_url || null };
|
||
} catch { /* fall back to design copy */ }
|
||
});
|
||
</script>
|
||
|
||
<svelte:head>
|
||
<title>upbeatBytes — a calmer, brighter corner of the internet</title>
|
||
<meta name="robots" content="noindex" />
|
||
<meta name="description" content="A calmer, brighter corner of the internet: good news, daily art, small games, and little resets." />
|
||
</svelte:head>
|
||
|
||
{#snippet joyCard(i)}
|
||
{#if i === 0}
|
||
<div class="joy joy-word">
|
||
<span class="wm" aria-hidden="true">S</span>
|
||
<div class="joy-in">
|
||
<div class="tag"><span class="rule"></span><span class="tag-label">Word of the day</span></div>
|
||
<p class="word-line"><span class="word">Serene</span> <span class="word-pos">adj.</span></p>
|
||
<p class="word-pron">/səˈriːn/</p>
|
||
<p class="def">Calm, peaceful, and untroubled. The quiet after a storm passes.</p>
|
||
</div>
|
||
</div>
|
||
{:else if i === 1}
|
||
<div class="joy joy-quote">
|
||
<span class="wm wm-q" aria-hidden="true">“</span>
|
||
<div class="joy-in">
|
||
<div class="tag"><span class="rule"></span><span class="tag-label">Quote of the day</span></div>
|
||
<p class="quote">Very little is needed to make a happy life.</p>
|
||
<div class="attrib"><span class="attrib-rule"></span><span class="attrib-by">Marcus Aurelius</span></div>
|
||
</div>
|
||
</div>
|
||
{:else}
|
||
<div class="joy joy-fact">
|
||
<div class="joy-in">
|
||
<div class="joy-top">
|
||
<div class="tag"><span class="rule"></span><span class="tag-label">A good thing today</span></div>
|
||
<span class="soon">SOON</span>
|
||
</div>
|
||
<p class="fact-hero"><span class="year">1928</span> <span class="onthis">ON THIS DAY</span></p>
|
||
<p class="fact">Penicillin was discovered by a happy accident.</p>
|
||
</div>
|
||
</div>
|
||
{/if}
|
||
{/snippet}
|
||
|
||
<div class="page">
|
||
<header class="bar">
|
||
<a class="brand" href="/home3" aria-label="upbeatBytes home">
|
||
<img src="/logo.svg" alt="upbeatBytes" width="586" height="196" />
|
||
</a>
|
||
<nav class="nav">
|
||
<a class="on" href="/">News</a>
|
||
<a href="/play">Games</a>
|
||
<a href="/art">Art</a>
|
||
<a class="acct" href="/account" aria-label="Your account">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#C98A2E" stroke-width="2" aria-hidden="true">
|
||
<circle cx="12" cy="8" r="4" /><path d="M4 21c0-4 4-6 8-6s8 2 8 6" />
|
||
</svg>
|
||
</a>
|
||
</nav>
|
||
</header>
|
||
|
||
<section class="hero">
|
||
<h1>A <span class="t">calmer</span>, <span class="b">brighter</span> corner of the internet.</h1>
|
||
<p class="sub">Good news, daily art, small games, and little resets.</p>
|
||
</section>
|
||
|
||
<main class="bento">
|
||
<!-- Good News (tall) — a card with TWO links, so it's a div, not a single anchor -->
|
||
<div class="card news">
|
||
<div class="news-photo" style={news?.image ? `background-image:url(${news.image})` : ''}></div>
|
||
<div class="news-body">
|
||
<span class="label" style="color:#0083ad">GOOD NEWS</span>
|
||
<h2>{headline}</h2>
|
||
<p class="summary">{news?.summary || "We read the week so you don't have to doomscroll it. Five quietly hopeful stories, summarised to the gist."}</p>
|
||
<div class="news-foot">
|
||
<a class="link news-link" href={news?.id ? `/a/${news.id}` : '/'}>Read article</a>
|
||
<span class="meta">3 min read</span>
|
||
</div>
|
||
<a class="news-more" href="/">Read more good news →</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="rightcol">
|
||
<!-- Daily Art (wide) -->
|
||
<a class="card art" href="/art">
|
||
<div class="art-body">
|
||
<span class="label" style="color:#8857C2">DAILY ART</span>
|
||
<h3>A masterwork a day</h3>
|
||
<p class="art-today">
|
||
{#if art}Today: <span class="ital">{art.title}</span>{#if art.artist} — {art.artist}{/if}{#if art.year}, {art.year}{/if}.
|
||
{:else}Today: <span class="ital">Among the Sierra Nevada</span> — Bierstadt, 1868.{/if}
|
||
</p>
|
||
<span class="link art-link">View today</span>
|
||
</div>
|
||
<div class="art-swatch" style={art?.image ? `--art:url(${art.image})` : ''}></div>
|
||
</a>
|
||
|
||
<!-- bottom pair — vertically centered in the space beneath the pinned Art card -->
|
||
<div class="pair-wrap">
|
||
<div class="pair">
|
||
<a class="card play" href="/play">
|
||
<div class="play-top">
|
||
<span class="label" style="color:#A8650F">PLAY</span>
|
||
<h3>A little daily puzzle</h3>
|
||
</div>
|
||
|
||
<!-- "bleeding boards": three game motifs clipping at the card edges (decorative) -->
|
||
<div class="play-band" aria-hidden="true">
|
||
<div class="wb">
|
||
<div class="wb-row"><span class="wb-t wb-a">E</span><span class="wb-t wb-n">A</span><span class="wb-t wb-a">T</span></div>
|
||
<div class="wb-row"><span class="wb-t wb-g">Y</span><span class="wb-t wb-g">T</span><span class="wb-t wb-g">E</span></div>
|
||
<div class="wb-row"><span class="wb-t wb-e"></span><span class="wb-t wb-e"></span><span class="wb-t wb-d"></span></div>
|
||
</div>
|
||
<div class="ws">
|
||
<span>K</span><span>R</span><span>O</span><span>A</span><span>E</span><span>S</span>
|
||
<span class="hl">B</span><span class="hl">Y</span><span class="hl">T</span><span class="hl">E</span><span class="hl">S</span><span>W</span>
|
||
<span>T</span><span>I</span><span>M</span><span>U</span><span>H</span><span>P</span>
|
||
<span>G</span><span>E</span><span>B</span><span>O</span><span>R</span><span>L</span>
|
||
<span>F</span><span>I</span><span>N</span><span>D</span><span>C</span><span>A</span>
|
||
<span>Z</span><span>O</span><span>S</span><span>E</span><span>K</span><span>Y</span>
|
||
</div>
|
||
<div class="mm">
|
||
<span class="mm-a"></span>
|
||
<span class="mm-w"><span class="mm-dot" style="background:#6bbf8c"></span></span>
|
||
<span class="mm-a"></span>
|
||
<span class="mm-w"><span class="mm-dot" style="background:#6bbf8c"></span></span>
|
||
<span class="mm-a"></span>
|
||
<span class="mm-a"></span>
|
||
<span class="mm-a"></span>
|
||
<span class="mm-w"><span class="mm-dot" style="background:#D2861B"></span></span>
|
||
<span class="mm-a"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="play-foot"><span class="link play-link">Enter</span></div>
|
||
</a>
|
||
<div class="card moment">
|
||
<div class="moment-top">
|
||
<span class="label" style="color:#3F9A66">ENTERTAINMENT</span>
|
||
<span class="soon">SOON</span>
|
||
</div>
|
||
<p class="moment-line">A little something to enjoy.</p>
|
||
<span class="moment-meta">Shows, clips, and curiosities. Coming soon.</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- "small joys" — two jewels at a time, rotated by the reader (3 cells total) -->
|
||
<div class="joys-shelf">
|
||
<div class="joys-head">
|
||
<div class="joys-title"><span class="jt-label">Small joys for today</span><span class="jt-count">· {joyIdx + 1} of 3</span></div>
|
||
<div class="joys-nav">
|
||
<div class="joys-dots" aria-hidden="true">
|
||
{#each [0, 1, 2] as d}
|
||
<span class="dot" class:on={d === joyIdx} style={d === joyIdx ? `background:${JOY_ACCENTS[joyIdx]}` : ''}></span>
|
||
{/each}
|
||
</div>
|
||
<div class="joys-arrows">
|
||
<button class="arrow" onclick={prevJoy} aria-label="Previous small joys">‹</button>
|
||
<button class="arrow" onclick={nextJoy} aria-label="More small joys">›</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="joys">
|
||
{@render joyCard(joyIdx)}
|
||
{@render joyCard((joyIdx + 1) % 3)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<footer class="foot">upbeatBytes — no ads, no paywalls, no doomscrolling.</footer>
|
||
</div>
|
||
|
||
<style>
|
||
@font-face { font-family: 'Hanken Grotesk'; src: url('/fonts/hanken-var.woff2') format('woff2'); font-weight: 400 700; font-style: normal; font-display: swap; }
|
||
@font-face { font-family: 'Newsreader'; src: url('/fonts/newsreader-var.woff2') format('woff2'); font-weight: 400 600; font-style: normal; font-display: swap; }
|
||
@font-face { font-family: 'Newsreader'; src: url('/fonts/newsreader-italic-var.woff2') format('woff2'); font-weight: 400 500; font-style: italic; font-display: swap; }
|
||
|
||
.page {
|
||
--ink: #1c1916; --body: #6b6256; --muted: #a89e8c; --teal: #0083ad;
|
||
--canvas: #FFF9EF; --news-border: #f2e7d3;
|
||
min-height: 100vh; background: var(--canvas); color: #23201b;
|
||
font-family: 'Hanken Grotesk', ui-sans-serif, system-ui, sans-serif;
|
||
display: flex; flex-direction: column;
|
||
}
|
||
.page :global(*) { box-sizing: border-box; }
|
||
|
||
/* Header — real logo left, nav right */
|
||
.bar {
|
||
display: flex; align-items: center; justify-content: space-between;
|
||
max-width: 1180px; width: 100%; margin: 0 auto; box-sizing: border-box;
|
||
padding: 26px clamp(18px, 5vw, 44px) 0;
|
||
}
|
||
.brand { display: block; line-height: 0; }
|
||
.brand img { height: 48px; width: auto; display: block; }
|
||
.nav { display: flex; align-items: center; gap: clamp(16px, 2.4vw, 32px); font-size: 16.5px; font-weight: 500; }
|
||
.nav a { color: var(--body); text-decoration: none; }
|
||
.nav a.on { color: #23201b; }
|
||
.nav a:hover { color: var(--teal); }
|
||
.acct {
|
||
width: 32px; height: 32px; border-radius: 50%; border: 1.5px solid #e6c9a0; background: #FCEFD7;
|
||
display: flex; align-items: center; justify-content: center;
|
||
}
|
||
.acct:hover { background: #fbe6c4; }
|
||
|
||
/* Hero — spacing tuned per the /home2 pass: pulled up a touch, more air before cards */
|
||
.hero { text-align: center; max-width: 1180px; width: 100%; margin: 0 auto; padding: clamp(24px, 4vw, 34px) clamp(18px, 5vw, 44px) clamp(38px, 5vw, 48px); }
|
||
.hero h1 {
|
||
font-family: 'Newsreader', Georgia, serif; font-weight: 500;
|
||
font-size: clamp(2.1rem, 5vw, 50px); line-height: 1.04; letter-spacing: -0.015em; margin: 0; color: var(--ink);
|
||
}
|
||
.hero h1 .t { color: #0083ad; }
|
||
.hero h1 .b { color: #E0852C; }
|
||
.hero .sub { font-family: 'Newsreader', Georgia, serif; font-style: italic; font-size: clamp(1rem, 2vw, 19px); color: #857b6c; margin: 14px 0 0; }
|
||
|
||
/* Bento grid */
|
||
.bento {
|
||
max-width: 1180px; width: 100%; margin: 0 auto; box-sizing: border-box;
|
||
padding: 0 clamp(18px, 5vw, 44px) 16px;
|
||
display: grid; grid-template-columns: minmax(0, 1.18fr) minmax(0, 1.82fr); gap: 16px;
|
||
}
|
||
/* right column matches the News height; Art stays pinned to the TOP and the Play/Moment
|
||
pair to the BOTTOM, with the extra space distributed BETWEEN them (FIX1). The cards
|
||
themselves keep their natural size and never stretch. */
|
||
.rightcol { display: flex; flex-direction: column; gap: 16px; }
|
||
.rightcol .art { flex: none; } /* Art pinned to the top */
|
||
.pair-wrap { flex: 1; display: flex; align-items: center; } /* fill the rest; pair vertically centered */
|
||
.card {
|
||
border-radius: 18px; overflow: hidden; text-decoration: none; color: inherit;
|
||
transition: transform 0.18s ease, box-shadow 0.18s ease;
|
||
}
|
||
a.card:hover { transform: translateY(-2px); }
|
||
.label { font-size: 11px; font-weight: 700; letter-spacing: 0.16em; }
|
||
.link { font-size: 14px; font-weight: 600; padding-bottom: 2px; align-self: flex-start; }
|
||
/* card titles a touch larger + bolder so they jump on hover/scan */
|
||
h2, h3 { font-family: 'Newsreader', Georgia, serif; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
|
||
|
||
/* Good News — tall, photo on top */
|
||
.news {
|
||
background: #fff; border: 1px solid var(--news-border);
|
||
display: flex; flex-direction: column; box-shadow: 0 6px 20px -14px rgba(0, 131, 173, 0.4);
|
||
}
|
||
.news-photo { aspect-ratio: 5/4; background: linear-gradient(160deg, #6fc4d8, #9bd4c9 55%, #f6cf7e); background-size: cover; background-position: center; }
|
||
.news-body { padding: 24px 26px; flex: 1; display: flex; flex-direction: column; }
|
||
.news h2 {
|
||
font-size: clamp(1.55rem, 2.6vw, 30px); line-height: 1.14; margin: 12px 0 0;
|
||
display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
|
||
}
|
||
/* the gist FILLS the room available (the card runs tall), fading only at the very bottom */
|
||
.summary {
|
||
font-size: 14.5px; line-height: 1.55; color: var(--body); margin: 12px 0 0;
|
||
flex: 1 1 auto; min-height: 0; overflow: hidden;
|
||
-webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 2.1em), transparent);
|
||
mask-image: linear-gradient(to bottom, #000 calc(100% - 2.1em), transparent);
|
||
}
|
||
.news-foot { display: flex; align-items: center; justify-content: space-between; padding-top: 18px; }
|
||
.news-link { color: var(--teal); border-bottom: 2px solid #6fc4d8; text-decoration: none; }
|
||
.meta { font-size: 12px; color: var(--muted); }
|
||
/* secondary link: straight to the full brief, without reading the highlighted article */
|
||
.news-more { display: inline-block; margin-top: 12px; font-size: 13px; font-weight: 600; color: var(--muted); text-decoration: none; }
|
||
.news-more:hover { color: var(--teal); }
|
||
|
||
/* Daily Art — wide, text left + artwork swatch right */
|
||
.art { background: #F3EEF9; border: 1px solid #e4d8f1; display: flex; min-height: 188px; }
|
||
.art-body { flex: 1; padding: 24px 26px; display: flex; flex-direction: column; }
|
||
.art h3 { font-size: clamp(1.35rem, 2.1vw, 25px); line-height: 1.16; margin: 10px 0 0; color: #2a1c3d; }
|
||
.art-today { font-size: 13.5px; line-height: 1.5; color: #6f6280; margin: 9px 0 0; }
|
||
.ital { font-style: italic; font-family: 'Newsreader', Georgia, serif; }
|
||
.art-link { margin-top: auto; color: #8857C2; border-bottom: 2px solid #c9aef0; }
|
||
/* swatch crops a few px off every edge (::after inset) so scanned paintings don't show
|
||
their ragged/black canvas edge at the top */
|
||
.art-swatch {
|
||
width: 46%; min-width: 130px; position: relative; overflow: hidden;
|
||
background: linear-gradient(170deg, #bfe0f0 0%, #a9cf9a 50%, #d89a4e 100%);
|
||
}
|
||
.art-swatch::after {
|
||
content: ""; position: absolute; inset: -6px;
|
||
background-image: var(--art); background-size: cover; background-position: center;
|
||
}
|
||
|
||
/* bottom pair */
|
||
.pair { width: 100%; display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||
.play { background: #FFF3DC; border: 1px solid #f6e2b8; display: flex; flex-direction: column; }
|
||
.play-top { padding: 22px 24px 0; }
|
||
.play h3 { font-size: clamp(1.25rem, 1.9vw, 23px); margin: 14px 0 0; color: #5c3d0c; }
|
||
.play-foot { margin-top: auto; padding: 16px 24px 22px; }
|
||
.play-link { color: #A8650F; border-bottom: 2px solid #e0a94f; }
|
||
|
||
/* "bleeding boards" — three game motifs clipping at the card edges (decorative) */
|
||
/* Word search is the centred highlight; the two side games are the SAME size and each
|
||
bleeds ~half a column off its edge (consistent both sides) to imply "more under the hood". */
|
||
.play-band { position: relative; height: 124px; margin-top: 24px; overflow: hidden; }
|
||
.wb { position: absolute; top: 50%; left: -12px; transform: translateY(-50%); display: flex; flex-direction: column; gap: 4px; }
|
||
.wb-row { display: flex; gap: 4px; }
|
||
.wb-t { width: 24px; height: 24px; border-radius: 5px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 11px; color: #fff; }
|
||
.wb-g { background: #6bbf8c; } .wb-a { background: #E6A02C; } .wb-n { background: #d9c39a; }
|
||
.wb-e { background: #fff; border: 1.5px solid #ecca84; } .wb-d { background: #fff; border: 1.5px dashed #e0bb6f; }
|
||
.ws {
|
||
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
|
||
display: grid; grid-template-columns: repeat(6, 14px); gap: 3px;
|
||
font-weight: 600; font-size: 10.5px; line-height: 14px; color: #d4b576; text-align: center;
|
||
background: #fff; border: 1.5px solid #f0d597; border-radius: 10px; padding: 9px;
|
||
box-shadow: 0 5px 16px -8px rgba(210, 134, 27, 0.55);
|
||
}
|
||
.ws .hl { color: #B5701A; font-weight: 800; }
|
||
.mm { position: absolute; top: 50%; right: -12px; transform: translateY(-50%); display: grid; grid-template-columns: repeat(3, 24px); grid-auto-rows: 24px; gap: 4px; }
|
||
.mm > span { border-radius: 6px; }
|
||
.mm-a { background: #E6A02C; }
|
||
.mm-w { background: #fff; border: 1.5px solid #f0d597; display: flex; align-items: center; justify-content: center; }
|
||
.mm-dot { width: 7px; height: 7px; border-radius: 50%; display: block; }
|
||
|
||
.moment { background: #E6F3E9; border: 1px solid #cee6d3; padding: 22px 24px; display: flex; flex-direction: column; }
|
||
.moment-top { display: flex; align-items: center; justify-content: space-between; }
|
||
.soon { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; color: #3F9A66; background: #fff; border-radius: 999px; padding: 3px 8px; }
|
||
.moment-line { font-family: 'Newsreader', Georgia, serif; font-style: italic; font-size: 18px; line-height: 1.3; color: #214a35; margin: 14px 0 0; }
|
||
.moment-meta { margin-top: auto; padding-top: 16px; font-size: 13px; color: #6f9683; }
|
||
|
||
/* "small joys" rail — little jewels: one big focal point per card, a faint oversized
|
||
watermark glyph, an accent-tag label, soft diagonal gradient + long low shadow. */
|
||
.joys-shelf { flex: none; }
|
||
.joys-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
|
||
.joys-title { display: flex; align-items: baseline; gap: 8px; }
|
||
.jt-label { font-family: 'Newsreader', Georgia, serif; font-style: italic; font-size: 17px; color: #7a6f5b; }
|
||
.jt-count { font-size: 12px; color: #b3a890; }
|
||
.joys-nav { display: flex; align-items: center; gap: 14px; }
|
||
.joys-dots { display: flex; align-items: center; gap: 6px; }
|
||
.dot { width: 6px; height: 6px; border-radius: 50%; background: #d9cdb8; transition: width 0.2s ease, background 0.2s ease; }
|
||
.dot.on { width: 18px; border-radius: 3px; }
|
||
.joys-arrows { display: flex; gap: 8px; }
|
||
.arrow {
|
||
width: 30px; height: 30px; border-radius: 50%; border: 1px solid #e0d3b8; background: transparent;
|
||
color: #b09a6e; font-size: 14px; cursor: pointer; display: flex; align-items: center; justify-content: center;
|
||
padding: 0; line-height: 1; transition: background 0.15s ease, color 0.15s ease;
|
||
}
|
||
.arrow:hover { background: #fff; color: #9a7b3e; }
|
||
.joys { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||
/* all cells share one compact height (tight, not crowded) so every rotation matches */
|
||
.joy { position: relative; overflow: hidden; border-radius: 20px; padding: 18px 22px; min-height: 158px; box-sizing: border-box; }
|
||
.joy-in { position: relative; } /* content sits above the watermark */
|
||
.wm { position: absolute; font-family: 'Newsreader', Georgia, serif; line-height: 1; pointer-events: none; }
|
||
|
||
/* a fresh trio, distinct from the doors above (teal/plum/amber/green): sky · rose · clay */
|
||
.joy-word { background: linear-gradient(165deg, #EAF2F9, #DBE8F4); border: 1px solid #d2e1f0; box-shadow: 0 10px 30px -22px rgba(60, 100, 145, 0.55); --accent: #4f7da8; --rule: #4f7da8; }
|
||
.joy-word .wm { right: -14px; bottom: -30px; font-size: 150px; font-weight: 400; color: rgba(79, 125, 168, 0.13); }
|
||
.joy-quote { background: linear-gradient(165deg, #F9EDF1, #F1DEE6); border: 1px solid #eed6df; box-shadow: 0 10px 30px -22px rgba(150, 85, 115, 0.5); --accent: #b06a86; --rule: #b06a86; }
|
||
.joy-quote .wm { left: 14px; top: -26px; font-size: 120px; color: rgba(176, 106, 134, 0.16); }
|
||
.joy-fact { background: linear-gradient(165deg, #F7EAE1, #EFDACB); border: 1px solid #ecd5c4; box-shadow: 0 10px 30px -22px rgba(150, 90, 55, 0.5); --accent: #b06a45; --rule: #b06a45; }
|
||
|
||
.tag { display: flex; align-items: center; gap: 8px; }
|
||
.tag .rule { width: 18px; height: 2px; border-radius: 2px; background: var(--rule); }
|
||
.tag-label { font-size: 10px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--accent); }
|
||
|
||
.word-line { margin: 8px 0 0; display: flex; align-items: baseline; gap: 9px; }
|
||
.joy .word { font-family: 'Newsreader', Georgia, serif; font-weight: 500; font-size: 32px; line-height: 1; letter-spacing: -0.01em; color: #2c3a48; }
|
||
.word-pos { font-family: 'Newsreader', Georgia, serif; font-style: italic; font-size: 13px; color: #7d93a8; }
|
||
.word-pron { font-family: 'Newsreader', Georgia, serif; font-style: italic; font-size: 13px; color: #5f7791; margin: 2px 0 0; }
|
||
.joy .def { font-size: 13.5px; color: #5c6b77; margin: 8px 0 0; line-height: 1.45; }
|
||
|
||
.joy .quote { font-family: 'Newsreader', Georgia, serif; font-style: italic; font-size: 21px; line-height: 1.3; color: #3e2c36; margin: 16px 0 0; }
|
||
.attrib { display: flex; align-items: center; gap: 9px; margin-top: 12px; }
|
||
.attrib-rule { width: 22px; height: 1px; background: #d8afc1; }
|
||
.attrib-by { font-family: 'Newsreader', Georgia, serif; font-size: 13px; color: #97667f; }
|
||
|
||
.joy-fact .joy-top { display: flex; align-items: center; justify-content: space-between; }
|
||
.joy-fact .soon { color: #b06a45; }
|
||
.fact-hero { display: flex; align-items: baseline; gap: 8px; margin: 12px 0 0; }
|
||
.year { font-family: 'Newsreader', Georgia, serif; font-weight: 500; font-size: 30px; color: #7a4a30; line-height: 0.9; }
|
||
.onthis { font-size: 11px; color: #9e7a64; letter-spacing: 0.04em; }
|
||
.joy .fact { font-family: 'Newsreader', Georgia, serif; font-size: 16px; color: #5e4636; margin: 8px 0 0; line-height: 1.34; }
|
||
|
||
.foot {
|
||
text-align: center; max-width: 1180px; width: 100%; margin: 14px auto 0; box-sizing: border-box;
|
||
padding: 20px clamp(18px, 5vw, 44px) 30px; font-size: 13px; color: var(--muted);
|
||
border-top: 1px solid var(--news-border);
|
||
}
|
||
|
||
/* responsive — collapse the bento on narrow screens */
|
||
@media (max-width: 860px) {
|
||
.bento { grid-template-columns: 1fr; }
|
||
.news { grid-row: auto; }
|
||
}
|
||
@media (max-width: 520px) {
|
||
.art { flex-direction: column; }
|
||
.art-swatch { width: 100%; min-height: 130px; }
|
||
.pair { grid-template-columns: 1fr; }
|
||
.joys { grid-template-columns: 1fr; }
|
||
}
|
||
</style>
|