/* Design tokens - pastel pink & white scheme.
   Change them here later and every page updates at once. */
:root {
    --bg: #fff0f7; /* pinkish white - the page background */
    --text: #9e3f77; /* deep raspberry pink - stays readable on the pale background */
    --header-bg: #ffffff; /* white - the floating pill */
    --header-text: #c2427f; /* medium raspberry - the title text on the white pill */
    --drawer-bg: #ffd6e7; /* pastel pink - one step deeper than the page */
    --text-muted: #a34f81; /* soft raspberry - secondary labels (platform names on social cards) */
    --radius: 12px;
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1); /* aggressive ease-out: launches fast, settles smoothly */
}

body {
    background-color: var(--bg);
    color: var(--text);
    /* Quicksand - a rounded geometric sans: cute, but still professional.
       Loaded from Google Fonts in each page's <head> (the three font links
       are part of the standard page boilerplate, see AGENTS.md);
       Arial is the fallback for when the font can't load */
    font-family: 'Quicksand', Arial, sans-serif;
    margin: 0; /* removes the browser's default white frame around the page */
    padding-bottom: 110px; /* stops page content from hiding behind the fixed bottom bar */
}

/* Animated background (pure CSS, no canvas/JS): seven translucent circles
   drifting slowly. --u scales everything to the viewport's short side, the
   same way the old shader scaled by min(res). z-index -1 keeps it behind all
   content, above the page colour.
   Each circle is five nested layers - one per sinusoid axis plus the fill -
   because transform animations don't compose on a single element. The
   parameters match the old shader's fixed mulberry32 seed 0xC0FFEE exactly */
.bg-blobs {
    --u: min(100vw, 100vh); /* one unit = the viewport's short side */
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
}

.bg-blobs div {
    position: absolute;
}

.bg-c0, .bg-c1, .bg-c2, .bg-c3, .bg-c4, .bg-c5, .bg-c6 {
    top: 50%;
    left: 50%;
}

@keyframes bgc0x1 {
    from { transform: translateX(calc(var(--u) * -0.359)); }
    to   { transform: translateX(calc(var(--u) * 0.359)); }
}

@keyframes bgc0y1 {
    from { transform: translateY(calc(var(--u) * 0.1082)); }
    to   { transform: translateY(calc(var(--u) * -0.1082)); }
}

@keyframes bgc0x2 {
    from { transform: translateX(calc(var(--u) * 0.0893)); }
    to   { transform: translateX(calc(var(--u) * -0.0893)); }
}

@keyframes bgc0y2 {
    from { transform: translateY(calc(var(--u) * -0.1386)); }
    to   { transform: translateY(calc(var(--u) * 0.1386)); }
}

@keyframes bgc0s {
    from { transform: scale(1.0494); }
    to   { transform: scale(0.9506); }
}

.bg-c0 {
    left: calc(50% + var(--u) * -0.8619);
    top: calc(50% - var(--u) * 0.2326);
    animation: bgc0x1 79.2629s ease-in-out -75.0111s infinite alternate;
}

.bg-c0 > .bg-d {
    animation: bgc0y1 41.8367s ease-in-out -24.936s infinite alternate;
}

.bg-c0 > .bg-d > .bg-e {
    animation: bgc0x2 72.8296s ease-in-out -21.1352s infinite alternate;
}

.bg-c0 > .bg-d > .bg-e > .bg-f {
    animation: bgc0y2 50.0771s ease-in-out -5.0461s infinite alternate;
}

.bg-g0 {
    width: calc(var(--u) * 1.0504);
    height: calc(var(--u) * 1.0504);
    margin: calc(var(--u) * -0.5252);
    background: var(--drawer-bg);
    border-radius: 50%;
    opacity: 0.274;
    animation: bgc0s 75.7976s ease-in-out -14.5426s infinite alternate;
}

@keyframes bgc1x1 {
    from { transform: translateX(calc(var(--u) * -0.0616)); }
    to   { transform: translateX(calc(var(--u) * 0.0616)); }
}

@keyframes bgc1y1 {
    from { transform: translateY(calc(var(--u) * -0.2003)); }
    to   { transform: translateY(calc(var(--u) * 0.2003)); }
}

