@import url('https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,600;1,6..72,400;1,6..72,600&display=swap');

/* ==========================================================================
   Chance Shepherd — portfolio
   Palette and typography after darioamodei.com: warm near-black, ivory text,
   Newsreader serif, one narrow column. Decoration stays quiet; motion is
   restrained and always opt-out via prefers-reduced-motion.
   ========================================================================== */

:root {
    --bg:      #1F1E1D;
    --text:    #F0EEE6;
    --muted:   #9C968A;
    --faint:   #6E6A62;
    --rule:    rgba(240, 238, 230, 0.13);
    --tint:    rgba(240, 238, 230, 0.035);
    --accent:  #CC785C;

    --measure: 620px;
    --gutter:  20px;
    --ease:    cubic-bezier(0.22, 0.61, 0.36, 1);
}

*, *::before, *::after { box-sizing: border-box; }

html {
    scroll-behavior: smooth;
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    font-family: 'Newsreader', 'Times New Roman', Times, serif;
    font-optical-sizing: auto;
    font-size: 20px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

/* --- Skip link -------------------------------------------------------------
   Invisible until focused. First stop for anyone navigating by keyboard.
   -------------------------------------------------------------------------- */

.skip {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 50;
    background: var(--accent);
    color: #1F1E1D;
    padding: 10px 18px;
    border-radius: 0 0 3px 0;
    text-decoration: none;
    font-size: 0.8em;
}

.skip:focus {
    left: 0;
    color: #1F1E1D;
}

/* --- Reading progress -----------------------------------------------------
   A hairline of clay across the top that fills as you read. Fixed, so it never
   becomes an ancestor of page content.
   -------------------------------------------------------------------------- */

#progress {
    position: fixed;
    top: 0;
    left: 0;
    height: 2px;
    width: 0;
    z-index: 20;
    pointer-events: none;
    background: linear-gradient(90deg, rgba(204, 120, 92, 0.15), var(--accent));
}

/* --- Star canvas ---------------------------------------------------------- */

#star-bg {
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
    z-index: 0;
    pointer-events: none;
}

/* --- Layout --------------------------------------------------------------- */

.wrap {
    position: relative;
    z-index: 1;
    max-width: var(--measure);
    margin: 0 auto;
    padding: 0 var(--gutter);
}

.masthead {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 24px;
    padding: 56px 0 44px;
}

.masthead .wordmark {
    font-size: 1.44em;
    font-weight: 600;
    line-height: 1.2;
    margin: 0;
}

.masthead .wordmark a { text-decoration: none; }
.masthead .wordmark a:hover { color: var(--accent); }

.masthead nav {
    display: flex;
    gap: 18px;
    flex-shrink: 0;
}

.masthead nav a {
    font-size: 0.6em;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: none;
    border-bottom: 1px solid var(--text);
    padding-bottom: 1px;
    white-space: nowrap;
    transition: color 0.18s var(--ease), border-color 0.18s var(--ease);
}

.masthead nav a:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

main { padding-bottom: 96px; }

/* --- Text ----------------------------------------------------------------- */

h2 {
    font-size: 1.2em;
    font-weight: 600;
    line-height: 1.2;
    margin: 0 0 0.7em;
}

h3 {
    font-size: 1em;
    font-weight: 600;
    line-height: 1.4;
    margin: 0 0 0.4em;
}

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

a {
    color: inherit;
    text-decoration: underline;
    text-decoration-thickness: 1.6px;
    text-underline-offset: 2px;
    transition: color 0.18s var(--ease);
}

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

.lede { margin-bottom: 1em; }

.muted {
    color: var(--muted);
    font-size: 0.8em;
    letter-spacing: 0.02em;
}

em, i { font-style: italic; }

hr { border: 0; border-top: 1px solid var(--rule); margin: 0; }

::selection { background: var(--accent); color: var(--bg); }

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
    border-radius: 2px;
}

/* "More" disclosure on the bio */

.more-toggle {
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    color: inherit;
    font: inherit;
    text-decoration: underline;
    text-decoration-thickness: 1.6px;
    text-underline-offset: 2px;
    cursor: pointer;
}

.more-toggle:hover { color: var(--accent); }
.more[hidden] { display: none; }

/* --- Sections ------------------------------------------------------------- */

/* Each section opens with a full-width hairline and a short clay tick, so the
   page reads as distinct chapters rather than one continuous column. */
.section {
    border-top: 1px solid var(--rule);
    padding-top: 36px;
    margin-top: 64px;
    position: relative;
}

.section::before {
    content: "";
    position: absolute;
    top: -1px;
    left: 0;
    width: 34px;
    height: 2px;
    background: var(--accent);
}

.section > h2 { margin-bottom: 0.85em; }

.list { list-style: none; margin: 0; padding: 0; }

.row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 24px;
    padding: 6px 0;
}

.row-main { min-width: 0; }

