/* ========================
   FONT FACE
   ======================== */

@font-face {
    font-family: 'NHaasGrotesk';
    src: url('../assets/fonts/NHaasGroteskDSPro-45Lt.woff2') format('woff2'),
         url('../assets/fonts/NHaasGroteskDSPro-45Lt.otf') format('opentype');
    font-weight: 300;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'NHaasGrotesk';
    src: url('../assets/fonts/NHaasGroteskDSPro-55Rg.woff2') format('woff2'),
         url('../assets/fonts/NHaasGroteskDSPro-55Rg.otf') format('opentype');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'NHaasGrotesk';
    src: url('../assets/fonts/NHaasGroteskDSPro-65Md.woff2') format('woff2'),
         url('../assets/fonts/NHaasGroteskDSPro-65Md.otf') format('opentype');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'NHaasGrotesk';
    src: url('../assets/fonts/NHaasGroteskDSPro-75Bd.woff2') format('woff2'),
         url('../assets/fonts/NHaasGroteskDSPro-75Bd.otf') format('opentype');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

/* Geist Mono (OFL), self-hosted: the whole site */
@font-face {
    font-family: 'Geist Mono';
    src: url('../assets/fonts/GeistMono-Variable-latin.woff2') format('woff2');
    font-weight: 400 500;
    font-style: normal;
    font-display: swap;
}

/* ========================
   RESET
   ======================== */

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

:root {
    --primary: rgba(0, 0, 0, 0.85);
    --secondary: rgba(0, 0, 0, 0.42);
    --muted: rgba(0, 0, 0, 0.32);
    --bg: #ffffff;
    --text: #000000;
    /* The site's one typeface. Neue Haas stays available as --nhaas, only
       for projects whose own work is set in it (Zero, pasternak.cv). */
    --font: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;
    --nhaas: 'NHaasGrotesk', 'Neue Haas Grotesk Display Pro', Helvetica, Arial, sans-serif;
}

html, body {
    height: 100%;
    font-family: var(--font);
    font-weight: 400;
    background: var(--bg);
    color: var(--text);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow: hidden;
}

/* ========================
   FONT TEST — ?font=haas shows the whole site in Neue Haas, ?font=mono goes
   back to Geist Mono. The choice sticks in this browser until changed.
   ======================== */

html.font-haas {
    --font: var(--nhaas);
}

html.font-haas .nav-link,
html.font-haas .project-label,
html.font-haas .slide-name,
html.font-haas .next-project,
html.font-haas .home-caption {
    font-size: 13px;
}

html.font-haas .readout,
html.font-haas .xhair-label {
    letter-spacing: 0.05em;
}

/* ========================
   CURSOR — a crosshair that says what a click does (cursor.js). Only on
   a mouse or trackpad; touch keeps the system behaviour. The system
   pointer is hidden only once cursor.js has taken over.
   ======================== */

html.has-xhair,
html.has-xhair body,
html.has-xhair a,
html.has-xhair button {
    cursor: none;
}

.xhair {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 9998;
    pointer-events: none;
    will-change: transform;
}

.xhair[hidden] { display: none; }

.xhair-cross {
    position: absolute;
    left: -10px;
    top: -10px;
    width: 21px;
    height: 21px;
    /* No blend mode: the parent is its own stacking context, so a blended
       child had nothing to blend with and the cross disappeared on white. */
    filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.55));
}

.xhair-cross::before,
.xhair-cross::after {
    content: '';
    position: absolute;
    background: #111;
}

body.dark .xhair-cross::before,
body.dark .xhair-cross::after,
body.slide-dark .xhair-cross::before,
body.slide-dark .xhair-cross::after {
    background: #fff;
}

body.dark .xhair-cross,
body.slide-dark .xhair-cross { filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.55)); }

