/* =====================================================================
   BENJAMIN GAMMAGE: STANDALONE HOMEPAGE STYLES
   =====================================================================
   Goes with index.html in this folder. Plain CSS, no build step.

   Layout values (padding, font sizes, gaps) mostly live as inline
   style="" attributes in index.html. This file holds everything that
   inline styles can't do: animations, hover states, responsive rules
   and shared components.

   Contents
     0.  Colour tokens
     1.  Base
     2.  Hero background grid
     3.  Entrance animations (page load)
     4.  Status dot
     5.  Text link underline
     6.  Buttons
     7.  Code card (typing, bars, scan line)
     8.  Logo badge spin
     9.  Marquees (topic ticker + Say hello)
     10. At a glance cards
     11. Blog rows
     12. Videos
     13. Newsletter input
     14. Footer bits
     15. Scroll reveal
     16. Reduced motion
     17. Responsive
   ===================================================================== */


/* =====================================================================
   0. COLOUR TOKENS
   ---------------------------------------------------------------------
   Taken from the @theme block in the gammagelabs repo (input.css):
     --bg      #00343d  (--color-primary)
     --ink     #c0f0e0  (--color-secondary)
     --accent  #9ed9c9  (--color-primary_darker)
     --line    #33666b  (--color-secondary_light)
   The rest are in-between shades. The HTML also uses these hex values
   inline, so a colour change means find-and-replace in both files.
   ===================================================================== */
/* Dark is the default, exactly like the current site (body without a class).
   Light mode is `body.light-mode`, the same switch the current site uses.
   Current-site tokens:  dark  bg #00343d / text #c0f0e0 / accent #9ed9c9
                         light bg #c0f0e0 / text #00343d / accent #00343d
   The in-between shades below are derived so every page flips cleanly. */
:root {
    color-scheme: dark;
    --bg: #00343d;
    --ink: #c0f0e0;
    --accent: #9ed9c9;        /* fills: buttons, bands, hover fills */
    --hl: #9ed9c9;            /* accent used as TEXT (kickers, highlighted words) */
    --muted: #86b5ab;         /* small labels */
    --soft: #a8d6c8;          /* secondary paragraphs */
    --prose: #cdeee2;         /* long-form body text */
    --line: #33666b;
    --line-soft: #1f5a62;     /* card and row borders */
    --surface: #063f48;       /* card fill, row hover */
    --grid: #0d4650;          /* hero grid lines */
    --bg-deep: #002d35;       /* alternate section background */
    --dash: #4f8580;
    --header-bg: rgba(0,52,61,.86);
    --ph-bg: rgba(6,63,72,.5);
    --shadow: rgba(0, 0, 0, .28);
    --ease: cubic-bezier(.2, .8, .2, 1);
}

body.light-mode {
    color-scheme: light;
    --bg: #c0f0e0;
    --ink: #00343d;
    --accent: #00343d;
    --hl: #0a6b6f;
    --muted: #2f666b;
    --soft: #1c5560;
    --prose: #08404a;
    --line: #7fbcae;
    --line-soft: #9ad6c4;
    --surface: #b3e7d4;
    --grid: #aee3d1;
    --bg-deep: #b4e8d6;
    --dash: #3f7f7f;
    --header-bg: rgba(192,240,224,.88);
    --ph-bg: rgba(168,224,205,.55);
    --shadow: rgba(0,52,61,.22);
}

html.light-mode-preload { background: #c0f0e0; }


/* =====================================================================
   1. BASE
   ===================================================================== */
*,
*::before,
*::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
}

a {
    color: var(--ink);
}

a:hover {
    color: var(--accent);
}

/* Wrapper around the whole page. overflow-x: hidden stops the
   marquees from creating a sideways scrollbar. */
.bg-root {
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
    color: var(--ink);
    background: var(--bg);
    overflow-x: hidden;
}

.mono {
    font-family: 'IBM Plex Mono', ui-monospace, monospace;
}

/* IBM Plex Mono tops out at 700, so any 800 in the HTML maps to 700. */
.bg-root [style*="font-weight: 800"] {
    font-weight: 700 !important;
}

/* Centered content column used by every section. */
.wrap {
    max-width: 1240px;
    margin: 0 auto;
    padding: 0 32px;
}


/* =====================================================================
   2. HERO BACKGROUND GRID
   Faint graph paper that drifts diagonally. 56px appears in both
   background-size and the keyframe so the loop is seamless.
   ===================================================================== */
.gridbg {
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: .5;
    background-image:
        linear-gradient(var(--grid) 1px, transparent 1px),
        linear-gradient(90deg, var(--grid) 1px, transparent 1px);
    background-size: 56px 56px;
    animation: drift 40s linear infinite;
}

@keyframes drift {
    to { background-position: 56px 56px; }
}


/* =====================================================================
   3. ENTRANCE ANIMATIONS (on page load)
   ---------------------------------------------------------------------
   .rise  fades an element up 28px. Its delay is set inline in the HTML
          (style="animation-delay: ...") so each item waits its turn.
   .w     same, for each word of the headline.
   ===================================================================== */
@keyframes rise {
    from { opacity: 0; transform: translateY(28px); }
    to   { opacity: 1; transform: none; }
}

.rise {
    opacity: 0;
    animation: rise .9s var(--ease) forwards;
}

.w {
    display: inline-block;
    opacity: 0;
    animation: rise .8s var(--ease) forwards;
}