.row-org,
.row-note {
    display: block;
    color: var(--muted);
    font-size: 0.8em;
    line-height: 1.5;
}

.row-meta {
    color: var(--muted);
    font-size: 0.8em;
    white-space: nowrap;
    flex-shrink: 0;
}

/* --- Page links -----------------------------------------------------------
   Anything that navigates to another page reads as a full-width target with a
   travelling arrow, so it is obvious at a glance which items open up.
   -------------------------------------------------------------------------- */

.golink {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 20px;
    padding: 13px 14px 13px 16px;
    margin: 0 -14px;
    border-radius: 3px;
    text-decoration: none;
    position: relative;
    transition: background 0.2s var(--ease), color 0.18s var(--ease);
}

.golink::before {
    content: "";
    position: absolute;
    left: 0;
    top: 8px;
    bottom: 8px;
    width: 1px;
    background: var(--accent);
    opacity: 0;
    transition: opacity 0.2s var(--ease);
}

.golink:hover,
.golink:focus-visible {
    background: var(--tint);
    color: var(--text);
}

.golink:hover::before,
.golink:focus-visible::before { opacity: 1; }

.golink-main { min-width: 0; }

.golink-title {
    text-decoration: underline;
    text-decoration-thickness: 1.6px;
    text-underline-offset: 2px;
    transition: color 0.18s var(--ease);
}

.golink:hover .golink-title { color: var(--accent); }

.golink-sub {
    display: block;
    color: var(--muted);
    font-size: 0.8em;
    line-height: 1.5;
    margin-top: 2px;
}

.golink-arrow {
    flex-shrink: 0;
    color: var(--faint);
    font-size: 0.85em;
    transition: transform 0.25s var(--ease), color 0.18s var(--ease);
}

.golink:hover .golink-arrow,
.golink:focus-visible .golink-arrow {
    transform: translateX(5px);
    color: var(--accent);
}

/* --- Expandable detail ----------------------------------------------------- */

.panel {
    border-bottom: 1px solid var(--rule);
}

.panel:first-of-type { border-top: 1px solid var(--rule); }

.panel > summary {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 20px;
    padding: 15px 14px 15px 16px;
    margin: 0 -14px;
    list-style: none;
    cursor: pointer;
    border-radius: 3px;
    transition: background 0.2s var(--ease);
    position: relative;
}

.panel > summary::-webkit-details-marker { display: none; }
.panel > summary:hover { background: var(--tint); }

.panel-title { min-width: 0; }

.panel-org {
    display: block;
    color: var(--muted);
    font-size: 0.8em;
    line-height: 1.5;
    margin-top: 2px;
}

.panel-side {
    display: flex;
    align-items: baseline;
    gap: 12px;
    flex-shrink: 0;
    color: var(--muted);
    font-size: 0.8em;
    white-space: nowrap;
}

/* The +/- reads as an actual button, so it's obvious the row opens. */
.panel-sign {
    position: relative;
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    align-self: center;
    border: 1px solid var(--rule);
    border-radius: 50%;
    transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
}

.panel-sign::before,
.panel-sign::after {
    content: "";
    position: absolute;
    background: var(--muted);
    transition: transform 0.3s var(--ease), background 0.18s var(--ease);
}

.panel-sign::before { left: 6px; right: 6px; top: 11px; height: 1px; }
.panel-sign::after  { top: 6px; bottom: 6px; left: 11px; width: 1px; }

.panel[open] .panel-sign::after { transform: scaleY(0); }

.panel > summary:hover .panel-sign,
.panel > summary:focus-visible .panel-sign {
    border-color: var(--accent);
    background: rgba(204, 120, 92, 0.14);
}

.panel > summary:hover .panel-sign::before,
.panel > summary:hover .panel-sign::after { background: var(--accent); }

/* Title behaves like a link on hover, reinforcing that the row is interactive */
.panel > summary:hover .panel-title {
    text-decoration: underline;
    text-decoration-thickness: 1.6px;
    text-underline-offset: 3px;
    text-decoration-color: var(--faint);
}

/* Open rows get a clay spine so the expanded one is easy to track */
.panel[open] {
    background: linear-gradient(90deg, rgba(204, 120, 92, 0.05), transparent 42%);
}

/* -16 margin + 2 border + 16 padding lands text in the same place as when
   closed (-14 + 16), so opening a row doesn't nudge it sideways. */
.panel[open] > summary { border-left: 2px solid var(--accent); margin-left: -16px; padding-left: 16px; }
.panel[open] .panel-sign { border-color: var(--accent); }
.panel[open] .panel-sign::before { background: var(--accent); }
.panel[open] .panel-body { padding-left: 2px; }

.panel-body {
    padding: 2px 0 22px;
    animation: panel-in 0.32s var(--ease);
}

.panel-body p { margin-bottom: 0.8em; }
.panel-body p:last-child { margin-bottom: 0; }