@keyframes bgc1x2 {
    from { transform: translateX(calc(var(--u) * -0.138)); }
    to   { transform: translateX(calc(var(--u) * 0.138)); }
}

@keyframes bgc1y2 {
    from { transform: translateY(calc(var(--u) * 0.03)); }
    to   { transform: translateY(calc(var(--u) * -0.03)); }
}

@keyframes bgc1s {
    from { transform: scale(1.0577); }
    to   { transform: scale(0.9423); }
}

.bg-c1 {
    left: calc(50% + var(--u) * 0.0243);
    top: calc(50% - var(--u) * 0.3757);
    animation: bgc1x1 39.9006s ease-in-out -23.7192s infinite alternate;
}

.bg-c1 > .bg-d {
    animation: bgc1y1 30.94s ease-in-out -3.0901s infinite alternate;
}

.bg-c1 > .bg-d > .bg-e {
    animation: bgc1x2 45.9666s ease-in-out -37.9941s infinite alternate;
}

.bg-c1 > .bg-d > .bg-e > .bg-f {
    animation: bgc1y2 38.335s ease-in-out -21.4477s infinite alternate;
}

.bg-g1 {
    width: calc(var(--u) * 0.7001);
    height: calc(var(--u) * 0.7001);
    margin: calc(var(--u) * -0.3501);
    background: var(--drawer-bg);
    border-radius: 50%;
    opacity: 0.2414;
    animation: bgc1s 88.8665s ease-in-out -7.939s infinite alternate;
}

@keyframes bgc2x1 {
    from { transform: translateX(calc(var(--u) * 0.2585)); }
    to   { transform: translateX(calc(var(--u) * -0.2585)); }
}

@keyframes bgc2y1 {
    from { transform: translateY(calc(var(--u) * 0.2171)); }
    to   { transform: translateY(calc(var(--u) * -0.2171)); }
}

@keyframes bgc2x2 {
    from { transform: translateX(calc(var(--u) * -0.0683)); }
    to   { transform: translateX(calc(var(--u) * 0.0683)); }
}

@keyframes bgc2y2 {
    from { transform: translateY(calc(var(--u) * 0.0318)); }
    to   { transform: translateY(calc(var(--u) * -0.0318)); }
}

@keyframes bgc2s {
    from { transform: scale(0.94); }
    to   { transform: scale(1.06); }
}

.bg-c2 {
    left: calc(50% + var(--u) * -0.3935);
    top: calc(50% - var(--u) * 0.2302);
    animation: bgc2x1 36.9248s ease-in-out -1.665s infinite alternate;
}

.bg-c2 > .bg-d {
    animation: bgc2y1 97.1931s ease-in-out -78.9503s infinite alternate;
}

.bg-c2 > .bg-d > .bg-e {
    animation: bgc2x2 35.0083s ease-in-out -23.6345s infinite alternate;
}

.bg-c2 > .bg-d > .bg-e > .bg-f {
    animation: bgc2y2 40.0904s ease-in-out -23.1844s infinite alternate;
}

.bg-g2 {
    width: calc(var(--u) * 0.9585);
    height: calc(var(--u) * 0.9585);
    margin: calc(var(--u) * -0.4793);
    background: var(--drawer-bg);
    border-radius: 50%;
    opacity: 0.248;
    animation: bgc2s 40.6095s ease-in-out -40.1936s infinite alternate;
}

@keyframes bgc3x1 {
    from { transform: translateX(calc(var(--u) * 0.151)); }
    to   { transform: translateX(calc(var(--u) * -0.151)); }
}

@keyframes bgc3y1 {
    from { transform: translateY(calc(var(--u) * 0.2163)); }
    to   { transform: translateY(calc(var(--u) * -0.2163)); }
}

@keyframes bgc3x2 {
    from { transform: translateX(calc(var(--u) * 0.031)); }
    to   { transform: translateX(calc(var(--u) * -0.031)); }
}

@keyframes bgc3y2 {
    from { transform: translateY(calc(var(--u) * 0.0867)); }
    to   { transform: translateY(calc(var(--u) * -0.0867)); }
}

@keyframes bgc3s {
    from { transform: scale(0.9821); }
    to   { transform: scale(1.0179); }
}