/* Blinking cursor after the headline. */
.caret {
    display: inline-block;
    width: .08em;
    height: .85em;
    margin-left: .08em;
    vertical-align: -.05em;
    animation: blink 1s steps(1) infinite;
}

@keyframes blink {
    50% { opacity: 0; }
}


/* =====================================================================
   4. STATUS DOT
   The ::after is a copy of the dot that grows and fades (the "ping").
   The dot colour is set inline; the ring inherits it.
   ===================================================================== */
.dot {
    position: relative;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    flex-shrink: 0;
}

.dot::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: inherit;
    animation: ping 1.8s cubic-bezier(0, 0, .2, 1) infinite;
}

@keyframes ping {
    75%, 100% { transform: scale(2.6); opacity: 0; }
}


/* =====================================================================
   5. TEXT LINK UNDERLINE
   Draws in from the left on hover, leaves to the right on mouse-out.
   The trick is flipping transform-origin between the two states.
   ===================================================================== */
.ul {
    position: relative;
    text-decoration: none;
}

.ul::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -4px;
    height: 2px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: right;
    transition: transform .35s ease;
}

.ul:hover::after {
    transform: scaleX(1);
    transform-origin: left;
}


/* =====================================================================
   6. BUTTONS
   Pills that lift 3px on hover while the arrow (.arr) slides right.
   ===================================================================== */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-height: 48px;              /* comfortable touch target */
    padding: 0 22px;
    border-radius: 999px;
    text-decoration: none;
    font-weight: 600;
    transition: transform .25s ease, background .25s ease, color .25s ease;
}

.btn:hover {
    transform: translateY(-3px);
}

.btn .arr {
    transition: transform .25s ease;
}

.btn:hover .arr {
    transform: translateX(5px);
}

.btn-solid {
    background: var(--accent);
    color: var(--bg);
}

.btn-solid:hover {
    background: var(--ink);
    color: var(--bg);
}

.btn-ghost {
    border: 1.5px solid var(--line);
    color: var(--ink);
}

.btn-ghost:hover {
    border-color: var(--ink);
    color: var(--ink);
}


/* =====================================================================
   7. CODE CARD
   ===================================================================== */

/* Typing: each line grows from width 0 to --n (set inline, in ch =
   character widths) in steps, so it looks typed. If you edit a line's
   text, update its --n to the new character count. */
.code-line {
    white-space: nowrap;
    overflow: hidden;
    width: 0;
    animation: type 1.1s steps(28, end) forwards;
}

@keyframes type {
    to { width: var(--n); }
}

/* Whole card bobs up and down with a tiny tilt. */
.float {
    animation: floaty 7s ease-in-out infinite;
}

@keyframes floaty {
    50% { transform: translateY(-12px) rotate(-.6deg); }
}

/* Bars run two animations: grow once, then breathe forever.
   The two delays per bar are set inline in the HTML, in that order. */
.bars {
    display: flex;
    align-items: flex-end;
    gap: 8px;
    height: 150px;
}

.bar {
    flex: 1;
    border-radius: 4px 4px 0 0;
    transform-origin: bottom;
    animation: grow 1.2s var(--ease) both, breathe 3.6s ease-in-out infinite;
}

@keyframes grow {
    from { transform: scaleY(0); }
}

@keyframes breathe {
    50% { transform: scaleY(.72); }
}

/* Glowing line sweeping across the chart. */
.scan {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--accent);
    box-shadow: 0 0 18px var(--accent);
    animation: scan 4.5s ease-in-out infinite;
}

@keyframes scan {
    0%   { left: 0; }
    50%  { left: calc(100% - 2px); }
    100% { left: 0; }
}


/* =====================================================================
   8. LOGO BADGE SPIN (nav)
   ===================================================================== */
.orbit {
    animation: spin 18s linear infinite;
}
.orbit-photo { overflow: hidden; }
.orbit-photo img { height: 100%; object-fit: cover; width: 100%; }

@keyframes spin {
    to { transform: rotate(360deg); }
}


/* =====================================================================
   9. MARQUEES
   ---------------------------------------------------------------------
   The HTML holds two identical copies of the text side by side.
   Sliding left by exactly 50% lands where copy 2 began, so the loop
   never jumps. Bigger duration = slower.
   ===================================================================== */
.marquee {
    display: flex;
    width: max-content;
    animation: slide 28s linear infinite;
}

/* Footer "Say hello": opposite direction, a little slower. */
.marquee.rev {
    animation-direction: reverse;
    animation-duration: 36s;
}

@keyframes slide {
    to { transform: translateX(-50%); }
}


/* =====================================================================
   10. AT A GLANCE CARDS
   ---------------------------------------------------------------------
   Hover: an accent layer (::before) parked below the card slides up to
   fill it, the card lifts 8px and tilts, and the arrow icon rotates.
   ===================================================================== */
.cards {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 20px;
}

.card {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    min-height: 260px;
    padding: 28px;
    border: 1.5px solid var(--line-soft);
    border-radius: 20px;
    text-decoration: none;
    color: var(--ink);
    background: var(--surface);
    overflow: hidden;
    transition: transform .35s var(--ease), border-color .35s ease;
}

.card::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    background: var(--accent);
    transform: translateY(101%);
    transition: transform .45s cubic-bezier(.7, 0, .2, 1);
}

/* Keeps the text above the sliding fill. */
.card > * {
    position: relative;
    z-index: 1;
    transition: color .3s ease;
}