@keyframes panel-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: none; }
}

/* --- Chips ---------------------------------------------------------------- */

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    margin-top: 14px;
    padding: 0;
    list-style: none;
}

.chips li {
    font-size: 0.7em;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--muted);
    border: 1px solid var(--rule);
    border-radius: 100px;
    padding: 3px 11px;
}

/* --- Timeline rail --------------------------------------------------------- */

.rail {
    list-style: none;
    margin: 24px 0 0;
    padding: 0 0 0 26px;
    position: relative;
}

.rail::before {
    content: "";
    position: absolute;
    left: 3px;
    top: 8px;
    bottom: 8px;
    width: 1px;
    background: linear-gradient(180deg, var(--accent), var(--rule) 55%, transparent);
}

.rail li {
    position: relative;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 20px;
    padding: 9px 0;
}

.rail li::before {
    content: "";
    position: absolute;
    left: -26px;
    top: 15px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--bg);
    border: 1px solid var(--muted);
}

.rail li:first-child::before {
    background: var(--accent);
    border-color: var(--accent);
}

.rail-date {
    color: var(--muted);
    font-size: 0.8em;
    white-space: nowrap;
    flex-shrink: 0;
}

/* --- Prose entries --------------------------------------------------------- */

.entry { padding: 10px 0 18px; }
.entry:last-child { padding-bottom: 0; }
.entry p { margin: 0.3em 0 0; }
.entry .muted { display: block; margin-bottom: 0.5em; }

/* --- Media ---------------------------------------------------------------- */

figure { margin: 28px 0; }

figure img,
.photo {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 2px;
}

figcaption {
    margin-top: 8px;
    color: var(--muted);
    font-size: 0.8em;
}

/* --- Document card ---------------------------------------------------------
   The inline viewer is treated as an enhancement: browsers without a PDF
   plugin, phones (which never render inline PDFs), and file:// origins all
   still get a usable header with Open and Download.
   -------------------------------------------------------------------------- */

.doc {
    border: 1px solid var(--rule);
    border-radius: 3px;
    overflow: hidden;
    margin: 26px 0;
    background: rgba(240, 238, 230, 0.02);
}

.doc-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    padding: 15px 16px;
}

.doc-id { display: flex; align-items: center; gap: 11px; min-width: 0; }

.doc-kind {
    flex-shrink: 0;
    font-size: 0.6em;
    letter-spacing: 0.12em;
    color: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 2px;
    padding: 3px 7px;
    line-height: 1;
}

.doc-name { display: block; font-size: 0.9em; line-height: 1.35; }
.doc-sub { display: block; color: var(--muted); font-size: 0.72em; }

.doc-actions { display: flex; gap: 8px; flex-shrink: 0; }

.btn {
    display: inline-block;
    font-size: 0.72em;
    letter-spacing: 0.05em;
    text-decoration: none;
    color: var(--text);
    border: 1px solid var(--rule);
    border-radius: 2px;
    padding: 7px 14px;
    white-space: nowrap;
    transition: border-color 0.2s var(--ease), background 0.2s var(--ease), color 0.2s var(--ease);
}

.btn:hover {
    border-color: var(--accent);
    background: rgba(204, 120, 92, 0.14);
    color: var(--text);
}

