/* styles.css — the entire look of pulsipher.dev in one file.

   HOW TO FIND THINGS: rules are ordered the way the page reads top-to-bottom —
   design tokens (colours & fonts), global base elements, the red header bar,
   the home page (hero + section list), the project subpages (Novels, Game Dev,
   Data Science Tools), then the footer. Nearly every colour is defined once as
   a token below and reused via var(--name), so to recolour the whole site you
   usually only edit the tokens. Colours respond to the system light/dark mode,
   with a manual override via the header toggle (see the data-theme blocks). */

/* ------------------------------------------------------- design tokens */
/* These are the LIGHT-MODE values. The dark-mode values are in the two blocks
   right below. Change a value here and it updates everywhere it's used. */
:root {
    --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif; /* headings: your name, page titles, section names, logo */
    --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; /* everything else (body text, nav, buttons) */

    --bg: #ffffff;              /* page background */
    --text: #212227;            /* main body text (blurbs, intros) */
    --muted: #6b6c72;           /* dimmed text — currently just the footer copyright line */
    --line: #e7e5e2;            /* faint divider colour — NOT currently used (dividers use --accent); kept as a spare */
    --accent: #ad2c34;          /* Positive Red — links, all divider lines, arrows, the lattice, focus rings */
    --accent-strong: #8f2129;   /* darker red for link hover */
    --accent-soft: rgba(173, 44, 52, 0.08); /* faint red tint — NOT currently used; kept as a spare */
    --brand: #ad2c34;           /* the header bar and the tag pills — stays this deep red in BOTH light and dark */
    --subtext: #212227;         /* hero tagline ("Software Engineer by day…") + home section descriptors; = body text in light mode */
    --portrait-ring: #ad2c34;   /* ring around the headshot — red in light mode (a white ring would vanish on the white page) */

    /* Opacity of the panel behind the hero / subpage text (over the lattice).
       100% = fully opaque (lattice fully hidden behind the text); lower lets
       more of the lattice show through, e.g. 42% for the see-through look. */
    --panel-opacity: 75%;
}

/* DARK-MODE colours. Applied when the visitor's system prefers dark (unless
   they've forced light via the header toggle). Only the values that differ from
   light are worth noting; the rest mirror the light tokens. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --bg: #16171b;          /* page background (near-black) */
        --text: #e8e6e2;        /* main body text (off-white) */
        --muted: #97969c;       /* footer copyright */
        --line: #2b2c31;        /* spare divider colour (unused) */
        --accent: #e34b52;      /* brighter red so it stays vivid (not pink) on the dark background */
        --accent-strong: #ec6b6f; /* link hover */
        --accent-soft: rgba(227, 75, 82, 0.12); /* spare tint (unused) */
        --subtext: #c3c2c6;     /* hero tagline + home descriptors — a light grey, one notch below pure white */
        --portrait-ring: #ffffff; /* white headshot ring on the dark page */
    }
}

/* Same dark values again, applied when the visitor FORCES dark with the toggle
   (regardless of their system setting). Keep this in sync with the block above. */
:root[data-theme="dark"] {
    --bg: #16171b;
    --text: #e8e6e2;
    --muted: #97969c;
    --line: #2b2c31;
    --accent: #e34b52;
    --accent-strong: #ec6b6f;
    --accent-soft: rgba(227, 75, 82, 0.12);
    --subtext: #c3c2c6;
    --portrait-ring: #ffffff;
}

/* -------------------------------------------------------- base elements */
/* Reset every element's margin/padding and use border-box sizing everywhere. */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/* Tells the browser both themes exist (styles native form controls, scrollbars). */
html {
    color-scheme: light dark;
}

/* Page defaults: body font, text colour, and the column layout that keeps the
   footer pinned to the bottom on short pages. */
body {
    font-family: var(--sans);
    font-size: 1rem;
    line-height: 1.7;            /* line spacing for all body text */
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    min-height: 100vh;           /* fill the screen so the footer sits at the bottom */
    display: flex;
    flex-direction: column;
    overflow-x: hidden;          /* hides the sideways overflow from the full-bleed hero lattice */
}