.card:hover {
    transform: translateY(-8px) rotate(-.5deg);
    border-color: var(--accent);
    color: var(--bg);
}

.card:hover::before {
    transform: translateY(0);
}

/* !important because the muted colour is set inline in the HTML. */
.card:hover .muted {
    color: var(--bg) !important;
}

.card .ico {
    transition: transform .45s var(--ease);
}

.card:hover .ico {
    transform: rotate(-45deg) scale(1.1);
}


/* =====================================================================
   11. BLOG ROWS
   Hover: row slides right 16px, gets a soft fill, title turns accent,
   and the round arrow button rotates and fills.
   ===================================================================== */
.post {
    display: grid;
    grid-template-columns: 160px minmax(0, 1fr) 56px;
    align-items: center;
    gap: 24px;
    padding: 30px 8px;
    border-top: 1.5px solid var(--line-soft);
    text-decoration: none;
    color: var(--ink);
    transition: padding .35s ease, background .35s ease;
}

.post:hover {
    padding-left: 24px;
    background: var(--surface);
    color: var(--ink);
}

.post .pt {
    transition: color .3s ease;
}

.post:hover .pt {
    color: var(--accent);
}

.post .go {
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: 1.5px solid var(--line);
    transition: transform .35s ease, background .35s ease, border-color .35s ease;
}

.post:hover .go {
    transform: rotate(-45deg);
    background: var(--accent);
    border-color: var(--accent);
    color: var(--bg);
}


/* =====================================================================
   12. VIDEOS
   Each tile is a YouTube thumbnail link. The play button sends out a
   repeating ripple ring; the tile scales up slightly on hover.
   ===================================================================== */
.vids {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 20px;
}

.vid {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-radius: 16px;
    border: 1.5px solid var(--line-soft);
    background: var(--surface);
    text-decoration: none;
    color: var(--ink);
    transition: transform .35s ease;
}

.vid:hover {
    transform: scale(1.03);
}

/* Thumbnail fills the tile, dimmed so the play button stands out. */
.vid .thumb {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    filter: brightness(.7);
    transition: filter .35s ease;
}

.vid:hover .thumb {
    filter: brightness(.85);
}

.vid .play {
    position: relative;
    width: 64px;
    height: 64px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--ink);
    color: var(--bg);
    transition: transform .35s ease, background .35s ease;
}

.vid:hover .play {
    transform: scale(1.15);
    background: var(--accent);
}

.vid .ring {
    position: absolute;
    width: 64px;
    height: 64px;
    border-radius: 50%;
    border: 2px solid var(--ink);
    animation: ripple 2.4s ease-out infinite;
}

@keyframes ripple {
    from { transform: scale(1);   opacity: .7; }
    to   { transform: scale(2.4); opacity: 0; }
}

/* Little bouncing equaliser next to "YouTube · Twitch · Kick". */
.eq {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 16px;
}

.eq span {
    width: 3px;
    background: var(--accent);
    animation: eq .9s ease-in-out infinite;
}

@keyframes eq {
    0%, 100% { height: 4px; }
    50%      { height: 16px; }
}


/* =====================================================================
   13. NEWSLETTER INPUT
   ===================================================================== */
.field {
    flex: 1;
    min-height: 52px;
    padding: 0 20px;
    border-radius: 999px;
    border: 1.5px solid var(--line);
    background: var(--bg);
    color: var(--ink);
    font: inherit;
    font-size: 16px;              /* 16px stops iOS from zooming on focus */
    transition: border-color .3s ease, box-shadow .3s ease;
}

.field:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 25%, transparent);
}


/* =====================================================================
   14. FOOTER BITS
   ===================================================================== */

/* Social pills lift and turn accent on hover. */
.social {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 16px;
    border: 1.5px solid var(--line-soft);
    border-radius: 999px;
    text-decoration: none;
    color: var(--ink);
    transition: transform .25s ease, border-color .25s ease, color .25s ease;
}

.social:hover {
    transform: translateY(-4px);
    border-color: var(--accent);
    color: var(--accent);
}

/* Giant scrolling "Say hello". clamp() scales it with the screen. */
.giant {
    font-size: clamp(72px, 15vw, 220px);
    font-weight: 800;
    letter-spacing: -.04em;
    line-height: .9;
    white-space: nowrap;
}

/* "hello" drawn as outline only. */
.giant .o {
    -webkit-text-stroke: 2px var(--ink);
    color: transparent;
}


/* =====================================================================
   15. SCROLL REVEAL
   ---------------------------------------------------------------------
   CSS scroll-driven animations: elements fade up as they scroll into
   view, no JavaScript. Chrome and Edge support it; other browsers skip
   this block and simply show the content.

   These keyframes animate the separate "translate" property instead of
   "transform", so they don't override the hover lift on cards and
   videos (which use "transform").
   ===================================================================== */
@supports (animation-timeline: view()) {
    .reveal {
        animation: reveal-up linear both;
        animation-timeline: view();
        animation-range: entry 0% cover 28%;
    }

    .reveal-x {
        animation: slidein linear both;
        animation-timeline: view();
        animation-range: entry 0% cover 30%;
    }
}

@keyframes reveal-up {
    from { opacity: 0; translate: 0 28px; }
    to   { opacity: 1; translate: none; }
}

@keyframes slidein {
    from { opacity: 0; translate: -60px 0; }
    to   { opacity: 1; translate: none; }
}