.bg-c3 {
    left: calc(50% + var(--u) * 0.7254);
    top: calc(50% - var(--u) * 0.4199);
    animation: bgc3x1 27.5902s ease-in-out -7.5236s infinite alternate;
}

.bg-c3 > .bg-d {
    animation: bgc3y1 48.9203s ease-in-out -43.4087s infinite alternate;
}

.bg-c3 > .bg-d > .bg-e {
    animation: bgc3x2 52.0905s ease-in-out -22.7345s infinite alternate;
}

.bg-c3 > .bg-d > .bg-e > .bg-f {
    animation: bgc3y2 70.3085s ease-in-out -48.2996s infinite alternate;
}

.bg-g3 {
    width: calc(var(--u) * 0.8529);
    height: calc(var(--u) * 0.8529);
    margin: calc(var(--u) * -0.4264);
    background: var(--drawer-bg);
    border-radius: 50%;
    opacity: 0.2268;
    animation: bgc3s 72.709s ease-in-out -43.3635s infinite alternate;
}

@keyframes bgc4x1 {
    from { transform: translateX(calc(var(--u) * -0.0177)); }
    to   { transform: translateX(calc(var(--u) * 0.0177)); }
}

@keyframes bgc4y1 {
    from { transform: translateY(calc(var(--u) * 0.0815)); }
    to   { transform: translateY(calc(var(--u) * -0.0815)); }
}

@keyframes bgc4x2 {
    from { transform: translateX(calc(var(--u) * 0.1658)); }
    to   { transform: translateX(calc(var(--u) * -0.1658)); }
}

@keyframes bgc4y2 {
    from { transform: translateY(calc(var(--u) * -0.1691)); }
    to   { transform: translateY(calc(var(--u) * 0.1691)); }
}

@keyframes bgc4s {
    from { transform: scale(0.9938); }
    to   { transform: scale(1.0062); }
}

.bg-c4 {
    left: calc(50% + var(--u) * -0.4324);
    top: calc(50% - var(--u) * -0.4806);
    animation: bgc4x1 26.9515s ease-in-out -14.1868s infinite alternate;
}

.bg-c4 > .bg-d {
    animation: bgc4y1 29.3882s ease-in-out -18.3504s infinite alternate;
}

.bg-c4 > .bg-d > .bg-e {
    animation: bgc4x2 29.4299s ease-in-out -4.1069s infinite alternate;
}

.bg-c4 > .bg-d > .bg-e > .bg-f {
    animation: bgc4y2 69.5287s ease-in-out -8.7188s infinite alternate;
}

.bg-g4 {
    width: calc(var(--u) * 0.7963);
    height: calc(var(--u) * 0.7963);
    margin: calc(var(--u) * -0.3981);
    background: var(--drawer-bg);
    border-radius: 50%;
    opacity: 0.245;
    animation: bgc4s 59.6528s ease-in-out -31.7841s infinite alternate;
}

@keyframes bgc5x1 {
    from { transform: translateX(calc(var(--u) * -0.0561)); }
    to   { transform: translateX(calc(var(--u) * 0.0561)); }
}

@keyframes bgc5y1 {
    from { transform: translateY(calc(var(--u) * 0.1112)); }
    to   { transform: translateY(calc(var(--u) * -0.1112)); }
}

@keyframes bgc5x2 {
    from { transform: translateX(calc(var(--u) * 0.1627)); }
    to   { transform: translateX(calc(var(--u) * -0.1627)); }
}

@keyframes bgc5y2 {
    from { transform: translateY(calc(var(--u) * 0.1858)); }
    to   { transform: translateY(calc(var(--u) * -0.1858)); }
}

@keyframes bgc5s {
    from { transform: scale(1.0461); }
    to   { transform: scale(0.9539); }
}

.bg-c5 {
    left: calc(50% + var(--u) * 0.5579);
    top: calc(50% - var(--u) * -0.0292);
    animation: bgc5x1 28.8622s ease-in-out -17.7394s infinite alternate;
}

.bg-c5 > .bg-d {
    animation: bgc5y1 59.4962s ease-in-out -44.4069s infinite alternate;
}

.bg-c5 > .bg-d > .bg-e {
    animation: bgc5x2 57.9112s ease-in-out -9.3696s infinite alternate;
}

.bg-c5 > .bg-d > .bg-e > .bg-f {
    animation: bgc5y2 28.0415s ease-in-out -27.3887s infinite alternate;
}

