/* ---------- Base ---------- */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

/* Named distinctly from the system "Helvetica" so every browser/OS
   renders this exact bundled file instead of substituting its own. */
@font-face {
    font-family: 'Helvetica Local';
    src: url('../fonts/Helvetica.ttf') format('truetype');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'Helvetica Local';
    src: url('../fonts/Helvetica-Bold.ttf') format('truetype');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

:root {
    --sidebar-bg: #efefed;
    --content-bg: #f7f7f7;
    --ink: #000000;
    --muted: #8a8a85;
    --rule: #d9d9d5;
    --border: #000000;
    --sidebar-width: clamp(280px, 30vw, 360px);

    --font-sans: 'Space Grotesk', -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
    --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    --font-name: 'Helvetica Local', Helvetica, Arial, sans-serif;
}

html, body {
    height: 100%;
}

/* Grey everywhere by default — .content paints its own white card on
   top of it (both the 10px-inset desktop card below and mobile's own
   margined card), so the gap around the card actually reads as a gap
   instead of blending into a same-color page. */
body {
    font-family: var(--font-sans);
    background: var(--sidebar-bg);
    color: var(--ink);
    line-height: 1.5;
}

a {
    color: inherit;
    text-decoration: none;
}

/* ---------- Page layout ---------- */
.page {
    display: grid;
    grid-template-columns: var(--sidebar-width) 1fr;
    min-height: 100vh;
}

/* ---------- Sidebar ---------- */
.sidebar {
    background: var(--sidebar-bg);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 16px 22px 20px;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow: hidden;
}

.sidebar-top {
    display: flex;
    flex-direction: column;
}

.name {
    font-family: var(--font-name);
    font-size: 24px;
    font-weight: 700;
    color: rgb(0, 0, 0);
    letter-spacing: -0.015em;
    line-height: 16px;
    margin-bottom: 4px;
}

.role {
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 18px;
    font-weight: 400;
    line-height: 20px;
    letter-spacing: 0.02em;
    color: rgb(0, 0, 0);
    margin-bottom: 18px;
}

/* At 18px this wraps to two lines within the sidebar's own width on
   desktop; sized down just enough to keep it on one line there. Mobile
   keeps the full 18px spec since the sidebar goes full-width there. */
@media (min-width: 861px) {
    .role {
        font-size: 15px;
    }
}

.pill-row {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
    margin-bottom: 22px;
}

/* Buttons are pre-flattened SVG art (rect + white text paths already
   baked in from the brand kit) rather than live text, so .pill is just
   a sizing/link wrapper around the <img>. No transform here — a
   rotate(), even at 0deg, promotes the element to its own compositing
   layer and can anti-alias the hover border unevenly at the corners
   ("broken" edges); buttons sit perfectly straight with no transform
   at all instead. */
.pill {
    display: inline-flex;
    align-items: center;
    border: 1px solid transparent;
    border-radius: 11px;
    transition: filter 0.15s ease;
    /* Kill the default mobile-browser tap flash (a translucent grey/blue
       overlay on touch) so tapping a button never shows any color
       change of its own — only a true :hover (below) does. */
    -webkit-tap-highlight-color: transparent;
}

.pill img {
    display: block;
    height: 48px;
    width: auto;
}

/* Hover no longer tints the black box — it previews the active state
   instead: box goes transparent (page background shows through),
   border appears, and the glyph inverts white->black, exactly like
   .pill--active below. The border is reserved (transparent) on .pill
   at all times, so it never has to be added on hover — nothing resizes
   or reflows when the glyph image swaps in, so a slow-loading swap
   can never show a collapsed/partial border.

   Scoped to (hover: hover) — devices with a real pointer — so a tap on
   touch/mobile never triggers or "sticks" this: touch browsers treat a
   tap as a momentary :hover match with no matching mouseleave, which
   would otherwise leave the button visually stuck in its hover color
   after being clicked. Clicking never changes a button's color on any
   device; only genuinely hovering it with a mouse does. */
@media (hover: hover) and (pointer: fine) {
    .pill:hover:not(.pill--active) {
        background: transparent;
        border-color: #000000;
    }

    .pill:hover:not(.pill--active) img {
        filter: invert(1);
    }
}

/* Nav buttons: same solid black-box asset as the home page (the box
   is baked into the SVG, not drawn in CSS). All three sit level, no
   tilt, flush on one line. */
.pill-row .pill img {
    height: 32px;
}

/* Current-page state: inverting the asset (black<->white) turns its
   own baked-in black box white and its white text black in one move —
   the thin border is just there so the now-white button still reads
   against the white page background. */
.pill--active {
    background: transparent;
    border: 1px solid #000000;
    border-radius: 11px;
}

.pill-row .pill--active img {
    filter: invert(1);
}

.doodle {
    display: flex;
    flex-direction: row;
    align-items: flex-end;
    gap: 6px;
}

.doodle svg {
    width: 100px;
    height: auto;
}

.fig-caption {
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 14px;
    font-weight: 700;
    line-height: 16px;
    color: rgb(0, 0, 0);
    padding-bottom: 2px;
}

.sidebar-bottom {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Bleeds past the sidebar's own horizontal padding (negative margins
   equal to it) so the hairline and the repeating "Links" text run edge
   to edge, instead of sitting inset like the rest of the sidebar
   content. .sidebar has overflow:hidden to clip this. */
.marquee {
    overflow: hidden;
    border-top: 1px solid var(--rule);
    border-bottom: 1px solid var(--rule);
    margin: 0 -22px;
    padding: 2px 0;
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 18px;
    font-weight: 400;
    line-height: 28px;
    color: rgb(0, 0, 0);
    mask-image: linear-gradient(to right, black 85%, transparent 100%);
}

/* Two identical copies of the text side by side, scrolled left by
   exactly one copy's width (-50%) on a seamless loop — as the first
   copy scrolls out of view the second is already in the same spot,
   so the loop point is invisible. */
.marquee-track {
    display: flex;
    width: max-content;
    white-space: nowrap;
    animation: marquee-scroll 34s linear infinite;
}

.marquee:hover .marquee-track {
    animation-play-state: paused;
}

@keyframes marquee-scroll {
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
    .marquee-track {
        animation: none;
    }
}

/* Flex-wrap, not a grid: each button hugs its own label width instead
   of being stretched to an equal column (that's what was turning "X"
   into a wide near-empty pill). Rows just wrap naturally. */
.social-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.social-grid .pill img {
    height: 34px;
}

/* ---------- Main content ---------- */
/* Floating white card: 10px gap on every side (from the sidebar, and
   from the viewport's top/right/bottom edges) at desktop widths, over
   the grey page background set on body above. Mobile overrides this
   entirely in the responsive block below (its own margin/padding, and
   only left/right — the header/footer bands provide the vertical
   separation there instead). */
.content {
    background: var(--content-bg);
    margin: 10px;
    padding: 24px 20px 4rem 24px;
}

.hero-image {
    position: relative;
    width: 100%;
    height: 78vh;
    background: #111111;
    border-radius: 4px;
    border: none;
    overflow: hidden;
}

.hero-slide {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity 0.6s ease;
}

.hero-slide.active {
    opacity: 1;
}

.work {
    margin-top: 55px;
}

/* font-family is Space Grotesk, not the Helvetica Local used for .name:
   Helvetica Local only ships 400/700 (see @font-face above), so a 600
   request on it font-matches to the nearest available weight, which per
   the CSS font-matching algorithm is 700 upward from 600 — i.e. it was
   silently rendering as Bold no matter what weight was requested here.
   Space Grotesk has a real 600 file loaded (see the Google Fonts link
   in index.html), so this is the only way to get genuine medium weight
   without a real Helvetica Medium file. */
.work h2 {
    font-family: var(--font-name);
    font-size: 24px;
    font-weight: 400;
    line-height: 24px;
    color: rgb(0, 0, 0);
    border-bottom: 1px solid var(--ink);
    padding-bottom: 8px;
}

.work-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 2.25rem 1.75rem;
    margin-top: 20px;
}