/* =====================================================================
   16. REDUCED MOTION
   Visitors with "reduce motion" on get the finished page, no movement.
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        animation-delay: 0s !important;
        transition-duration: .01ms !important;
    }

    .reveal,
    .reveal-x {
        animation: none !important;
    }

    .dot::after,
    .vid .ring {
        display: none;
    }
}


/* =====================================================================
   17. RESPONSIVE
   The !important flags are needed because these override inline styles.
   ===================================================================== */

/* Tablet */
@media (max-width: 980px) {
    .hero {
        grid-template-columns: minmax(0, 1fr) !important;   /* stack hero */
    }

    .cards {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .vids {
        grid-template-columns: minmax(0, 1fr);
    }

    .split {
        grid-template-columns: minmax(0, 1fr) !important;   /* stack blog + footer */
    }

    /* The nav links hide here. This standalone version has no mobile
       menu; the Eleventy version keeps Benjamin's existing burger menu. */
    .navlinks {
        display: none !important;
    }
}

/* Phone */
@media (max-width: 600px) {
    .wrap {
        padding: 0 16px;
    }

    .cards {
        grid-template-columns: minmax(0, 1fr);
    }

    .post {
        grid-template-columns: minmax(0, 1fr) 48px;
    }

    .post .pd {
        grid-column: 1 / -1;     /* date moves above the title */
    }

    .h1 {
        font-size: 48px !important;
    }

    .newsrow {
        flex-direction: column !important;
    }
}


/* =====================================================================
   18. MULTI-PAGE ADDITIONS
   Shared by every inner page: page header, prose, mobile menu, forms,
   filters, project cards. Added when the redesign grew past the homepage.
   ===================================================================== */

/* Current page in the nav */
.navlinks a { color: var(--ink); }
.navlinks a[aria-current="page"] { color: var(--accent); }
.navlinks a[aria-current="page"]::after { transform: scaleX(1); }

/* Mobile menu (no JavaScript: a <details> element). Hidden on desktop. */
.menu { display: none; position: relative; }
.menu summary {
    list-style: none; cursor: pointer; min-height: 44px; padding: 0 18px;
    display: inline-flex; align-items: center; border-radius: 999px;
    border: 1.5px solid var(--line); color: var(--ink); font-weight: 600; font-size: 15px;
}
.menu summary::-webkit-details-marker { display: none; }
.menu[open] summary { border-color: var(--accent); color: var(--accent); }
.menu-panel {
    position: absolute; right: 0; top: 56px; min-width: 220px; z-index: 30;
    display: flex; flex-direction: column; gap: 4px; padding: 12px;
    background: var(--surface); border: 1.5px solid var(--line-soft); border-radius: 18px;
    box-shadow: 0 30px 60px var(--shadow);
}
.menu-panel a { padding: 12px 14px; border-radius: 10px; text-decoration: none; font-size: 17px; }
.menu-panel a:hover { background: var(--bg); }

/* Inner page header */
.phead { position: relative; overflow: hidden; padding: 88px 0 72px; border-bottom: 1px solid var(--grid); }
.phead .inner { position: relative; display: flex; flex-direction: column; gap: 22px; }
.kicker { font-size: 13px; letter-spacing: .14em; color: var(--accent); text-transform: uppercase; display: flex; align-items: center; gap: 12px; }
.phead h1 { margin: 0; font-size: clamp(44px, 7vw, 88px); line-height: 1.02; font-weight: 700; letter-spacing: -.04em; max-width: 16ch; }
.phead h1.wide { max-width: 22ch; }
.phead .lede { margin: 0; max-width: 640px; font-size: 20px; line-height: 1.55; color: var(--soft); }
.crumbs { font-size: 14px; color: var(--muted); display: flex; gap: 10px; flex-wrap: wrap; }
.crumbs a { text-decoration: none; color: var(--muted); }
.crumbs a:hover { color: var(--accent); }

/* Long-form text */
.prose { max-width: 720px; }
.prose h2 { margin: 56px 0 16px; font-size: clamp(28px, 3.4vw, 40px); line-height: 1.1; letter-spacing: -.03em; font-weight: 700; scroll-margin-top: 110px; }
.prose h2:first-child { margin-top: 0; }
.prose p { margin: 0 0 20px; font-size: 18px; line-height: 1.75; color: var(--prose); }
.prose a { color: var(--accent); text-underline-offset: 4px; }
.prose a:hover { color: var(--ink); }
.prose blockquote {
    margin: 28px 0; padding: 4px 0 4px 24px; border-left: 3px solid var(--accent);
    font-size: 24px; line-height: 1.4; font-weight: 600; letter-spacing: -.01em; color: var(--ink);
}
.prose .pull { font-size: clamp(26px, 3.4vw, 38px); line-height: 1.2; font-weight: 700; letter-spacing: -.03em; color: var(--accent); margin: 32px 0; }
.prose .ph {
    margin: 0 0 20px; padding: 16px 18px; border: 1.5px dashed var(--line); border-radius: 14px;
    font-size: 15px; line-height: 1.6; color: var(--muted); background: var(--ph-bg);
}
.prose .ph b { color: var(--accent); font-weight: 600; letter-spacing: .08em; font-size: 12px; text-transform: uppercase; display: block; margin-bottom: 6px; }

/* Expandable employment history on About */
.past-jobs { margin: 36px 0 8px; border-top: 1.5px solid var(--line-soft); border-bottom: 1.5px solid var(--line-soft); }
.past-jobs summary { display: flex; align-items: center; justify-content: space-between; padding: 18px 0; cursor: pointer; color: var(--ink); font-size: 20px; font-weight: 600; list-style: none; }
.past-jobs summary::-webkit-details-marker { display: none; }
.past-jobs summary span { color: var(--accent); font-size: 28px; font-weight: 400; line-height: 1; transition: transform .25s ease; }
.past-jobs[open] summary span { transform: rotate(45deg); }
.past-jobs nav { display: flex; flex-direction: column; gap: 12px; padding: 0 0 20px; }
.past-jobs nav a { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px 16px; border: 1.5px solid var(--line-soft); border-radius: 12px; text-decoration: none; color: var(--prose); transition: border-color .25s ease, color .25s ease, transform .25s ease; }
.past-jobs nav a:hover { border-color: var(--accent); color: var(--ink); transform: translateX(6px); }
.job-page { padding: 56px 0 120px; }
.job-page .wrap { max-width: 1020px; }
.job-page .back-link { display: inline-block; margin-bottom: 44px; color: var(--muted); text-decoration: none; }
.job-page .back-link:hover { color: var(--accent); }
.skills-pill { margin: 0 0 52px; padding: 14px 18px; border: 1.5px solid var(--line-soft); border-radius: 28px; background: var(--surface); }
.job-page .skills-pill ul { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; padding: 0; list-style: none; }
.job-page .skills-pill li { margin: 0; padding: 5px 9px; border: 1px solid var(--line); border-radius: 999px; color: var(--prose); font-size: 13px; line-height: 1.2; }
.job-callout { display: flex; flex-direction: column; gap: 8px; margin: 0 0 28px; padding: 20px 22px; border-left: 3px solid var(--accent); background: var(--surface); color: var(--prose); }
.job-callout > span { font-size: 24px; line-height: 1; }
.job-callout p { margin: 0; }
.job-page .prose ol { margin: 0 0 28px; padding-left: 28px; color: var(--prose); font-size: 18px; line-height: 1.75; }
.job-page .prose li { padding-left: 8px; margin-bottom: 8px; }

/* Sticky side nav on About / posts */
.toc { position: sticky; top: 110px; align-self: start; display: flex; flex-direction: column; gap: 12px; }
.toc a { text-decoration: none; font-size: 15px; color: var(--muted); padding-left: 14px; border-left: 2px solid var(--line-soft); transition: color .25s ease, border-color .25s ease; }
.toc a:hover { color: var(--ink); border-color: var(--accent); }

/* Little label pills */
.tag {
    display: inline-flex; align-items: center; padding: 3px 10px; border-radius: 999px;
    border: 1.5px solid var(--line); font-size: 11.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--accent);
}
.chips { display: flex; flex-wrap: wrap; gap: 10px; }
.chip {
    min-height: 40px; padding: 0 16px; border-radius: 999px; border: 1.5px solid var(--line-soft);
    background: transparent; color: var(--ink); font: inherit; font-size: 14px; cursor: pointer;
    transition: background .25s ease, color .25s ease, border-color .25s ease, transform .25s ease;
}
.chip:hover { border-color: var(--accent); transform: translateY(-2px); }
.chip[aria-pressed="true"] { background: var(--accent); color: var(--bg); border-color: var(--accent); }