.btn-primary { border-color: var(--accent); color: var(--accent); }
.btn-primary:hover { background: var(--accent); color: #1F1E1D; }

.doc-view {
    display: block;
    width: 100%;
    height: 620px;
    border: 0;
    border-top: 1px solid var(--rule);
    background: #33312E;
}

.doc-view-tall { height: 80vh; min-height: 560px; }

.doc-fallback {
    display: none;
    border-top: 1px solid var(--rule);
    padding: 18px 16px;
    color: var(--muted);
    font-size: 0.8em;
}

/* Phones and small tablets never render an inline PDF — don't show them a
   blank grey rectangle, show the note instead. */
@media (max-width: 860px) {
    .doc-view { display: none; }
    .doc-fallback { display: block; }
}

/* --- Block diagram ---------------------------------------------------------- */

.blockdiagram { width: 100%; height: auto; display: block; margin: 26px 0 6px; overflow: visible; }

.blockdiagram .bd-box   { fill: rgba(240, 238, 230, 0.04); stroke: var(--rule); stroke-width: 1; }
.blockdiagram .bd-hv    { fill: rgba(204, 120, 92, 0.15); stroke: var(--accent); }
.blockdiagram .bd-text  { fill: var(--text); font-size: 12.5px; }
.blockdiagram .bd-sub   { fill: var(--muted); font-size: 9.5px; letter-spacing: 0.05em; }
.blockdiagram .bd-arrow { stroke: var(--muted); stroke-width: 1.3; fill: none; }
.blockdiagram .bd-tie   { stroke: var(--faint); stroke-width: 1; stroke-dasharray: 3 3; fill: none; }
.blockdiagram .bd-tip   { fill: var(--muted); }

/* --- Heat dependent fault (Miata) --------------------------------------------
   One switch drives the whole picture: the cracked joint opens when hot, and
   everything downstream of the immobilizer goes dark.
   -------------------------------------------------------------------------- */

.heat { margin: 28px 0 8px; }
.heat .switch { margin-bottom: 14px; }

.heat .hj-top { transition: transform 0.7s var(--ease); }
.heat[data-temp="hot"] .hj-top { transform: translateY(-5px); }

.heat .hj-cur {
    fill: none;
    stroke: var(--accent);
    stroke-width: 2.2;
    stroke-dasharray: 5 6;
    animation: ray-travel 1.6s linear infinite;
    transition: opacity 0.5s var(--ease);
}

.heat .hj-sig {
    fill: none;
    stroke: var(--accent);
    stroke-width: 1.4;
    transition: opacity 0.5s var(--ease);
}

.heat .hj-out { transition: opacity 0.5s var(--ease); }

.heat .hj-gap,
.heat .hj-x { opacity: 0; transition: opacity 0.5s var(--ease); }
.heat .hj-gap { fill: var(--accent); }
.heat .hj-x { fill: var(--accent); font-size: 14px; }

.heat[data-temp="hot"] .hj-cur-low,
.heat[data-temp="hot"] .hj-sig { opacity: 0.14; animation: none; }
.heat[data-temp="hot"] .hj-out { opacity: 0.3; }
.heat[data-temp="hot"] .hj-gap { opacity: 0.9; }
.heat[data-temp="hot"] .hj-x { opacity: 1; }

.heat-status {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-top: 6px;
}

.heat-status strong {
    font-weight: 600;
    white-space: nowrap;
    transition: color 0.3s var(--ease);
}

.heat[data-temp="hot"] .heat-status strong { color: var(--accent); }

/* --- Browser window preview --------------------------------------------------
   A live site shown inside a minimal window frame. The whole thing is a link.
   -------------------------------------------------------------------------- */

.browser {
    display: block;
    margin: 28px 0 10px;
    border: 1px solid var(--rule);
    border-radius: 6px;
    overflow: hidden;
    text-decoration: none;
    background: #151414;
    box-shadow: 0 18px 40px -22px rgba(0, 0, 0, 0.8);
    transition: border-color 0.25s var(--ease), transform 0.35s var(--ease), box-shadow 0.35s var(--ease);
}

.browser:hover,
.browser:focus-visible {
    border-color: var(--accent);
    transform: translateY(-2px);
    box-shadow: 0 26px 48px -24px rgba(0, 0, 0, 0.9);
    color: var(--text);
}

.browser-bar {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--rule);
    background: rgba(240, 238, 230, 0.03);
}

.browser-bar i {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: rgba(240, 238, 230, 0.16);
    flex-shrink: 0;
}

.browser-url {
    flex: 1;
    margin-left: 8px;
    padding: 4px 12px;
    border-radius: 100px;
    background: rgba(240, 238, 230, 0.05);
    color: var(--muted);
    font-size: 0.66em;
    letter-spacing: 0.04em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.browser-go {
    flex-shrink: 0;
    font-size: 0.66em;
    letter-spacing: 0.06em;
    color: var(--accent);
    transition: transform 0.25s var(--ease);
}

.browser:hover .browser-go { transform: translateX(3px); }

.browser-view {
    position: relative;
    display: block;
    aspect-ratio: 1760 / 1290;
    overflow: hidden;
}

.browser-view img,
.browser-view iframe {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
    object-fit: cover;
    object-position: top;
}

/* --- Career timeline -------------------------------------------------------- */

.timeline { width: 100%; height: auto; display: block; margin: 8px 0 4px; overflow: visible; }

.timeline .tl-grid  { stroke: var(--rule); stroke-width: 1; }
.timeline .tl-year  { fill: var(--faint); font-size: 10px; letter-spacing: 0.08em; }
.timeline .tl-label { fill: var(--muted); font-size: 11px; }
.timeline .tl-bar   { rx: 2; transition: opacity 0.2s var(--ease); }
.timeline .tl-industry { fill: var(--accent); opacity: 0.75; }
.timeline .tl-campus   { fill: rgba(240, 238, 230, 0.26); }
.timeline .tl-ongoing  { stroke: var(--faint); stroke-width: 1.5; stroke-dasharray: 2 4; }

/* Rows are clickable: each jumps to and opens its role below. The invisible
   hit rect spans the full width so the label is as clickable as the bar. */
.tl-hit { fill: transparent; }
.tl-row { cursor: pointer; }
.tl-row:focus { outline: none; }

.timeline .tl-row:hover .tl-bar,
.timeline .tl-row:focus-visible .tl-bar { opacity: 1; }

.timeline .tl-row:hover .tl-label { fill: var(--text); }
.timeline .tl-row:focus-visible .tl-label { fill: var(--accent); }

.timeline .tl-row:hover .tl-hit,
.timeline .tl-row:focus-visible .tl-hit { fill: rgba(240, 238, 230, 0.035); }

/* Brief clay wash on whichever role you jumped to */
@keyframes panel-flash {
    from { background-color: rgba(204, 120, 92, 0.16); }
    to   { background-color: transparent; }
}

.panel.is-flash { animation: panel-flash 1.4s var(--ease); }

.tl-key {
    display: flex;
    gap: 20px;
    flex-wrap: wrap;
    list-style: none;
    margin: 14px 0 0;
    padding: 0;
    font-size: 0.72em;
    color: var(--muted);
}

.tl-key li { display: flex; align-items: center; gap: 8px; }

.tl-key i {
    width: 18px;
    height: 8px;
    border-radius: 2px;
    display: inline-block;
}

/* Video, behind a poster so YouTube's chrome only appears once asked for */

.facade {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    margin: 24px 0;
    border: 0;
    padding: 0;
    border-radius: 3px;
    overflow: hidden;
    cursor: pointer;
    background: #000 center/cover no-repeat;
    display: block;
}

.facade img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    opacity: 0.72;
    transition: opacity 0.3s var(--ease), transform 0.5s var(--ease);
}