/* Highlight colour when you drag-select text. */
::selection {
    background: var(--accent);
    color: #ffffff;
}

/* Default link style (body/blurb links). Header, hero, and footer links are
   restyled in their own sections below. */
a {
    color: var(--accent);
    text-decoration: none;
    transition: color 120ms ease; /* fade on hover */
}

a:hover {
    color: var(--accent-strong);
    text-decoration: underline;
    text-underline-offset: 0.2em; /* gap between text and underline */
}

/* Red outline shown around whatever has keyboard focus (accessibility). */
:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* Shared look for all headings (name, page titles, section names, item titles). */
h1, h2, h3 {
    font-family: var(--serif);
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.01em;     /* slight tightening for the serif headings */
}

/* The centered content column. max-width sets how wide the readable area is;
   padding is the left/right gutter (also how far the text sits from the edges). */
.wrap {
    max-width: 42rem;            /* content column width */
    width: 100%;
    flex: 1;
    margin: 0 auto;              /* center it */
    padding: 0 2.25rem;          /* side gutters */
    display: flex;
    flex-direction: column;
}

/* Pushes the footer down so it stays at the bottom of short pages. */
main {
    flex: 1;
}

/* ------------------------------------------- site header (red brand bar) */
/* The full-width red bar across the top of every page. */
.site-header {
    position: relative;
    z-index: 5;                  /* keeps the bar painting ABOVE the hero lattice (so the lattice never shows over the nav) */
    background: var(--brand);    /* the red bar colour */
}

/* Inner row of the header — aligns the logo (left) and nav+toggle (right) to the
   same width and gutters as the page content. */
.header-inner {
    max-width: 42rem;            /* match .wrap so logo/nav line up with the content */
    margin: 0 auto;
    padding: 1.1rem 2.25rem;     /* header height (top/bottom) and side gutters */
    display: flex;
    justify-content: space-between; /* logo left, nav right */
    align-items: baseline;
    gap: 1rem;
    flex-wrap: wrap;
}

/* White focus ring inside the red bar (the red one wouldn't show on red). */
.site-header :focus-visible {
    outline-color: #ffffff;
}

/* "Andrew Pulsipher" logo text at top-left of the bar. */
.site-mark {
    font-family: var(--serif);
    font-size: 1.1rem;
    font-weight: 600;
    color: #ffffff;
}

.site-mark:hover {
    color: #ffffff;              /* no colour change on hover (stays white) */
}

/* Wrapper around the nav links + theme toggle, keeping them together on the right. */
.header-right {
    display: flex;
    align-items: center;
    gap: 1.4rem;                 /* space between the nav group and the toggle */
    flex-wrap: wrap;
}

/* The nav links row (Novels / Game Dev / Data Science Tools). */
.site-nav {
    display: flex;
    gap: 1.4rem;                 /* space between nav links */
    flex-wrap: wrap;
}

/* The light/dark toggle button (sun/moon icon) in the header. */
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.15rem;
    background: none;
    border: 0;
    color: rgba(255, 255, 255, 0.85); /* icon colour (semi-white) */
    cursor: pointer;
    transition: color 120ms ease;
}

.theme-toggle:hover {
    color: #ffffff;              /* icon brightens on hover */
}

.theme-toggle svg {
    width: 1.2rem;               /* toggle icon size */
    height: 1.2rem;
}

/* Nav link text colour (slightly dimmed white on the red bar). */
.site-nav a {
    font-size: 0.9rem;
    color: rgba(255, 255, 255, 0.78);
}

.site-nav a:hover {
    color: #ffffff;              /* brightens on hover */
    text-decoration: none;
}

/* The nav link for the page you're currently on — full white + underline. */
.site-nav a[aria-current="page"] {
    color: #ffffff;
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 0.4em;
}

/* ------------------------------------------------------------ home page */
/* The top hero block: headshot on the left, name/tagline/links on the right,
   with the lattice band behind. grid-template-columns sets that two-column
   layout; column-gap is the space between photo and text. */