/* Post rows with a category tag */
.post .meta { display: flex; flex-direction: column; gap: 8px; }
.post[hidden] { display: none; }

/* Three-up project cards */
.cards.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cards.three .card { min-height: 300px; }

/* Platform buttons in the hero card */
.plat { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 24px; padding-top: 20px; border-top: 1px dashed var(--line); }
.plat a {
    display: flex; align-items: center; justify-content: space-between; min-height: 52px; padding: 0 16px;
    border: 1.5px solid var(--line-soft); border-radius: 14px; text-decoration: none; font-size: 15px; font-weight: 600;
    transition: background .25s ease, color .25s ease, transform .25s ease, border-color .25s ease;
}
.plat a:hover { background: var(--accent); color: var(--bg); border-color: var(--accent); transform: translateY(-3px); }

/* Forms */
.form { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.form > .hidden { display: none; }
.form .full { grid-column: 1 / -1; }
.form label { display: block; margin-bottom: 8px; font-size: 13px; color: var(--muted); }
.form .field { width: 100%; }
.form select.field { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--accent) 50%), linear-gradient(135deg, var(--accent) 50%, transparent 50%); background-position: calc(100% - 26px) 50%, calc(100% - 20px) 50%; background-size: 6px 6px; background-repeat: no-repeat; }
.form textarea.field { border-radius: 20px; padding: 16px 20px; min-height: 160px; resize: vertical; }

/* Contact methods */
.method {
    display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 20px 22px;
    border: 1.5px solid var(--line-soft); border-radius: 16px; background: var(--surface); text-decoration: none;
    transition: transform .3s ease, border-color .3s ease;
}
.method:hover { transform: translateX(8px); border-color: var(--accent); }
.method small { display: block; font-size: 12px; letter-spacing: .12em; color: var(--muted); text-transform: uppercase; margin-bottom: 4px; }

/* Facts strip on About */
.facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.fact { padding: 22px; border: 1.5px solid var(--line-soft); border-radius: 18px; background: var(--surface); }
.fact small { display: block; font-size: 12px; letter-spacing: .12em; color: var(--muted); text-transform: uppercase; margin-bottom: 10px; }
.fact span { font-size: 20px; font-weight: 600; letter-spacing: -.01em; }