.facade:hover img { opacity: 0.92; transform: scale(1.02); }

.facade-play {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}

.facade-play span {
    width: 62px;
    height: 62px;
    border-radius: 50%;
    border: 1px solid rgba(240, 238, 230, 0.55);
    background: rgba(31, 30, 29, 0.55);
    backdrop-filter: blur(2px);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.25s var(--ease), border-color 0.25s var(--ease), transform 0.25s var(--ease);
}

.facade-play span::after {
    content: "";
    border-left: 13px solid var(--text);
    border-top: 8px solid transparent;
    border-bottom: 8px solid transparent;
    margin-left: 4px;
}

.facade:hover .facade-play span {
    background: rgba(204, 120, 92, 0.85);
    border-color: var(--accent);
    transform: scale(1.06);
}

.facade-label {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 30px 16px 12px;
    text-align: left;
    font-size: 0.8em;
    color: var(--text);
    background: linear-gradient(transparent, rgba(0, 0, 0, 0.75));
    pointer-events: none;
}

.facade iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

/* Spotify, forced to its dark theme and compact height so the player's own
   album-art colouring cannot take over the page. */

.spotify {
    width: 100%;
    height: 152px;
    border: 0;
    border-radius: 3px;
    margin: 14px 0;
    display: block;
    color-scheme: normal;
}

/* --- Gallery --------------------------------------------------------------- */

.gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
    margin: 24px 0;
}

.gallery figure { margin: 0; }

.gallery img {
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: 2px;
    transition: opacity 0.25s var(--ease), transform 0.4s var(--ease);
}

.gallery a { display: block; text-decoration: none; }
.gallery a:hover img { opacity: 0.82; transform: scale(1.015); }

/* Placeholder tiles for a gallery that is not filled in yet */

.slot {
    aspect-ratio: 4 / 3;
    border: 1px dashed var(--rule);
    border-radius: 2px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--faint);
    font-size: 0.7em;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-align: center;
    padding: 8px;
}

/* --- Callout --------------------------------------------------------------- */

.note {
    border-left: 1px solid var(--accent);
    padding: 2px 0 2px 18px;
    margin: 24px 0;
    color: var(--muted);
    font-size: 0.85em;
}

/* --- Scroll reveal ---------------------------------------------------------
   Only applied once JS confirms it can run, so the page is fully readable
   with scripting off.
   -------------------------------------------------------------------------- */

.js-reveal .reveal {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}

.js-reveal .reveal.is-in {
    opacity: 1;
    transform: none;
}

/* Once the animation has run, drop every trace of it. A lingering transform or
   composited layer stops Chrome's out-of-process PDF viewer from painting, which
   is what left the embedded documents blank. */
.js-reveal .reveal.is-done {
    opacity: 1;
    transform: none;
    transition: none;
}

/* --- Footer --------------------------------------------------------------- */

footer {
    position: relative;
    z-index: 1;
    max-width: var(--measure);
    margin: 0 auto;
    padding: 28px var(--gutter) 64px;
    border-top: 1px solid var(--rule);
    color: var(--muted);
    font-size: 0.8em;
    display: flex;
    justify-content: space-between;
    gap: 16px;
}

/* --- Responsive ----------------------------------------------------------- */