.hero {
    position: relative;          /* anchor for the absolutely-positioned lattice */
    display: grid;
    grid-template-columns: auto 1fr; /* photo (its own size) | text (fills rest) */
    align-items: center;
    column-gap: 2.5rem;          /* gap between headshot and text */
    padding: 4.5rem 0 3rem;      /* vertical space above/below the hero */
}

/* The name/tagline/links column. z-index keeps it above the lattice. */
.hero-text {
    position: relative;
    z-index: 1;
}

/* The circular headshot. width/height set its size; the outline is the coloured
   ring and outline-offset is the gap between the photo and that ring. */
.hero-portrait {
    position: relative;
    z-index: 1;                  /* above the lattice */
    width: 9.5rem;               /* headshot size */
    height: 9.5rem;
    border-radius: 50%;          /* circle */
    object-fit: cover;           /* crop the photo to fill the circle */
    /* Ring separated from the photo by a small gap: white in dark mode, red in
       light mode (where white would vanish against the page). */
    outline: 3.75px solid var(--portrait-ring); /* ring thickness + colour */
    outline-offset: 3px;         /* size of the gap between photo and ring */
}

/* Phone layout: stack the headshot above the text and shrink it a little. */
@media (max-width: 40rem) {
    .hero {
        grid-template-columns: 1fr; /* single column (stacked) */
        row-gap: 2.5rem;
    }

    .hero-portrait {
        width: 7.5rem;           /* smaller headshot on phones */
        height: 7.5rem;
    }
}

/* Hero background: the diagonal lattice of swords, spears & spaceships, drawn
   once at build time by build.js (buildHeroPattern). Purely decorative.
   Full-bleed: this band spans the whole viewport width (like the nav bar) via
   the left:50% / width:100vw / -50vw trick, while the hero content stays in the
   centered column above it. */
.hero-bg {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    width: 100vw;                /* full viewport width */
    margin-left: -50vw;          /* re-center the full-width band */
    overflow: hidden;            /* clip the oversized SVG to the band */
    z-index: 0;                  /* behind the hero text/photo */
    pointer-events: none;        /* never intercepts clicks */
}

/* The lattice SVG is drawn at a fixed pixel size (from its width/height attrs in
   build.js) and only CENTERED here — never stretched — so the glyph density is
   identical at every screen size. stroke sets the lattice colour (the red). */
.hero-bg svg {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%); /* center the fixed-size canvas */
    fill: none;
    stroke: var(--accent);       /* lattice line colour */
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* The three kinds of marks in the lattice. Raise opacity to make it bolder,
   lower it to make it fainter. Tuned to read as strongly as the red dividers. */
.hero-bg .wp { stroke-width: 1.4; opacity: 0.9; }    /* the weapon & spaceship drawings */
.hero-bg .hx { stroke-width: 1.5; opacity: 0.9; }    /* the plain connector lines between them */
.hero-bg .node { stroke-width: 1.3; opacity: 0.72; } /* the small "+" marks at each intersection */

/* LEGIBILITY OVER THE LATTICE. These rules apply to BOTH the home hero and the
   subpage headers, so text stays readable on top of the busy lattice. */

/* isolation lets the frosted panel (below) sit behind the text but above the lattice. */
.hero-text,
.page-header-content {
    isolation: isolate;
}

/* The frosted panel: a rounded rectangle in the page colour behind the text
   block, hiding/softening the lattice there. inset controls how far it extends
   past the text; its see-through-ness is --panel-opacity (in the tokens above).
   Uses ::before on the hero, ::after on subpages (whose ::before is the red bar). */
.hero-text::before,
.page-header-content::after {
    content: "";
    position: absolute;
    inset: -0.9rem -1.3rem;      /* how far the panel extends around the text (top/bottom, left/right) */
    z-index: -1;                 /* behind the text, above the lattice */
    border-radius: 16px;         /* rounded corners of the panel */
    background: color-mix(in srgb, var(--bg) var(--panel-opacity), transparent);
}

/* Links inside the hero and subpage headers: light text with a red underline,
   so they don't disappear into the red lattice (unlike normal red body links). */