@media (max-width: 980px) {
    .menu { display: block; }
    .hello-btn { display: none !important; }
    .cards.three { grid-template-columns: minmax(0, 1fr); }
    .facts { grid-template-columns: minmax(0, 1fr); }
    .toc { position: static; flex-direction: row; flex-wrap: wrap; gap: 10px; }
    .toc a { border: 1.5px solid var(--line-soft); border-radius: 999px; padding: 8px 14px; }
}
@media (max-width: 600px) {
    .phead { padding: 56px 0 48px; }
    .form { grid-template-columns: minmax(0, 1fr); }
    .plat { grid-template-columns: minmax(0, 1fr); }
    .prose p { font-size: 17px; }
}


/* ---------------------------------------------------------------------
   19. POST LAYOUT (centered column + outline in the left margin)
   --------------------------------------------------------------------- */
.posthead .inner { align-items: center; text-align: center; gap: 20px; }
.posthead h1 { max-width: 20ch; font-size: clamp(38px, 5.6vw, 68px); }
.posthead .lede { max-width: 620px; }
.posthead .crumbs { justify-content: center; }
.byline { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: center; font-size: 14px; color: var(--soft); }
.byline .sep { color: var(--line); }

.postgrid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 700px) minmax(0, 1fr); gap: 48px; }
.postgrid .prose { grid-column: 2; max-width: none; }
.toc-side { grid-column: 1; grid-row: 1; justify-self: end; width: 100%; max-width: 230px; }
.toc-side a.on { color: var(--ink); border-color: var(--accent); }
.toc-top { display: none; }

@media (max-width: 1180px) {
    .postgrid { grid-template-columns: minmax(0, 1fr); max-width: 700px; }
    .postgrid .prose { grid-column: 1; }
    .toc-side { display: none; }
    .toc-top { display: block; margin-bottom: 36px; border: 1.5px solid var(--line-soft); border-radius: 16px; background: var(--surface); }
    .toc-top summary { cursor: pointer; padding: 14px 18px; font-size: 14px; letter-spacing: .08em; list-style: none; }
    .toc-top summary::-webkit-details-marker { display: none; }
    .toc-top div { display: flex; flex-direction: column; padding: 0 18px 14px; gap: 10px; }
    .toc-top a { text-decoration: none; font-size: 15px; color: var(--soft); }
}

/* overflow-x: hidden on .bg-root turns it into a scroll container, which
   silently breaks every position: sticky inside it (nav, outlines).
   `clip` hides the marquee overflow without doing that. */
.bg-root { overflow-x: clip; }


/* ---------------------------------------------------------------------
   20. THEME TOGGLE (dark / light, same body.light-mode switch as today)
   --------------------------------------------------------------------- */
.theme-btn {
    width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center;
    border-radius: 50%; border: 1.5px solid var(--line); background: transparent; color: var(--ink);
    cursor: pointer; transition: transform .25s ease, border-color .25s ease, background .25s ease;
}
.theme-btn:hover { border-color: var(--accent); transform: rotate(18deg); }
.theme-btn .i-moon { display: none; }
body.light-mode .theme-btn .i-sun { display: none; }
body.light-mode .theme-btn .i-moon { display: inline; }
body, .bg-root { transition: background-color .3s ease, color .3s ease; }


/* ---------------------------------------------------------------------
   21. ANNOUNCEMENT BAR (above the nav; scrolls away, nav stays sticky)
   --------------------------------------------------------------------- */
.announce {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    min-height: 38px; padding: 6px 16px; text-align: center;
    background: var(--accent); color: var(--bg);
    font-size: 14px; font-weight: 600; letter-spacing: .01em;
}

a.announce { text-decoration: none; transition: background .25s ease; }
a.announce:hover { background: var(--ink); color: var(--bg); }
.announce-link { text-decoration: underline; text-underline-offset: 3px; margin-left: 4px; }
.announce .arr { display: inline-block; transition: transform .25s ease; }
a.announce:hover .arr { transform: translateX(4px); }
@media (max-width: 600px) {
    .announce { font-size: 13px; gap: 6px; white-space: nowrap; padding: 6px 10px; }
    .announce-link .arr { display: none; }
}


/* Discord callout (homepage) */
.discord-card {
    display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap;
    padding: 32px 40px; border-radius: 24px; border: 1.5px solid var(--line-soft); background: var(--surface);
}
.discord-ico {
    width: 60px; height: 60px; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
    color: var(--ink);
}
.newsletter-disabled { opacity: .42; pointer-events: none; user-select: none; }
.coming-soon { border: 1px solid var(--line); border-radius: 999px; color: var(--muted); font-size: 11px; letter-spacing: .1em; padding: 4px 8px; }
.cv-download svg { height: 24px; width: 24px; }
.cv-download { transition: transform .25s ease, background .25s ease, color .25s ease; }
.cv-download:hover { color: var(--ink); transform: translateY(-3px); }
@media (max-width: 600px) { .discord-card { padding: 24px; } }