.bg-g5 {
    width: calc(var(--u) * 1.0494);
    height: calc(var(--u) * 1.0494);
    margin: calc(var(--u) * -0.5247);
    background: var(--drawer-bg);
    border-radius: 50%;
    opacity: 0.2967;
    animation: bgc5s 91.3365s ease-in-out -20.1754s infinite alternate;
}

@keyframes bgc6x1 {
    from { transform: translateX(calc(var(--u) * -0.2014)); }
    to   { transform: translateX(calc(var(--u) * 0.2014)); }
}

@keyframes bgc6y1 {
    from { transform: translateY(calc(var(--u) * -0.2749)); }
    to   { transform: translateY(calc(var(--u) * 0.2749)); }
}

@keyframes bgc6x2 {
    from { transform: translateX(calc(var(--u) * -0.0666)); }
    to   { transform: translateX(calc(var(--u) * 0.0666)); }
}

@keyframes bgc6y2 {
    from { transform: translateY(calc(var(--u) * -0.0929)); }
    to   { transform: translateY(calc(var(--u) * 0.0929)); }
}

@keyframes bgc6s {
    from { transform: scale(0.9514); }
    to   { transform: scale(1.0486); }
}

.bg-c6 {
    left: calc(50% + var(--u) * -0.3593);
    top: calc(50% - var(--u) * 0.5458);
    animation: bgc6x1 67.5872s ease-in-out -51.4348s infinite alternate;
}

.bg-c6 > .bg-d {
    animation: bgc6y1 59.4874s ease-in-out -1.1022s infinite alternate;
}

.bg-c6 > .bg-d > .bg-e {
    animation: bgc6x2 31.8854s ease-in-out -23.9979s infinite alternate;
}

.bg-c6 > .bg-d > .bg-e > .bg-f {
    animation: bgc6y2 50.7173s ease-in-out -1.7053s infinite alternate;
}

.bg-g6 {
    width: calc(var(--u) * 0.6965);
    height: calc(var(--u) * 0.6965);
    margin: calc(var(--u) * -0.3483);
    background: var(--drawer-bg);
    border-radius: 50%;
    opacity: 0.2889;
    animation: bgc6s 100.4678s ease-in-out -80.4623s infinite alternate;
}
/* Centered content column - reuse this class on every page for cohesion */
.container {
    max-width: 900px;
    margin-inline: auto;
    padding: 24px;
    text-align: center;
}

/* Space around the floating bar so it doesn't touch the page edges.
   fixed pins it to the bottom of the screen - thumb-reachable on mobile,
   and since it's out of normal flow, opening the drawer can't push the
   page content around (no layout shift) */
header {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 100; /* above the backdrop (50) so the bar and drawer stay clickable while the page is dimmed */
    padding: 0 24px 16px;
    /* The pill is fetched + injected by pill.js, so it arrives a beat after
       first paint - this makes that arrival feel intentional instead of a pop.
       (Animating the header's transform is safe: nothing INSIDE it is
       position:fixed, so no containing-block surprises) */
    animation: pill-in 0.3s var(--ease-out);
}

@keyframes pill-in {
    from { opacity: 0; transform: translateY(12px); }
}

/* The pill slot. The server substitutes the {{include}} inside it into the real
   markup; until that substitution happens the marker arrives as literal text,
   and :not(:has(header)) hides it so it can never flash on screen. pill.js
   fills the slot in that case, and the header it inserts satisfies the :has()
   test, so the slot shows again - the same markup works either way */
#site-pill:not(:has(header)) {
    display: none;
}

/* Wider floating bar, centered on the page.
   space-between pins the wordmark left and the icon cluster right
   (only two children, so both sit truly at their edges) */
.header-content {
    width: 80%;
    max-width: 720px;
    margin-inline: auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 24px;
    background-color: var(--header-bg);
    border-radius: var(--radius);
    /* soft pink shadow so the white pill reads as floating on the pale page */
    box-shadow: 0 8px 24px rgba(158, 63, 119, 0.18);
    transition: transform 0.25s var(--ease-out);
}

/* :has() styles an element based on its descendants - here the pill scales
   up while the drawer (its sibling) is open, and back down when it closes */