.hero-text a,
.page-header-content a {
    color: var(--text);
    text-decoration: underline;
    text-decoration-color: var(--accent); /* the underline is red */
    text-decoration-thickness: 2px;
    text-underline-offset: 3px;
}

.hero-text a:hover,
.page-header-content a:hover {
    color: var(--accent-strong); /* turns red on hover */
}

/* Keep the LinkedIn/GitHub logos red even though their link text is light. */
.hero-text .social-icon,
.page-header-content .social-icon {
    color: var(--accent);
}

/* "Andrew Pulsipher" — the big name in the hero. clamp = min, preferred, max
   size, so it scales with the window between 2rem and 2.6rem. */
.hero-name {
    font-size: clamp(2rem, 5.5vw, 2.6rem);
}

/* LEGACY: styled the old job-title line under the name, which has been removed.
   Currently unused — safe to delete, or reuse if you add a line back. */
.hero-role {
    margin-top: 0.75rem;
    font-size: 1.05rem;
}

/* The tagline under the name ("Software Engineer by day. / Novelist and game
   maker by night."). Colour comes from --subtext. */
.hero-tagline {
    margin-top: 0.35rem;         /* space below the name */
    color: var(--subtext);
}

/* Extra space above the LinkedIn/GitHub row in the hero specifically. */
.hero .social-links {
    margin-top: 1.75rem;
}

/* The LinkedIn/GitHub row (used in both the hero and the footer). */
.social-links {
    display: flex;
    gap: 1.4rem;                 /* space between the two links */
}

/* Each social link: icon + label sitting side by side. */
.social-links a {
    font-size: 0.9rem;
    display: inline-flex;
    align-items: center;
    gap: 0.42rem;                /* space between the logo and its label */
}

/* The LinkedIn/GitHub logo size. */
.social-icon {
    width: 1.05em;               /* scales with the link text size */
    height: 1.05em;
    flex: none;
}

/* The list of sections on the home page (Novels / Game Dev / Data Science Tools),
   below the hero. */
.page-list {
    margin: 1.5rem 0 4rem;       /* space above the list and below it */
}

/* One row in that list: title + descriptor on the left, arrow on the right,
   with a red divider line on top. */
.page-list-item {
    display: grid;
    grid-template-columns: 1fr auto; /* text | arrow */
    align-items: center;
    column-gap: 1rem;
    padding: 1.4rem 0;           /* row height */
    border-top: 1px solid var(--accent); /* the red divider above each row */
    color: var(--text);
}

.page-list-item:hover {
    text-decoration: none;
}

/* The section name in each row (e.g. "Novels"). */
.page-list-title {
    grid-column: 1;
    font-family: var(--serif);
    font-size: 1.35rem;
    font-weight: 600;
    transition: color 120ms ease; /* fades to red on hover (see hover rule below) */
}

/* The one-line descriptor under each section name (e.g. "Dipping my toes…").
   Colour matches the hero tagline via --subtext. */
.page-list-tagline {
    grid-column: 1;
    font-size: 0.95rem;
    color: var(--subtext);
}

/* The red "→" arrow at the right of each row. */
.page-list-arrow {
    grid-column: 2;
    grid-row: 1 / span 2;        /* span both the title and descriptor rows */
    font-size: 1.2rem;
    color: var(--accent);
    transition: color 120ms ease, transform 120ms ease;
}

/* On hover: the section name turns red and the arrow turns red + slides right. */
.page-list-item:hover .page-list-title,
.page-list-item:hover .page-list-arrow {
    color: var(--accent);
}

.page-list-item:hover .page-list-arrow {
    transform: translateX(0.25rem); /* how far the arrow slides on hover */
}

/* -------------------------------------------------------- project pages */
/* The header block at the top of each subpage (title + intro), with the lattice
   behind it (same full-bleed .hero-bg as the home hero). */
.page-header {
    position: relative;          /* anchor for the lattice band */
    padding: 3.5rem 0 2rem;      /* space above/below the header */
}

/* The title + intro, kept above the lattice. */
.page-header-content {
    position: relative;
    z-index: 1;
}