/* Eleventy detail pages use the same visual language as the site6 shell. */
.article-section { padding: 64px 0 120px; }
.postgrid { display: grid; grid-template-columns: minmax(0, 700px) minmax(0, 230px); gap: 56px; max-width: 1020px; }
.postgrid .prose { grid-column: 1; min-width: 0; }
.toc-side { grid-column: 2; grid-row: 1; position: sticky; top: 110px; align-self: start; display: flex; flex-direction: column; gap: 14px; }
.toc-label, .overview-label { color: var(--muted); font-size: 12px; letter-spacing: .14em; }
.toc-side nav { display: flex; flex-direction: column; gap: 10px; }
.toc-side nav a { color: var(--muted); border-left: 2px solid var(--line-soft); font-size: 14px; line-height: 1.45; padding-left: 12px; text-decoration: none; transition: color .2s ease, border-color .2s ease; }
.toc-side nav a:hover, .toc-side nav a.blog-spy-link-active { color: var(--ink); border-color: var(--accent); }
.share-btn { align-items: center; background: transparent; border: 1.5px dashed var(--line); color: var(--muted); cursor: pointer; display: flex; font: inherit; font-size: 13px; justify-content: space-between; padding: 10px 12px; text-align: left; }
.share-btn:hover { border-color: var(--accent); color: var(--ink); }
.article-stats { border-top: 1px dashed var(--line); color: var(--muted); display: flex; font-size: 12px; justify-content: space-between; padding-top: 12px; }
.article-stats strong { color: var(--ink); font-weight: 500; }
.back-link { color: var(--muted); font-size: 13px; text-decoration: none; }
.back-link:hover { color: var(--ink); }
.prose { color: var(--prose); max-width: 720px; }
.prose h1, .prose h2, .prose h3 { color: var(--ink); }
.prose h2 { margin: 56px 0 16px; font-size: clamp(28px, 3.4vw, 40px); line-height: 1.1; letter-spacing: -.03em; font-weight: 700; scroll-margin-top: 110px; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { margin: 36px 0 12px; font-size: 24px; }
.prose p, .prose li { color: var(--prose); font-size: 18px; line-height: 1.75; }
.prose p { margin: 0 0 20px; }
.prose ul, .prose ol { margin: 0 0 24px; padding-left: 24px; }
.prose li { margin: 6px 0; }
.prose blockquote { border-left: 3px solid var(--accent); color: var(--accent); font-size: clamp(22px, 3vw, 32px); font-weight: 700; letter-spacing: -.03em; line-height: 1.25; margin: 32px 0; padding-left: 22px; }
.prose pre { background: var(--surface); border: 1.5px solid var(--line-soft); color: var(--prose); overflow-x: auto; padding: 20px; }
.prose code { color: var(--accent); }
.prose .btn_reverse { align-items: center; background: var(--accent); border: 1px solid var(--accent); color: var(--bg); display: inline-flex; font: inherit; gap: 8px; padding: 10px 16px; text-decoration: none; }
.prose .btn_reverse:hover { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.prose a.btn-solid { color: var(--bg); }
.prose a.btn-solid:hover { color: var(--bg); }
.prose img { border: 1.5px solid var(--line-soft); height: auto; max-width: 100%; }
.prose .content-copy a { color: var(--accent); text-underline-offset: 4px; }
.research-overview { background: var(--surface); border: 1.5px solid var(--line-soft); border-radius: 18px; display: flex; flex-direction: column; gap: 18px; margin-bottom: 42px; padding: 24px; }
.research-overview div { border-top: 1px solid var(--line-soft); padding-top: 14px; }
.research-overview strong { color: var(--ink); display: block; font-size: 14px; margin-bottom: 4px; }
.research-overview p { color: var(--soft); font-size: 15px; line-height: 1.5; margin: 0; }
.downloads { border-top: 1px dashed var(--line); display: flex; flex-direction: column; gap: 16px; margin-top: 48px; padding-top: 24px; }
.downloads > div { display: flex; flex-wrap: wrap; gap: 12px; }
.research-grid .prose > .grid { display: grid; gap: 24px; grid-template-columns: repeat(2, minmax(0, 1fr)); margin: 24px 0; }
.research-grid .prose > .grid > div, .research-grid .prose > .my-6 > div { border: 1px dashed var(--line-soft); border-radius: 14px; padding: 18px; }
.research-grid .prose > .grid > div p, .research-grid .prose > .my-6 > div p { color: var(--muted); font-size: 13px; margin-bottom: 10px; }
.research-grid .prose iframe { border: 0; width: 100%; }
.sidebar-item { border-bottom: 1px solid var(--line-soft); padding: 18px 0; }
.sidebar-item > input { position: absolute; opacity: 0; pointer-events: none; }
.sidebar-item label { align-items: center; color: var(--ink); cursor: pointer; display: flex; font-weight: 600; gap: 10px; }
.sidebar-item label:hover { color: var(--accent); }
.sidebar-item .month-posts { color: var(--soft); display: none; padding: 18px 0 4px 28px; }
.sidebar-item .month-toggle:checked ~ .month-posts { display: block; }
.sidebar-item .chevron { transition: transform .2s ease; }
.sidebar-item .month-toggle:checked ~ ul .chevron { transform: rotate(180deg); }
.sidebar-item .month-posts h3 { color: var(--ink); font-size: 20px; margin: 22px 0 8px; }
.sidebar-item .month-posts p, .sidebar-item .month-posts li { color: var(--soft); font-size: 16px; line-height: 1.65; }
.sidebar-item .month-posts ul { margin: 0 0 20px; padding-left: 20px; }
.sidebar-item .month-posts a { color: var(--accent); }
.sidebar-item .month-posts .px-2 { border: 1px solid var(--line); border-radius: 999px; color: var(--muted); display: inline-block; font-size: 12px; padding: 3px 8px; }
.toc-top { display: none; margin-top: 36px; width: 100%; }
@media (max-width: 900px) {
    .postgrid { grid-template-columns: minmax(0, 1fr); max-width: 700px; }
    .toc-side { display: none; }
    .toc-top { display: flex; }
}
@media (max-width: 600px) {
    .article-section { padding: 44px 0 80px; }
    .prose p, .prose li { font-size: 17px; }
    .prose blockquote { font-size: 24px; }
}
@media (max-width: 700px) { .research-grid .prose > .grid { grid-template-columns: 1fr; } }
@media (max-width: 980px) {
    #blog > .wrap > .reveal-x { position: static !important; }
}

.menu { display: none; }
.site6-footer { overflow: hidden; padding: 100px 0 40px; }
.site6-footer .giant { margin-bottom: 72px; }
.footer-grid { display: grid; gap: 48px; grid-template-columns: 1.4fr 1fr 1fr; }
.footer-grid > div, .footer-grid nav { display: flex; flex-direction: column; gap: 14px; }
.footer-grid a { align-self: flex-start; text-decoration: none; }
.footer-label { color: var(--muted); font-size: 13px; letter-spacing: .14em; }
.footer-email { font-size: 24px; font-weight: 600; }
.socials { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; }
.socials a, .footer-grid nav a { font-size: 18px; }
.socials a { font-size: 14px; }
.footer-status { align-items: center; display: flex; font-size: 18px; gap: 10px; }
.footer-note { color: var(--soft); font-size: 14px; }
.footer-bottom { border-top: 1px solid var(--grid); color: var(--muted); display: flex; font-size: 13px; justify-content: space-between; margin-top: 72px; padding-top: 24px; }
.connect-grid { display: grid; gap: 64px; grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); }
.connect-links { display: flex; flex-direction: column; gap: 12px; }
.connect-links a { align-items: center; border-bottom: 1px solid var(--line-soft); color: var(--ink); display: grid; font-size: 17px; gap: 8px; grid-template-columns: 90px 1fr auto; padding: 14px 0; text-decoration: none; }
.connect-links a span { color: var(--muted); font-size: 12px; }
.connect-links a b { color: var(--accent); font-weight: 400; }
.connect-card { background: var(--surface); border: 1.5px solid var(--line-soft); border-radius: 20px; padding: 32px; }
.connect-card h2 { font-size: 30px; margin: 0 0 8px; }
.connect-card > p { color: var(--soft); line-height: 1.6; margin: 0 0 24px; }
.connect-card form { display: flex; flex-direction: column; gap: 16px; }
.connect-card form > div { display: flex; flex-direction: column; gap: 6px; }
.connect-card label { color: var(--muted); font-size: 13px; }
.connect-card input, .connect-card select, .connect-card textarea { background: var(--bg); border: 1px solid var(--line); color: var(--ink); font: inherit; padding: 10px 12px; width: 100%; }
.connect-card textarea { min-height: 130px; resize: vertical; }
.connect-card input:focus, .connect-card select:focus, .connect-card textarea:focus { border-color: var(--accent); outline: none; }
.success-card { align-items: center; display: flex; flex-direction: column; gap: 14px; padding-bottom: 120px; padding-top: 72px; text-align: center; }
.success-card h2 { font-size: 32px; margin: 0; }
.success-card p { color: var(--soft); font-size: 17px; }
.success-icon { align-items: center; background: var(--accent); border-radius: 50%; color: var(--bg); display: flex; font-size: 24px; height: 52px; justify-content: center; width: 52px; }
@media (max-width: 700px) { .connect-grid { grid-template-columns: 1fr; gap: 36px; } .connect-card { padding: 24px; } }
@media (max-width: 700px) {
    .menu { display: block; position: relative; }
    .menu summary { color: var(--ink); cursor: pointer; font-size: 14px; list-style: none; }
    .menu summary::-webkit-details-marker { display: none; }
    .menu-panel { background: var(--surface); border: 1px solid var(--line-soft); display: flex; flex-direction: column; gap: 14px; padding: 18px; position: absolute; right: 0; top: 28px; width: 170px; }
    .footer-grid { grid-template-columns: 1fr; }
    .footer-bottom { flex-direction: column; gap: 12px; }
}

/* Shared consent banner. These pages no longer depend on Tailwind utilities. */
#cookieBanner { background: var(--bg); border-top: 1px dashed var(--line); bottom: 0; color: var(--ink); display: flex; left: 0; padding: 14px 32px; position: fixed; right: 0; z-index: 50; }
#cookieBanner.hidden { display: none; }
#cookieBanner > div { align-items: center; display: flex; gap: 20px; justify-content: space-between; margin: 0 auto; max-width: 1240px; width: 100%; }
#cookieBanner p { color: var(--soft); font-size: 13px; margin: 0; }
#cookieBanner button { cursor: pointer; font: inherit; }
#cookieBanner #declineCookies { background: transparent; border: 0; color: var(--muted); padding: 8px 12px; }
#cookieBanner #acceptCookies { background: var(--accent); border: 1px solid var(--accent); color: var(--bg); padding: 8px 16px; }
#cookieBanner #declineCookies:hover { color: var(--ink); }
@media (max-width: 600px) { #cookieBanner { padding: 14px 18px; } #cookieBanner > div { align-items: flex-start; flex-direction: column; gap: 10px; } #cookieBanner > div > div { align-self: flex-end; } }