header:has(.drawer.open) .header-content {
    transform: scale(1.03);
}

/* The wordmark (a home link back to /about/). Smaller than the icon on
   purpose - it pairs with the hamburger rather than competing with it. No
   extra padding of its own: the pill's own 8px 24px padding gives it exactly
   the same inset as the icon, so text and icon sit evenly inside the bar */
.header-content .wordmark {
    color: var(--header-text);
    font-size: 32px;
    font-weight: bold;
    line-height: 1; /* no extra leading */
    text-decoration: none; /* it's an <a> now, but it should still read as a label */
}

/* Icon cluster: music + hamburger sit flush together on the right of the pill.
   Wrapping both in one flex child is what keeps space-between from dropping
   the music button into the middle gap between wordmark and hamburger */
.icon-group {
    display: flex;
    align-items: center;
}

/* Was broken before: "button .pages-button" only matched a .pages-button
   INSIDE a button. The button itself has the class, so style it directly. */
.pages-button,
.music-button {
    background-color: transparent;
    border: none;
    width: 60px;
    height: 60px;
    flex-shrink: 0; /* keep both icon buttons at full size on narrow phones */
    cursor: pointer;
    /* the icon strokes use currentColor, so it follows the text token */
    color: var(--text);
}

/* Same focus ring as the other focusable cards and links, so keyboard users
   can see which button has focus */
.pages-button:focus-visible,
.music-button:focus-visible {
    outline: 3px solid var(--header-text);
    outline-offset: 2px;
}

/* Hamburger -> X morph while the drawer is open: the top and bottom lines
   slide to the middle and rotate into a cross, the middle line fades out.
   Each line rotates around its OWN centre (transform-origin in viewBox
   units), then translates so both crosses land on the icon's centre (12,12) */
.menu-line {
    transition: transform 0.25s var(--ease-out), opacity 0.2s var(--ease-out);
}

.menu-line-top    { transform-origin: 12px 6px; }
.menu-line-middle { transform-origin: 12px 12px; }
.menu-line-bottom { transform-origin: 12px 18px; }

header:has(.drawer.open) .menu-line-top {
    transform: translateY(6px) rotate(45deg);
}

header:has(.drawer.open) .menu-line-middle {
    opacity: 0;
}

header:has(.drawer.open) .menu-line-bottom {
    transform: translateY(-6px) rotate(-45deg);
}

/* Music toggle icon: no CSS animation here on purpose. The mute X is drawn as
   two <path>s and pill.js morphs their path data into the sound waves when
   unmuted (250ms, same ease-out curve as the hamburger). It's done in JS
   because Safari can't animate SVG path data via CSS `d` - one code path gives
   every browser the same morph. The .playing class is just a state marker now */


/* Drawer - expands UPWARD from the bar (it sits above the bar in the DOM).
   grid-template-rows animates 0fr -> 1fr ("no room" -> "exactly the room the
   content needs"). On close, the shrinking box sweeps down over the links,
   so they sink behind the bar and get swallowed by it - no popping out */
.drawer {
    width: 80%;
    max-width: 720px;
    margin-inline: auto;
    background-color: var(--drawer-bg);
    border-radius: var(--radius) var(--radius) 0 0; /* rounded top only, so it looks attached to the bar */
    display: grid;
    grid-template-rows: 0fr;
    visibility: hidden;
    /* visibility is switched with a 0.25s DELAY, not a 0.25s duration: on close
       it has to stay visible while the box collapses (otherwise the links
       vanish instead of sinking behind the bar), and on open the .open rule
       below overrides the delay away so it flips in the first frame. A
       duration-based switch left the links unfocusable until the transition
       clock advanced, which focus management in pill.js cannot rely on */
    transition: grid-template-rows 0.25s var(--ease-out), visibility 0s 0.25s;
}

.drawer.open {
    grid-template-rows: 1fr;
    visibility: visible;
    transition: grid-template-rows 0.25s var(--ease-out), visibility 0s;
}

/* Inner wrapper holds the padding so the drawer can collapse fully to 0.
   overflow: hidden is what lets the grid row actually squash it */
.drawer-links {
    display: flex;
    align-items: center;
    justify-content: space-between; /* spreads the items to fill the whole width */
    padding: 14px 24px;
    overflow: hidden;
}