/* The short red bar above each subpage title. */
.page-header-content::before {
    content: "";
    display: block;
    width: 2.5rem;               /* bar length */
    height: 3px;                 /* bar thickness */
    margin-bottom: 1.75rem;      /* gap between the bar and the title */
    background: var(--accent);
}

/* The subpage title (e.g. "Novels", "Game Dev"). Scales with the window. */
.page-title {
    font-size: clamp(2rem, 6vw, 2.6rem);
}

/* The intro paragraph under a subpage title. Colour matches the item blurbs (--text). */
.page-intro {
    margin-top: 1rem;
    color: var(--text);
}

/* Spacing between multiple intro paragraphs (if an intro has more than one). */
.page-intro p + p {
    margin-top: 0.75rem;
}

/* The list of items on a subpage (novels, games, tools). */
.item-list {
    margin: 2.5rem 0 4rem;       /* space above the first item and below the last */
}

/* One item (a single novel / game / tool). */
.item {
    padding: 2rem 0;             /* vertical space inside each item */
}

/* Red divider line between items (not above the first one). */
.item + .item {
    border-top: 1px solid var(--accent);
}

/* The item's title with its tag/status pills on the line below. */
.item-head {
    display: flex;
    align-items: center;         /* pills on the chip row line up with each other */
    gap: 0.45rem 0.6rem;         /* row gap between title and chips; column gap between chips */
    flex-wrap: wrap;
}

/* The item title (e.g. "Stonesoul", "epitraxr"). Full width, so the
   chips always wrap onto their own row beneath it. */
.item-title {
    font-size: 1.4rem;
    flex-basis: 100%;
}

/* The little red pill tag next to an item title (e.g. "FANTASY", "CRAN"). */
.item-tag {
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #ffffff;              /* white text… */
    background: var(--brand);    /* …on the deep red pill */
    padding: 0.2rem 0.6rem;      /* pill size */
    border-radius: 999px;        /* fully rounded ends */
    white-space: nowrap;
}

/* Status pill variant (e.g. "WORK IN PROGRESS", "QUERYING") — outlined in
   the accent red rather than filled, so it reads apart from the genre tag. */
.item-status {
    color: var(--accent);
    background: transparent;
    border: 1px solid var(--accent);
    padding: calc(0.2rem - 1px) calc(0.6rem - 1px); /* same pill height as .item-tag despite the border */
}

/* The item's description paragraph(s). Inherits the body --text colour. */
.item-blurb {
    margin-top: 0.75rem;         /* space below the title row */
}

.item-blurb p + p {
    margin-top: 0.75rem;         /* space between multiple blurb paragraphs */
}

/* The row of external links under an item (CRAN, GitHub, itch.io, …). */
.item-links {
    display: flex;
    gap: 1.25rem;                /* space between links */
    flex-wrap: wrap;
    margin-top: 1rem;            /* space above the links */
}

/* These links keep the normal red body-link style (they're not over the lattice). */
.item-links a {
    font-size: 0.9rem;
}

/* ---------------------------------------------------------- site footer */
/* The footer at the bottom of every page: social links left, copyright right,
   with a red divider on top. */
.site-footer {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 1.75rem 0 2.5rem;   /* space above and below the footer content */
    border-top: 1px solid var(--accent); /* red divider above the footer */
}

/* Footer LinkedIn/GitHub links — plain red (not the underlined hero style,
   since the footer isn't over the lattice). */
.site-footer .social-links a {
    color: var(--accent);
}

.site-footer .social-links a:hover {
    color: var(--accent);        /* no change on hover */
    text-decoration: none;
}

/* The "© 2026 Andrew Pulsipher" line. */
.copyright {
    font-size: 0.85rem;
    color: var(--muted);         /* the only place --muted is used */
}

/* -------------------------------------------------------- accessibility */
/* If the visitor asks their OS to reduce motion, disable all transitions and
   animations (e.g. the hover fades and arrow slide). The lattice is static
   anyway, so nothing visual is lost. */
@media (prefers-reduced-motion: reduce) {
    * {
        transition: none !important;
        animation: none !important;
    }
}