/* The game runs on the theme turned inside out, so the cross flips too */
html.gating .xhair-cross::before,
html.gating .xhair-cross::after { background: #f2f2f0; }
html.gating .xhair-cross { filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.55)); }
html.gating .xhair-label { background: #fff; color: #000; }

html.gating body.dark .xhair-cross::before,
html.gating body.dark .xhair-cross::after { background: #1c1c1c; }
html.gating body.dark .xhair-cross { filter: drop-shadow(0 0 1px rgba(255, 255, 255, 0.55)); }
html.gating body.dark .xhair-label { background: #000; color: #fff; }

.xhair-cross::before { left: 10px; top: 0; width: 1px; height: 21px; }
.xhair-cross::after { left: 0; top: 10px; width: 21px; height: 1px; }

.xhair-label {
    position: absolute;
    left: 14px;
    top: 12px;
    padding: 4px 6px;
    background: #000;
    color: #fff;
    font-family: var(--font);
    font-size: 10px;
    font-weight: 500;
    line-height: 1;
    letter-spacing: 0.02em;
    white-space: pre;
}

.xhair-label:empty { display: none; }

.xhair.flip .xhair-label { left: auto; right: 14px; }

body.dark .xhair-label,
body.slide-dark .xhair-label {
    background: #fff;
    color: #000;
}

body.loaded {
    overflow: auto;
}

/* ========================
   PAGE TRANSITIONS
   ======================== */

/* Moving between pages: the old page stays put and the new one settles
   up over it, soft and quick. No blank frame in between. Browsers without
   view transitions just swap pages. */
@view-transition {
    navigation: auto;
}

::view-transition-old(root) {
    animation: none;
}

::view-transition-new(root) {
    animation: page-settle 0.42s cubic-bezier(0.16, 1, 0.3, 1) both;
}

@keyframes page-settle {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    @view-transition {
        navigation: none;
    }
}

/* Loader removed — site lands directly on home. */

/* ========================
   MAIN SITE
   ======================== */

.site {
    /* Always visible — children (nav, home-center) handle their own reveal
       transitions via the .site.visible parent class. */
}

/* ========================
   HOMEPAGE
   ======================== */

.home {
    position: relative;
    width: 100vw;
    /* 100svh, not 100vh. On iOS Safari `100vh` is the viewport with the browser chrome
       HIDDEN — the tallest it ever gets — so a full-height page is taller than what you
       can see, and everything pinned to its bottom (the section switch, the clock) sits
       under the toolbar: visible on the way past, never tappable. That is the whole of
       "the nav bar isn't usable". `svh` is the SMALLEST viewport, so the bottom is always
       reachable, and unlike `dvh` it does not resize while you scroll. The 100vh line
       stays first as the fallback for anything that does not know svh. */
    height: 100vh;
    height: 100svh;
    overflow: hidden;
}

/* --- Nav — one word on the left (Contact from home, Index from everywhere
   else), your square (the theme button) or Figma on the right. --- */
.nav {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 44px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 13px;
    z-index: 100;
}

.nav-mark,
.nav-right {
    position: relative;
}

/* The theme button: two overlapping squares, like the fill and stroke
   swatches in a design tool. In light your solid square sits in front; a
   click slides them past each other, so in dark the outline is in front.
   The solid is an opaque ink so the outline behind can't show through it. */
.nav-mark {
    display: block;
    width: 19px;
    height: 19px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
}

.swatch {
    position: absolute;
    top: 0;
    left: 0;
    width: 14px;
    height: 14px;
}

.swatch-fill {
    z-index: 2;
    background: #262626;
}

.swatch-stroke {
    z-index: 1;
    background: var(--bg);
    border: 1px solid var(--primary);
    transform: translate(5px, 5px);
}

body.dark .swatch-fill {
    z-index: 1;
    background: #d9d9d9;
    transform: translate(5px, 5px);
}

body.dark .swatch-stroke {
    z-index: 2;
    transform: none;
}

/* Slide only during an actual switch, never on page load. Beats the
   theme-anim colour rule further down, which would otherwise drop it. */
body.theme-anim .swatch {
    transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1),
                background-color 0.25s ease,
                border-color 0.25s ease !important;
}

/* Small text controls keep their look but get a finger-sized hit area */
.nav-link,
.nav-figma,
.next-project {
    position: relative;
}

.nav-link::after,
.nav-figma::after,
.next-project::after {
    content: '';
    position: absolute;
    inset: -12px -8px;
}

/* A bigger hit area than the squares */
.nav-mark::after {
    content: '';
    position: absolute;
    inset: -6px;
}

.nav-right {
    display: flex;
    align-items: center;
    gap: 11px;
}

/* One word where Menu was: Contact on the home page, Index everywhere else */
.nav-link {
    font-family: var(--font);
    font-size: 12px;
    font-weight: 400;
    line-height: 1.144;
    letter-spacing: 0;
    color: var(--primary);
    text-decoration: none;
    transition: color 0.2s ease;
}

.nav-link:hover {
    color: var(--secondary);
}

/* ========================
   ACCESSIBILITY — focus rings + reduced motion
   ======================== */

.nav-mark:focus-visible,
.nav-link:focus-visible,
.next-project:focus-visible {
    outline: 1.5px solid var(--primary);
    outline-offset: 3px;
    border-radius: 2px;
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ========================
   DARK MODE
   ======================== */

body.dark {
    --primary: rgba(255, 255, 255, 0.85);
    --secondary: rgba(255, 255, 255, 0.42);
    --muted: rgba(255, 255, 255, 0.32);
    --bg: #0a0a0a;
    --text: #ffffff;
}

body.dark .loader {
    background: var(--bg);
}

/* Theme cross-fade — colours ease for the duration of a theme switch.
   darkmode.js adds .theme-anim only while toggling, so normal hover
   transitions are untouched the rest of the time. */
body.theme-anim,
body.theme-anim *,
body.theme-anim *::before,
body.theme-anim *::after {
    transition: background-color 0.25s ease,
                color 0.25s ease,
                border-color 0.25s ease !important;
}

/* ========================
   MOBILE
   ======================== */

@media (max-width: 768px) {

    html, body {
        cursor: auto;
    }

    .nav {
        padding: 0 12px;
    }

    .nav-link {
        font-size: 12px;
    }

}

/* ---------------------------------------------------------------------------
   Contact, as an icon. (In style.css, not home.css: the nav is on every
   page and home.css is not — in home.css the icon had no width outside the
   section pages, which is exactly how it was found.) It sat in the top-left as the word "Contact" and is now
   an envelope in the same well as the section switch in the opposite corner, so
   the two corners read as one system rather than as a word and a control.

   The flap is the whole idea: a closed envelope is a letter you have not sent,
   and it opens as you reach for it. Everything else here is furniture. */
.nav-icon {
    display: inline-grid;
    place-items: center;
    width: 34px;
    height: 26px;
    border-radius: 999px;
    background: var(--ui-well, rgba(0, 0, 0, 0.05));
    color: var(--ui);
    transition: background 0.26s cubic-bezier(0.32, 0.72, 0, 1);
}
body.dark .nav-icon { background: rgba(255, 255, 255, 0.08); }
.nav-icon:hover { background: var(--ui); color: var(--bg, #fff); }
body.dark .nav-icon:hover { background: rgba(255, 255, 255, 0.92); color: #101112; }

.mailicon { position: relative; display: block; width: 15px; height: 11px; }
.mailicon s {
    position: absolute;
    display: block;
    text-decoration: none;
}
.mailicon .bx { inset: 0; border: 1px solid currentColor; border-radius: 2px; }
/* the flap is a triangle hinged on the envelope's top edge; it falls open forward,
   which is why it rotates past 90deg rather than to it */
.mailicon .fl {
    left: 0; right: 0; top: 0; height: 7px;
    background: currentColor;
    clip-path: polygon(0 0, 100% 0, 50% 100%);
    transform-origin: top;
    transition: transform 0.36s cubic-bezier(0.32, 0.72, 0, 1);
}
.nav-icon:hover .mailicon .fl { transform: rotateX(148deg); }

/* the contact page's own corner: the same well, pointing back at the work */
.backicon { display: block; width: 15px; height: 11px; }
.backicon svg { width: 15px; height: 11px; display: block; overflow: visible; }
.backicon path { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.nav-icon .backicon svg { transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1); }
.nav-icon:hover .backicon svg { transform: translateX(-2px); }

@media (prefers-reduced-motion: reduce) {
    .mailicon .fl, .nav-icon, .nav-icon .backicon svg { transition: none; }
}