.drawer-link {
    color: var(--text);
    text-decoration: none;
    /* Padding makes the clickable area clearly bigger than the text itself
       (the links are flex items, so vertical padding applies fully) */
    padding: 6px 10px;
    transition: opacity 0.2s ease-out;
}

.drawer-link:hover {
    opacity: 0.7;
}

/* The link for the page you're already on: bold shows where you are, and it
   is disabled (unclickable) since there's nowhere to go - deliberately NOT
   dimmed, so it still reads as a normal link. pill.js sets both the .active
   class and aria-disabled="true" automatically from the URL (markActiveLink),
   so pages never set them by hand */
.drawer-link.active {
    font-weight: bold;
    pointer-events: none; /* makes it unclickable; aria-disabled covers screen readers */
}

/* A page that doesn't exist yet (events, for now): dimmed and unclickable,
   with an "under construction!" bubble on hover. The link keeps
   pointer-events: none so it can't be clicked - which also means it can't be
   hovered - so the bubble hangs off a wrapper <span class="tooltip-wrap">
   around the link (hovering through a transparent child still lights up its
   parent). pill.js skips .off links when marking the active one. Remove the
   wrapper + off class in components/pill.html when the page is built */
.drawer-link.off {
    opacity: 0.4;
    pointer-events: none;
}

/* The bubble floats above the link, but .drawer-links has overflow: hidden so
   the drawer can squash shut - that would clip it, so switch to visible while
   open (squashing only happens when the drawer closes) */
.drawer.open .drawer-links {
    overflow: visible;
}

.tooltip-wrap {
    position: relative; /* anchor for the bubble + arrow */
}

.tooltip-wrap::after {
    content: "under construction!";
    position: absolute;
    bottom: calc(100% + 8px); /* floats just above the link */
    left: 50%;
    transform: translateX(-50%);
    background-color: var(--header-bg);
    color: var(--text);
    font-size: 14px;
    padding: 6px 14px;
    border-radius: 999px; /* same pill shape as the bar */
    white-space: nowrap;
    box-shadow: 0 2px 8px rgba(158, 63, 119, 0.2);
    opacity: 0;
    pointer-events: none; /* never blocks clicks on the links below */
    transition: opacity 0.15s ease-out;
}

/* Little arrow under the bubble pointing at the link: a rotated square that
   straddles the bubble's bottom edge (its centre sits exactly on that edge),
   with the bubble painting over its top half - leaving a triangle */
.tooltip-wrap::before {
    content: "";
    position: absolute;
    bottom: calc(100% + 3.5px);
    left: 50%;
    transform: translateX(-50%) rotate(45deg);
    width: 9px;
    height: 9px;
    background-color: var(--header-bg);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease-out;
}

.tooltip-wrap:hover::before,
.tooltip-wrap:hover::after {
    opacity: 1;
}

.dot {
    font-size: 24px;
    opacity: 0.5;
}

/* Dimming layer over the page while the drawer is open */
.backdrop {
    position: fixed;
    inset: 0; /* stretches edge-to-edge over the whole viewport */
    /* plum tint instead of pure black - keeps the dimming in-scheme */
    background-color: rgba(122, 42, 92, 0.45);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s var(--ease-out), visibility 0.2s;
    z-index: 50;
}

.backdrop.visible {
    opacity: 1;
    visibility: visible;
}

/* Centers the image (replaces the deprecated align="center")
   and stops it overflowing on small screens */
img {
    display: block;
    max-width: 100%;
    margin-inline: auto;
}

/* Unstyled links would otherwise fall back to the browser's default blue,
   which clashes with the theme. Inheriting makes them raspberry like the
   rest of the text (the pill / cards / buttons all set their own colours) */
a {
    color: inherit;
}

/* Page title (e.g. "socials" on the socials page). Centred to match
   .container; colour is inherited from body (the deep raspberry token) */
h1 {
    text-align: center;
    font-size: 48px;
    margin: 24px 0 8px; /* small gap to the subtitle line below it */
}

/* The little line under the page title - secondary copy, so it uses the muted token */
.page-head p {
    color: var(--text-muted);
    font-size: 18px;
    margin-top: 0;
}

/* Gap between the heading and whatever follows (the card stack on socials) */
.page-head {
    margin-bottom: 32px;
}