@media (max-width: 640px) {
    body { font-size: 18px; }

    .masthead {
        padding: 36px 0 32px;
        flex-direction: column;
        align-items: flex-start;
        gap: 14px;
    }

    .masthead nav { gap: 16px; flex-wrap: wrap; }

    .row { flex-direction: column; gap: 2px; padding: 8px 0; }
    .row-meta { white-space: normal; }

    .golink { gap: 12px; }

    .panel > summary { gap: 12px; }
    .panel-side { flex-direction: row-reverse; gap: 10px; }

    .rail li { flex-direction: column; gap: 2px; }
    .rail-date { white-space: normal; }

    .embed-pdf { height: 62vh; min-height: 380px; }
    .embed-pdf-tall { height: 68vh; }

    .gallery { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }

    footer { flex-direction: column; }
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }

    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }

    .js-reveal .reveal { opacity: 1; transform: none; }
}

/* ==========================================================================
   Interactive pieces
   ========================================================================== */

/* --- Spec grid ------------------------------------------------------------- */

.specs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
    gap: 1px;
    background: var(--rule);
    border: 1px solid var(--rule);
    border-radius: 3px;
    margin: 26px 0;
    overflow: hidden;
}

.spec {
    background: var(--bg);
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

.spec dt {
    color: var(--muted);
    font-size: 0.68em;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    margin: 0 0 4px;
}

.spec dd {
    margin: 0;
    font-size: 1.05em;
    font-variant-numeric: tabular-nums;
}

/* --- Optical path diagram -------------------------------------------------- */

.scope {
    width: 100%;
    height: auto;
    margin: 26px 0 10px;
    display: block;
    overflow: visible;
}

.scope .body   { fill: none; stroke: var(--muted); stroke-width: 1.5; }
.scope .glass  { fill: rgba(204, 120, 92, 0.22); stroke: var(--accent); stroke-width: 1.5; }
.scope .ray    { fill: none; stroke: var(--accent); stroke-width: 1.2; opacity: 0.85; }
.scope .label  { fill: var(--muted); font-size: 11px; font-family: inherit; letter-spacing: 0.04em; }
.scope .dim    { stroke: var(--rule); stroke-width: 1; }

.scope .ray-anim {
    stroke-dasharray: 6 10;
    animation: ray-travel 2.6s linear infinite;
}

@keyframes ray-travel { to { stroke-dashoffset: -32; } }

.scope-part { cursor: pointer; }
.scope-part:hover .body { stroke: var(--accent); }
.scope-part:hover .label { fill: var(--text); }

/* --- Magnification calculator ---------------------------------------------- */

.calc {
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 22px;
    margin: 26px 0;
    background: rgba(240, 238, 230, 0.02);
}

.calc-controls {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    align-items: flex-end;
}

.calc-field { flex: 1 1 150px; min-width: 130px; }

.calc-field label {
    display: block;
    color: var(--muted);
    font-size: 0.68em;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    margin-bottom: 6px;
}

.calc-field select {
    width: 100%;
    appearance: none;
    background: var(--bg);
    color: var(--text);
    border: 1px solid var(--rule);
    border-radius: 2px;
    padding: 9px 12px;
    font-family: inherit;
    font-size: 0.85em;
    cursor: pointer;
}

.calc-field select:hover { border-color: var(--accent); }

.calc-out {
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid var(--rule);
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.calc-value {
    font-size: 2.2em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.calc-note {
    color: var(--muted);
    font-size: 0.78em;
    max-width: 300px;
    text-align: right;
}

/* Apparent-size preview: a disc that scales with magnification */

.calc-view {
    position: relative;
    height: 132px;
    margin-top: 20px;
    border: 1px solid var(--rule);
    border-radius: 2px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    background:
        radial-gradient(circle at 30% 40%, rgba(240,238,230,0.05), transparent 60%),
        var(--bg);
}

.calc-disc {
    border-radius: 50%;
    background: radial-gradient(circle at 35% 32%, #E8DFD2, #B9A88F 62%, #7C6E5C);
    transition: width 0.45s var(--ease), height 0.45s var(--ease);
    flex-shrink: 0;
}

.calc-fov {
    position: absolute;
    border: 1px solid var(--rule);
    border-radius: 50%;
    width: 118px;
    height: 118px;
    pointer-events: none;
}

/* --- Stacked build-up bar --------------------------------------------------- */

.stack { margin: 26px 0; }

.stack-bar {
    display: flex;
    width: 100%;
    height: 34px;
    border: 1px solid var(--rule);
    border-radius: 2px;
    overflow: hidden;
}

.stack-seg {
    position: relative;
    border-right: 1px solid var(--rule);
    transition: background 0.2s var(--ease);
}

.stack-seg:last-child { border-right: 0; }
.stack-seg:nth-child(1) { background: rgba(204, 120, 92, 0.55); }
.stack-seg:nth-child(2) { background: rgba(240, 238, 230, 0.16); }
.stack-seg:nth-child(3) { background: rgba(240, 238, 230, 0.09); }
.stack-seg:nth-child(4) { background: rgba(240, 238, 230, 0.04); }

.stack-key {
    list-style: none;
    margin: 14px 0 0;
    padding: 0;
    display: grid;
    gap: 4px;
}

.stack-key li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    font-size: 0.8em;
    color: var(--muted);
    padding: 3px 0;
}

.stack-key li span:last-child {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.stack-key li.total {
    border-top: 1px solid var(--rule);
    margin-top: 6px;
    padding-top: 9px;
    color: var(--text);
}

.stack-swatch {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 1px;
    margin-right: 9px;
    vertical-align: baseline;
}

/* --- Learning / Working / Practicing chart ---------------------------------- */

.studychart { margin: 26px 0; }

.studychart-bars {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
    align-items: end;
    height: 210px;
    padding-bottom: 2px;
    border-bottom: 1px solid var(--rule);
}

.studybar { display: flex; flex-direction: column; justify-content: flex-end; height: 100%; }

.studybar i {
    display: block;
    height: var(--h);
    border-radius: 2px 2px 0 0;
    transition: height 0.55s var(--ease), background 0.3s var(--ease);
}

.studybar[data-key="learning"]  i { background: rgba(240, 238, 230, 0.30); }
.studybar[data-key="working"]   i { background: rgba(240, 238, 230, 0.18); }
.studybar[data-key="practicing"] i { background: var(--accent); }

.studychart-labels {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px;
    margin-top: 10px;
}

.studychart-labels span {
    font-size: 0.8em;
    color: var(--muted);
    text-align: center;
}

.switch {
    display: inline-flex;
    border: 1px solid var(--rule);
    border-radius: 100px;
    padding: 3px;
    margin-bottom: 22px;
    gap: 2px;
}

.switch button {
    appearance: none;
    background: none;
    border: 0;
    color: var(--muted);
    font: inherit;
    font-size: 0.75em;
    letter-spacing: 0.04em;
    padding: 6px 16px;
    border-radius: 100px;
    cursor: pointer;
    transition: background 0.2s var(--ease), color 0.2s var(--ease);
}

.switch button:hover { color: var(--text); }

.switch button[aria-pressed="true"] {
    background: var(--accent);
    color: #1F1E1D;
}

/* --- Definition rows (what practicing is / isn't) ---------------------------- */

.contrast {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1px;
    background: var(--rule);
    border: 1px solid var(--rule);
    border-radius: 3px;
    margin: 26px 0;
    overflow: hidden;
}

.contrast > div { background: var(--bg); padding: 18px 18px 20px; }

.contrast h4 {
    margin: 0 0 10px;
    font-size: 0.68em;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--muted);
    font-weight: 600;
}

.contrast.is-yes h4, .contrast div.yes h4 { color: var(--accent); }

.contrast ul { margin: 0; padding-left: 18px; }
.contrast li { font-size: 0.85em; margin-bottom: 7px; }
.contrast li:last-child { margin-bottom: 0; }

.contrast-3 { grid-template-columns: repeat(3, 1fr); }

@media (max-width: 640px) {
    .contrast,
    .contrast-3 { grid-template-columns: 1fr; }
    .calc-note { text-align: left; max-width: none; }
    .studychart-bars { height: 165px; }
    .specs { grid-template-columns: repeat(2, 1fr); }
}

/* ==========================================================================
   Print
   The screen design is ivory on near black with an animated star field. None
   of that belongs on paper, and a recruiter hitting Ctrl+P on the résumé
   should get something clean.
   ========================================================================== */

@media print {
    :root {
        --bg:    #FFFFFF;
        --text:  #000000;
        --muted: #444444;
        --faint: #666666;
        --rule:  rgba(0, 0, 0, 0.22);
        --tint:  transparent;
    }

    html, body {
        background: #FFFFFF !important;
        color: #000000 !important;
        font-size: 11pt;
    }

    /* Screen furniture that has no meaning on paper */
    #star-bg,
    #progress,
    .skip,
    .masthead nav,
    .facade,
    .spotify,
    .doc-view,
    .doc-actions,
    .doc-fallback,
    .switch,
    .calc-view,
    .tl-key,
    footer {
        display: none !important;
    }

    .wrap, footer { max-width: none; padding: 0; }
    main { padding-bottom: 0; }

    /* Expanded panels print their contents; collapsed ones print too, so
       nothing silently goes missing from a printed page. */
    .panel > summary { padding-left: 0; margin-left: 0; }
    .panel-sign { display: none; }
    .panel-body { display: block !important; padding-left: 0; }
    .panel[open] { background: none; }
    .panel[open] > summary { border-left: 0; margin-left: 0; padding-left: 0; }

    /* Never animate or hide content on paper */
    .js-reveal .reveal { opacity: 1 !important; transform: none !important; }

    .section {
        margin-top: 22pt;
        padding-top: 14pt;
        break-inside: avoid;
    }

    .section::before { background: #000000; }

    h2, h3 { break-after: avoid; }
    .entry, .panel, figure, .specs { break-inside: avoid; }

    a { color: #000000; text-decoration: underline; }

    /* Spell out where offsite links actually go */
    main a[href^="http"]::after {
        content: " (" attr(href) ")";
        font-size: 0.75em;
        color: #555555;
        word-break: break-all;
    }

    .chips li, .spec, .doc { border-color: rgba(0, 0, 0, 0.25); }
    .doc { background: none; }
    .golink { margin: 0; padding: 4pt 0; }
    .golink-arrow { display: none; }

    img { max-width: 100% !important; }
}

/* ==========================================================================
   ASCII art
   Hand drawn pieces decode into place as they scroll into view, and photos
   can be rendered live as characters. Monospace is the only other typeface on
   the site, and it only ever appears here.
   ========================================================================== */

.ascii {
    margin: 0;
    font-family: ui-monospace, "Cascadia Mono", Consolas, "SFMono-Regular", Menlo, monospace;
    font-size: 11px;            /* replaced at runtime so the widest line fits exactly */
    line-height: 1.18;
    color: var(--muted);
    white-space: pre;
    overflow: hidden;
    user-select: none;
    letter-spacing: 0;
}

.ascii-wrap { margin: 30px 0 14px; }
.ascii-wrap.center .ascii { text-align: left; display: inline-block; }
.ascii-wrap.center { text-align: center; }

.ascii .tw {
    color: var(--text);
    transition: color 0.6s var(--ease), opacity 0.6s var(--ease);
}

.ascii .tw.on { color: var(--accent); }
.ascii .ac { color: var(--accent); }

.ascii-cap {
    margin-top: 10px;
    color: var(--muted);
    font-size: 0.8em;
}

/* --- Photo rendered as text ------------------------------------------------- */

.asciiimg {
    position: relative;
    margin: 28px 0 10px;
    border: 1px solid var(--rule);
    border-radius: 3px;
    overflow: hidden;
    cursor: pointer;
    background: #181716;
    outline-offset: 4px;
}

.asciiimg .ascii {
    display: block;
    line-height: 1;
    color: var(--text);
    opacity: 0.86;
    transition: opacity 0.6s var(--ease);
}

.asciiimg img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity 0.7s var(--ease);
}

/* Until JS has drawn the text version, simply show the photo. */
.asciiimg:not(.is-ready) img { position: static; opacity: 1; }
.asciiimg:not(.is-ready) .ascii { display: none; }

.asciiimg.is-photo img { opacity: 1; }
.asciiimg.is-photo .ascii { opacity: 0; }

@media (hover: hover) {
    .asciiimg:hover img { opacity: 1; }
    .asciiimg:hover .ascii { opacity: 0; }
    .asciiimg.is-photo:hover img { opacity: 0; }
    .asciiimg.is-photo:hover .ascii { opacity: 0.86; }
}

.asciiimg-hint {
    position: absolute;
    right: 10px;
    bottom: 9px;
    font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
    font-size: 10px;
    letter-spacing: 0.08em;
    color: var(--accent);
    background: rgba(24, 23, 22, 0.82);
    padding: 3px 8px;
    border-radius: 2px;
    pointer-events: none;
    transition: opacity 0.4s var(--ease);
}

.asciiimg:hover .asciiimg-hint,
.asciiimg.is-photo .asciiimg-hint { opacity: 0; }

@media print {
    .ascii-wrap, .asciiimg .ascii, .asciiimg-hint { display: none !important; }
    .asciiimg img { position: static !important; opacity: 1 !important; }
}

/* Colour arrives after the characters settle, like a print developing. */
@keyframes ascii-bloom {
    from { filter: saturate(0) brightness(1.35); }
    to   { filter: none; }
}

.asciiimg .ascii.is-color { animation: ascii-bloom 1.6s var(--ease) both; }

/* --- ASCII wordmark ----------------------------------------------------------
   The serif name stays in the markup for screen readers, search, print and
   no JS. Once the script draws the ASCII version it takes over visually.
   -------------------------------------------------------------------------- */

.wordmark-art { display: none; }

.wordmark.is-ascii .wordmark-text {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.wordmark.is-ascii .wordmark-art {
    display: block;
    color: var(--text);
    line-height: 1.12;
    transition: color 0.25s var(--ease);
}

.masthead.has-ascii { align-items: center; }
.wordmark.is-ascii { min-width: 0; flex: 1 1 auto; }

.wordmark.is-ascii a:hover .wordmark-art,
.wordmark.is-ascii a:focus-visible .wordmark-art { color: var(--accent); }

@media (max-width: 640px) {
    .masthead.has-ascii { align-items: flex-start; }
    .wordmark.is-ascii { width: 100%; }
}

@media print {
    .wordmark.is-ascii .wordmark-art { display: none !important; }
    .wordmark.is-ascii .wordmark-text { position: static; width: auto; height: auto; clip: auto; }
}