.work-card {
    display: flex;
    flex-direction: column;
}

.work-thumb {
    width: 100%;
    aspect-ratio: 4 / 3;
    border-radius: 0;
    background: #eee;
    margin-bottom: 14px;
    overflow: hidden;
    transition: border-radius 0.15s ease;
}

.work-thumb img,
.work-thumb video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.work-card:hover .work-thumb {
    border-radius: 30px;
}

.thumb-2 { background: linear-gradient(160deg, #b7f0c9 0%, #6fcf97 100%); }
.thumb-3 { background: linear-gradient(160deg, #f5e6c8 0%, #c9a25c 100%); }
.thumb-4 { background: linear-gradient(160deg, #cfd8e8 0%, #8f9fc2 100%); }

.work-card h3 {
    font-family: var(--font-name);
    font-size: 14px;
    font-weight: 700;
    line-height: 16px;
    color: rgb(0, 0, 0);
    margin-bottom: 0px;
}

.work-card p {
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 14px;
    font-weight: 400;
    line-height: 16px;
    color: rgb(0, 0, 0);
}

/* ---------- Archive page ---------- */
.archive-header {
    margin-bottom: 32px;
}

.archive-subtitle {
    font-family: var(--font-name);
    font-size: 14px;
    font-weight: 400;
    line-height: 16px;
    color: rgb(0, 0, 0);
    margin-top: 4px;
}

/* Even grid, not masonry — every card (the slideshow square included)
   shares the same 1:1 size, so a plain 2-column grid keeps them aligned
   exactly instead of the variable-height column-fill layout this used
   to be. */
.archive-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 1.75rem;
}

.archive-card {
    display: block;
}

.archive-thumb {
    width: 100%;
    aspect-ratio: 1 / 1;
    border-radius: 0;
    background: #eee;
    margin-bottom: 12px;
    overflow: hidden;
}

/* Real archive images are portrait (4:5) — cover-crop into the square
   thumb box rather than stretching or letterboxing. */
.archive-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Full-poster cards (nothing cropped) — a black frame around the
   whole piece, like a poster shown on a wall, same on mobile and
   desktop since the square box and padding are both percentage/
   aspect-ratio based. */
.archive-thumb--framed {
    background: #000000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 10%;
}

.archive-thumb--framed img {
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* Same "nothing cropped" idea as --framed, but for pieces (like the
   illustrations) that are already a full self-contained scene rather
   than a poster mockup — the default light thumb background instead
   of a black frame. */
.archive-thumb--full {
    background: #eee;
    display: flex;
    align-items: center;
    justify-content: center;
}

.archive-thumb--full img {
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* Extra breathing room for a --full piece that otherwise runs edge to
   edge (a device mockup, say) — stack with .archive-thumb--full. */
.archive-thumb--pad {
    padding: 10%;
}

/* Square looping video — first archive card. */
.archive-square {
    position: relative;
    width: 100%;
    aspect-ratio: 1 / 1;
    background: #111111;
    border-radius: 0;
    overflow: hidden;
    margin-bottom: 12px;
}

.archive-square video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Solid black card carrying just a big wordmark, matching the "Karusel"
   reference card — same idea as the home page's Selected Work thumbs,
   just with baked-in type instead of a photo. */
.archive-thumb-karusel {
    background: #000000;
    display: flex;
    align-items: center;
    justify-content: center;
}

.archive-thumb-logo {
    font-family: var(--font-name);
    font-size: 2.25rem;
    font-weight: 700;
    color: #ffffff;
    letter-spacing: -0.01em;
}

/* Same text styling as the Selected Work cards on the home page:
   Helvetica bold for any linked title, Courier Prime for the rest. */
.archive-caption {
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 14px;
    font-weight: 400;
    line-height: 16px;
    color: rgb(0, 0, 0);
}

.archive-link {
    font-family: var(--font-name);
    font-weight: 700;
    color: inherit;
    text-decoration: underline;
}

/* ---------- About page ---------- */
.about-content {
    display: flex;
    flex-direction: column;
    padding: 0;
}

/* No-scroll is a desktop-only constraint: on mobile the grid stacks to
   one column (see the responsive block below) and this much content
   genuinely needs more than one screen, so it scrolls normally there
   instead of clipping. min-height:100vh lives here too (not on the
   base rule) — on mobile it has no business forcing the card to full
   viewport height, since that's what stretched .status-bar's
   margin-top:auto down to the bottom of the screen, leaving a huge
   gap above "Last played" instead of sitting close to Credits. */
@media (min-width: 861px) {
    .about-content {
        /* .content now carries a 10px top+bottom margin (see the
           floating-card rule above) — subtract that back out so the
           locked-height card still ends exactly at the viewport edge
           instead of overflowing it by 20px. */
        min-height: calc(100vh - 20px);
        height: calc(100vh - 20px);
        overflow: hidden;
        /* Same "starts 20px into the card" spec as the project page —
           .about-grid's own 40px padding-top is zeroed out where that
           rule is defined below, so this is the only top offset left
           in play. box-sizing:border-box (global) keeps this inside
           the locked height above, not added on top of it. */
        padding-top: 20px;
    }
}

/* align-items is the default (stretch): .about-left and .about-right
   both stretch to whichever is taller, so the portrait's margin-top:
   auto below can push it to the bottom of that shared height. A fixed
   px offset here would overflow on shorter screens instead of adapting
   — the page must never need to scroll. */
/* No flex:1 here deliberately: the grid sizes to its natural content
   height (whichever column is taller), and .status-bar's margin-top:
   auto absorbs whatever's left in the flex column below it — that gap
   is what leaves the portrait sitting mid-page instead of dragged down
   to the footer. */
.about-grid {
    display: grid;
    grid-template-columns: minmax(280px, 32%) 1fr;
    gap: 40px;
    padding: 40px 24px 0;
}

/* Desktop only: zeroes the padding-top above out — .about-content's
   own 20px (set in the min-width:861px block up top) is the only top
   offset left, matching the project page's spec. */
@media (min-width: 861px) {
    .about-grid {
        padding-top: 0;
    }
}

.about-left {
    display: flex;
    flex-direction: column;
}

.page-title {
    font-family: var(--font-name);
    font-size: 36px;
    font-weight: 700;
    letter-spacing: -0.015em;
    line-height: 24px;
    color: rgb(0, 0, 0);
    margin: 0;
}

.about-portrait {
    width: 205px;
    margin-top: auto;
}

.about-portrait img {
    width: 100%;
    height: auto;
    display: block;
}

.about-right {
    min-width: 0;
}

.about-bio {
    font-family: var(--font-name);
    font-size: 18px;
    font-weight: 400;
    line-height: 20px;
    color: rgb(0, 0, 0);
    max-width: 58ch;
    margin: 0;
}

.about-bio + .about-bio {
    margin-top: 28px;
}

.about-right a {
    color: inherit;
    text-decoration: underline;
}

.meta-cols {
    display: grid;
    grid-template-columns: 287px auto;
    margin-top: 60px;
}

.section-label {
    font-family: 'Courier Prime', var(--font-mono);
    font-weight: 400;
    font-size: 1.15rem;
    color: rgb(0, 0, 0);
    margin: 0 0 8px;
}

.meta-list {
    list-style: none;
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 1.05rem;
    line-height: 1.2;
    color: rgb(0, 0, 0);
}

.skills-list {
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 14px;
    font-weight: 400;
    line-height: 15px;
    word-spacing: -2px;
}

.skills-title {
    font-size: 14px;
    line-height: 20px;
}

.meta-list--links a {
    text-decoration: underline;
}

.credits-block {
    margin-top: 60px;
}

.contact-title,
.credits-title {
    font-size: 14px;
    line-height: 20px;
}

.contact-list {
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 14px;
    font-weight: 400;
    line-height: 15px;
    word-spacing: -2px;
}

.credits-body {
    max-width: 220px;
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 14px;
    font-weight: 400;
    line-height: 15px;
    color: rgb(0, 0, 0);
    word-spacing: -2px;
}

/* ---------- Project page ---------- */
/* Same two-column shape as .about-grid (fixed-ish left rail, flexible
   right column) — reused here under its own name since a project page
   isn't the About page, just built from the same proportions. */
.project-grid {
    display: grid;
    grid-template-columns: minmax(280px, 32%) 1fr;
    gap: 40px;
    padding: 40px 24px 0;
}

.project-left {
    display: flex;
    flex-direction: column;
}

.project-subtitle {
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 18px;
    font-weight: 400;
    line-height: 20px;
    letter-spacing: 0.02em;
    color: rgb(0, 0, 0);
    margin-top: 8px;
}

.project-right {
    min-width: 0;
}

/* .about-bio's own text size/spacing (18px/20px, Helvetica Local),
   reused verbatim per spec — only the stacking gap differs slightly
   since project write-ups run to more paragraphs than the bio. */
.project-right .about-bio + .about-bio {
    margin-top: 12px;
}

/* All project pages: a size down from the shared 18px/20px .about-bio
   spec — project write-ups run longer than the About page's bio. */
.project-right .about-bio {
    font-size: 15px;
    line-height: 18px;
}

.project-meta {
    margin-top: 48px;
}

/* Same 14px/20px treatment as the About page's Skills/Contact/Credits
   labels (.skills-title, .contact-title, .credits-title). */
.project-meta-title {
    font-size: 14px;
    line-height: 20px;
}

/* Same 14px/15px treatment as the About page's Skills/Contact/Credits
   values (.skills-list, .contact-list, .credits-body). */
.project-meta-list {
    font-size: 14px;
    line-height: 15px;
    word-spacing: -2px;
}

.project-hero {
    width: 100%;
    margin-top: 16px;
}

.project-hero img,
.project-hero video {
    width: 100%;
    height: auto;
    display: block;
}

/* Two frames side by side, same size, facing each other — for a pair of
   related screens (e.g. Yango Tech frames 4+5, 6+7) instead of the
   default full-width stack. */
.project-hero-pair {
    display: flex;
    gap: 16px;
    margin-top: 16px;
}

.project-hero-pair .project-hero {
    margin-top: 0;
    flex: 1;
    min-width: 0;
}

/* Desktop only: the title/description block should start 20px into
   the card, not the 64px it'd get from .content's own 24px padding-top
   plus .project-grid's 40px — overriding both back down to net 20px. */
@media (min-width: 861px) {
    .project-content {
        padding-top: 20px;
    }

    .project-grid {
        padding-top: 0;
    }
}

@media (max-width: 860px) {
    .project-grid {
        grid-template-columns: 1fr;
        padding: 4px 0 0;
        gap: 16px;
    }

    .project-subtitle {
        margin-top: 2px;
    }

    /* Mobile-only: match the About page's Skills/Contact text size
       (.skills-list/.contact-list, 14px/15px) — overrides the generic
       mobile .about-bio bump (26px line-height) further down, since
       this selector is more specific. Desktop keeps the full 18px/20px
       body-copy spec. */
    .project-right .about-bio {
        font-size: 14px;
        line-height: 15px;
    }

    .project-meta {
        grid-template-columns: 1fr 1fr;
        gap: 16px;
        margin-top: 32px;
    }

    .project-hero {
        margin-top: 12px;
    }

    .project-hero-pair {
        gap: 8px;
        margin-top: 12px;
    }
}

/* margin-top:auto on a flex-column ancestor (.about-content) pins this
   to the bottom of the viewport regardless of how much content is
   above it. No rule above it, per spec. */
/* Grid, not flex, on desktop: location and the clock each get their
   own fixed-content ("auto") column, so a long "now playing" track
   title has nowhere to push them — it just ellipsizes within its own
   flexible (1fr) column instead (see #np-track below). */
.status-bar {
    display: grid;
    grid-template-columns: 1fr auto auto;
    column-gap: 24px;
    align-items: baseline;
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 1.1rem;
    color: rgb(0, 0, 0);
    margin-top: auto;
    padding: 24px;
}

/* Flex row so the label always stays fully visible and only the
   (potentially long) track title truncates — on one line, with an
   ellipsis, never wrapping. Same rule on desktop and mobile; only
   #np's own width (grid column vs. full-width row) differs. */
#np {
    display: flex;
    min-width: 0;
}

.status-location,
#clock {
    white-space: nowrap;
}

#np-label {
    flex-shrink: 0;
    text-decoration: underline;
    color: inherit;
}

#np-track {
    flex: 1;
    min-width: 0;
    margin-left: 8px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.status-location {
    font-family: var(--font-name);
    font-size: 17px;
    font-weight: 400;
    line-height: 24px;
    color: rgb(0, 0, 0);
}

#clock {
    font-family: 'Courier Prime', var(--font-mono);
    font-size: 18px;
    font-weight: 400;
    line-height: 16px;
    color: rgb(0, 0, 0);
    font-variant-numeric: tabular-nums;
}

@media (max-width: 860px) {
    .status-bar {
        display: flex;
        font-size: 14px;
        line-height: 15px;
        gap: 8px 20px;
        flex-wrap: wrap;
    }

    #np-label,
    #np-track,
    .status-location,
    #clock {
        font-size: 14px;
        line-height: 15px;
    }

    .status-location {
        font-family: 'Courier Prime', var(--font-mono);
        font-weight: 400;
    }
}

/* ---------- Responsive ---------- */
@media (max-width: 860px) {
    .page {
        display: flex;
        flex-direction: column;
    }

    .sidebar {
        display: contents;
    }

    .sidebar-top {
        order: 1;
        background: var(--sidebar-bg);
        padding: 1.15rem 1.5rem 1.15rem;
    }

    .role {
        font-size: 15px;
        line-height: 18px;
        white-space: nowrap;
        margin-bottom: 14px;
    }

    .pill-row {
        margin-bottom: 16px;
    }

    /* The page's ambient background matches the header/footer bands
       (--sidebar-bg) so .content reads as a distinct floating card
       rather than blending into the same tone as the page around it. */
    body {
        background: var(--sidebar-bg);
    }

    .content {
        order: 2;
        background: var(--content-bg);
        margin: 0 12px;
        padding: 1.75rem 1.25rem 3rem;
    }

    /* About's floating card hugs its own text more tightly than the
       Work/Archive grids — 10px in from the card edge on both sides,
       per the reference layout, rather than the shared 1.25rem. */
    .about-content {
        padding-left: 10px;
        padding-right: 10px;
    }

    .sidebar-bottom {
        order: 3;
        background: var(--sidebar-bg);
        padding: 1.5rem 1.5rem 2rem;
    }

    .hero-image {
        height: 50vh;
    }

    /* Mobile-only: smaller than desktop's 24px, but a bit bigger than
       the 14px project title/subtitle text so it still reads as a
       section heading. */
    .work h2 {
        font-size: 18px;
        line-height: 20px;
    }

    .work-grid {
        grid-template-columns: 1fr;
    }

    .about-grid {
        grid-template-columns: 1fr;
        padding: 4px 0 0;
        gap: 16px;
    }

    /* Heading and portrait sit in the same row, both pinned to
       flex-start, so their top edges line up exactly. */
    .about-left {
        flex-direction: row;
        align-items: flex-start;
        justify-content: space-between;
        gap: 16px;
    }

    /* Mobile-only: match the Selected Work project description text
       size (.work-card p — 14px/16px) but keep the same font-family as
       desktop (Helvetica Local, not Courier Prime). */
    .about-bio {
        font-size: 14px;
        line-height: 16px;
    }

    .page-title {
        font-size: 1.6rem;
    }

    /* Archive's "Archive" heading keeps the full desktop spec (36px/24px)
       at every width — only About's mobile title is downsized above. */
    .archive-header .page-title {
        font-size: 36px;
        line-height: 24px;
    }

    .about-portrait {
        width: 90px;
        margin-top: 0;
        flex-shrink: 0;
    }

    .meta-cols {
        grid-template-columns: 1fr 1fr;
        gap: 16px;
        margin-top: 24px;
    }

    .credits-block {
        margin-top: 24px;
    }

    .status-bar {
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
        gap: 8px 20px;
        margin-top: 0;
        padding: 24px 0 0;
    }

    /* Now-listening always gets its own full-width row, and the
       location/clock row below it gets extra top margin as a buffer.
       The track title itself never wraps — it ellipsizes instead, see
       the base #np/#np-track rules above. Weather sits at the left
       edge, time at the right (justify-content above). */
    #np {
        flex: 0 0 100%;
    }

    .status-location,
    #clock {
        margin-top: 16px;
    }

    .archive-grid {
        grid-template-columns: 1fr;
    }
}