/* Little sign-off line at the bottom of a page (e.g. the blog). Muted token
   + centred by .container, like the subtitle line, just a touch smaller. */
.page-foot {
    color: var(--text-muted);
    font-size: 16px;
    margin-top: 48px;
}

/* The about page's photo - capped so a big image doesn't dwarf the text */
.about-photo {
    max-width: 320px;
    margin-block: 8px 24px;
    border-radius: var(--radius);
}

/* ---- socials page: linktree-style card stack ---- */

.social-cards {
    display: flex;
    flex-direction: column;
    gap: 16px;
    max-width: 480px;
    margin-inline: auto; /* center the stack inside .container */
}

/* Each card is a link to a profile. White like the pill, same 12px rounding,
   and it scales up slightly on hover for that classic linktree feel */
.social-card {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 14px 20px;
    background: var(--header-bg);
    border-radius: var(--radius);
    box-shadow: 0 2px 10px rgba(158, 63, 119, 0.10);
    text-decoration: none;
    text-align: left; /* .container centers text - cards read left-to-right */
    color: var(--text);
    transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}

.social-card:hover {
    transform: scale(1.03); /* "slightly" - the card lifts toward you */
    box-shadow: 0 8px 24px rgba(158, 63, 119, 0.18); /* the pill's shadow */
}

.social-card:focus-visible {
    outline: 3px solid var(--header-text);
    outline-offset: 2px;
}

/* Logos are simple-icons (CC0) downloaded as files in assets/ and recoloured
   to the site raspberry (#9e3f77 = --text) so they match the theme instead of
   using brand colours. SVG files can't use CSS variables, so the hex is baked
   in - if --text changes, re-download: curl -fsSL https://cdn.simpleicons.org/<name>/<HEX> */
.social-logo {
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    margin-inline: 0; /* the global img rule auto-centres images; inside this flex
                          row that would fling the logo to the middle and the text
                          to the right edge - keep it flush left instead */
}

.social-text {
    display: flex;
    flex-direction: column;
}

/* The username is the star - large and bold. The platform name is just a label */
.social-handle {
    font-size: 20px;
    font-weight: bold;
    line-height: 1.2;
}

.social-platform {
    font-size: 13px;
    color: var(--text-muted);
}

/* ---- portfolio page: big alternating project cards ---------------------------- */

.project-cards {
    display: flex;
    flex-direction: column;
    gap: 40px; /* more breathing room than the social stack - these are big */
    max-width: 780px; /* deliberately a bit wider than the pill (720px) */
    margin-inline: auto;
}

/* The blog's card list is generated by the server from the files in /blog (see
   the {{range listFiles}} in blog/index.html). Before that substitution happens
   the list holds the raw template text instead of cards, so hide it until at
   least one card exists - same trick as the pill slot above */
.project-cards:not(:has(.project-card)) {
    display: none;
}

/* Each card is a link to the project's full page. Same white / rounded /
   shadow language as .social-card, just much bigger - image and text side by side */
.project-card {
    display: flex;
    align-items: center;
    gap: 24px;
    padding: 20px;
    background: var(--header-bg);
    border-radius: var(--radius);
    box-shadow: 0 2px 10px rgba(158, 63, 119, 0.10);
    text-decoration: none;
    color: var(--text);
    transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}

.project-card:hover {
    transform: scale(1.02); /* bigger cards, so a smaller lift than the social ones */
    box-shadow: 0 8px 24px rgba(158, 63, 119, 0.18); /* the pill's shadow */
}

.project-card:focus-visible {
    outline: 3px solid var(--header-text);
    outline-offset: 2px;
}

/* The image takes just under half the card. object-fit + max-height keep
   odd-shaped photos from stretching or making a giant card, and
   margin-inline:0 overrides the global auto-centre (same reason as .social-logo) */
.project-image {
    width: 45%;
    max-height: 320px;
    flex-shrink: 0;
    margin-inline: 0;
    border-radius: var(--radius);
    object-fit: cover;
}

/* Title + short description. Left-aligned by default (the .container is centred) */
.project-text {
    flex: 1;
    text-align: left;
}

/* Alternating cards: image on the right, text on the left but RIGHT-aligned,
   so the block still faces the image */
.project-card.reverse {
    flex-direction: row-reverse;
}

.project-card.reverse .project-text {
    text-align: right;
}

.project-title {
    font-size: 28px;
    margin: 0 0 8px;
}

.project-desc {
    color: var(--text-muted);
    font-size: 16px;
    line-height: 1.5;
    margin: 0;
}

/* ---- project full pages (portfolio/*.html) ------------------------------------- */

/* Placeholder hero image on a project page - swap for real screenshots later */
.project-hero {
    max-width: 480px;
    margin-block: 16px 32px;
}

/* "back to portfolio" link under the project copy. The padding gives it a
   generous hitbox, like the drawer links */
.back-link {
    display: inline-block;
    padding: 10px 20px;
    margin-top: 8px;
    font-weight: bold;
    color: var(--text);
    text-decoration: none;
    border-radius: var(--radius);
    transition: opacity 0.2s ease-out;
}

.back-link:hover {
    opacity: 0.7;
}

.back-link:focus-visible {
    outline: 3px solid var(--header-text);
    outline-offset: 2px;
}

/* Cards fade up into place, one after another. The delay comes from --i, which
   the :nth-child rules below hand out (the socials stack and the blog's
   generated list are both just a stack of these). `backwards` holds the first
   keyframe during the delay so a card stays invisible until its turn, and it
   releases the transform once finished - that matters, because a filled
   animation would outrank the hover scale and kill it. Past ten cards the
   stagger restarts at zero, which is invisible in practice */
@keyframes card-in {
    from {
        opacity: 0;
        transform: translateY(14px);
    }
}

.social-card,
.project-card {
    animation: card-in 0.5s var(--ease-out) backwards;
    animation-delay: calc(var(--i) * 70ms);
}

.social-card:nth-child(1), .project-card:nth-child(1) { --i: 0; }
.social-card:nth-child(2), .project-card:nth-child(2) { --i: 1; }
.social-card:nth-child(3), .project-card:nth-child(3) { --i: 2; }
.social-card:nth-child(4), .project-card:nth-child(4) { --i: 3; }
.social-card:nth-child(5), .project-card:nth-child(5) { --i: 4; }
.social-card:nth-child(6), .project-card:nth-child(6) { --i: 5; }
.social-card:nth-child(7), .project-card:nth-child(7) { --i: 6; }
.social-card:nth-child(8), .project-card:nth-child(8) { --i: 7; }
.social-card:nth-child(9), .project-card:nth-child(9) { --i: 8; }
.social-card:nth-child(10), .project-card:nth-child(10) { --i: 9; }

/* Small phones: the pill now holds three things (wordmark, music, menu), so
   everything shrinks a step to keep fitting */
@media (max-width: 560px) {
    .header-content {
        padding: 8px 16px;
    }

    .header-content .wordmark {
        font-size: 22px;
    }

    .pages-button,
    .music-button {
        width: 48px;
        height: 48px;
    }

    .menu-icon,
    .music-icon {
        width: 48px;
        height: 48px;
    }

    /* Project cards go vertical on phones: smaller image on top, then the
       title and description below, back in the site's centred reading style */
    .project-card,
    .project-card.reverse {
        flex-direction: column;
    }

    .project-image {
        width: 60%; /* "smaller" than the desktop half */
        max-height: none; /* no crop at small sizes - natural aspect ratio */
    }

    .project-text,
    .project-card.reverse .project-text {
        text-align: center;
    }

    /* Four links don't fit on one row, so they go 2x2. The dots between them
       are hidden - in a grid each dot would take its own cell */
    .drawer-links {
        display: grid;
        grid-template-columns: 1fr 1fr;
        justify-items: center;
    }

    .drawer-links .dot {
        display: none;
    }
}

/* Freeze the motion for people who ask for reduced motion. This lives at the
   END of the file on purpose: these are overrides, and a rule declared earlier
   would lose to the `animation` shorthands further down (which reset
   animation-name back) - the reason the entrances kept animating regardless */
@media (prefers-reduced-motion: reduce) {
    .bg-blobs div {
        animation-play-state: paused;
    }

    /* No slide-in, no fading up, and the cards appear at rest */
    header,
    .social-card,
    .project-card {
        animation: none;
        transform: none;
    }
}
