/* ============================================================
   FREESTYLE
   A second skin for the homepage only. Loaded after styles.css, so it wins
   every tie. The house rules this deliberately breaks are listed where they
   are broken.
   ============================================================ */

:root {
    --fs-ink: #0a0a0a;
    --fs-paper: #ffffff;
}

/* ------------------------------------------------------------
   Grain. One fixed overlay above everything, including the header.
   ------------------------------------------------------------ */
.fs-grain {
    position: fixed;
    inset: 0;
    z-index: 55;
    pointer-events: none;
    opacity: 0.055;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------
   The cursor. The white square with an arrow that used to sit in the middle
   of a hovered cover is gone: the cursor itself says what a click does.
   ------------------------------------------------------------ */
.fs-cursor {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 60;
    width: 10px;
    height: 10px;
    margin: -5px 0 0 -5px;
    border-radius: 50%;
    background: var(--fs-ink);
    pointer-events: none;
    opacity: 0;
    will-change: transform;
    transition: opacity 200ms var(--ease-out), width 260ms var(--ease-out),
                height 260ms var(--ease-out), margin 260ms var(--ease-out),
                background-color 260ms var(--ease-out);
}

.fs-cursor.is-live { opacity: 1; }

.fs-cursor.on-dark { background: var(--fs-paper); }

.fs-cursor.is-view {
    width: 92px;
    height: 92px;
    margin: -46px 0 0 -46px;
    background: var(--fs-ink);
}

.fs-cursor.is-view.on-dark { background: var(--fs-paper); }

.fs-cursor-label {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--fs-paper);
    opacity: 0;
    transform: scale(0.8);
    transition: opacity 200ms var(--ease-out), transform 260ms var(--ease-out);
}

.fs-cursor.on-dark .fs-cursor-label { color: var(--fs-ink); }

.fs-cursor.is-view .fs-cursor-label {
    opacity: 1;
    transform: scale(1);
}

/* The real cursor goes away only where the drawn one is doing its job. */
@media (hover: hover) and (pointer: fine) {
    html.fs-cursor-on body,
    html.fs-cursor-on a,
    html.fs-cursor-on button { cursor: none; }
}

/* ------------------------------------------------------------
   The first screen. Full bleed, dark, and the work itself is the field
   behind the name. This breaks "no brand colour on the chrome" and it
   breaks "transform and opacity only" nowhere: the field drifts on
   transform and the veil is a static gradient.
   ------------------------------------------------------------ */
.fs-rig {
    position: relative;
    height: 170vh;
}

.fs-hero {
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100svh;
    overflow: hidden;
    background: var(--fs-ink);
    display: flex;
    align-items: center;
}

.fs-reel {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    will-change: transform;
}

/* The type side is nearly solid and the far side lets the work through, so
   the empty right half of the old first screen is now the portfolio. */
.fs-veil {
    position: absolute;
    inset: 0;
    /* Three layers. The flat one sets a floor, because the reel runs from a
       black device render to a white interface and the type has to hold on
       both. The vertical one seats the header and the foot line, the
       horizontal one keeps the name on near solid ink and lets the work
       through on the far side. */
    background:
        linear-gradient(rgba(10,10,10,0.3), rgba(10,10,10,0.3)),
        linear-gradient(180deg, rgba(10,10,10,0.8) 0%, rgba(10,10,10,0) 20%, rgba(10,10,10,0) 68%, rgba(10,10,10,0.88) 100%),
        linear-gradient(90deg, var(--fs-ink) 16%, rgba(10,10,10,0.88) 36%, rgba(10,10,10,0.42) 64%, rgba(10,10,10,0.18) 100%);
    pointer-events: none;
}

.fs-hero-inner {
    position: relative;
    z-index: 2;
    width: 100%;
    padding: 0 clamp(1.5rem, 5vw, 5rem);
    will-change: transform, opacity;
}

.fs-h1 {
    font-family: 'Space Grotesk', sans-serif;
    font-size: clamp(2.75rem, 7.6vw, 8.5rem);
    line-height: 0.96;
    letter-spacing: -0.03em;
    color: var(--fs-paper);
    margin: 0 0 clamp(1.5rem, 3vw, 2.5rem);
    max-width: 16ch;
    /* The reel runs from a black device render to a white interface, so the
       type carries its own ground rather than depending on the veil to be
       right for every shot. Wide and soft, so it reads as depth and not as
       an outline. */
    text-shadow: 0 4px 40px rgba(10, 10, 10, 0.75), 0 1px 10px rgba(10, 10, 10, 0.5);
}

.fs-h1 span { display: block; }

.fs-line {
    font-weight: 700;
}

/* The line that is meant to recede is drawn rather than filled. */
.fs-line--ghost {
    font-weight: 700;
    color: transparent;
    -webkit-text-stroke: 1px rgba(255, 255, 255, 0.72);
}

.fs-mask {
    display: block;
    overflow: hidden;
    padding: 0.14em 0 0.18em;
    margin: -0.14em 0 -0.18em;
}

.fs-rise {
    display: block;
    transform: translateY(105%);
    animation: fsRise 1s var(--ease-out) forwards;
}

@keyframes fsRise {
    to { transform: translateY(0); }
}

.fs-sub {
    text-shadow: 0 2px 22px rgba(10, 10, 10, 0.8);
    max-width: 44ch;
    color: #a3a3a3;
    font-size: clamp(1rem, 1.25vw, 1.375rem);
    line-height: 1.6;
    opacity: 0;
    animation: fsFade 0.9s var(--ease-out) 700ms forwards;
}

.fs-sub b {
    display: inline-block;
    background: var(--fs-paper);
    color: var(--fs-ink);
    padding: 0.1em 0.45em;
    font-weight: 700;
}

@keyframes fsFade {
    to { opacity: 1; }
}

.fs-hero-foot {
    position: absolute;
    left: 0;
    right: 0;
    bottom: clamp(1.5rem, 3vw, 2.5rem);
    z-index: 2;
    padding: 0 clamp(1.5rem, 5vw, 5rem);
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: #a3a3a3;
    opacity: 0;
    animation: fsFade 0.9s var(--ease-out) 1000ms forwards;
}

.fs-count b { color: var(--fs-paper); font-weight: 700; }

/* The header sits on black for the whole first screen. */
#main-header.fs-on-dark .nav-link,
#main-header.fs-on-dark .masthead-place,
#main-header.fs-on-dark #mobile-menu-btn { color: #e5e5e5; }

#main-header.fs-on-dark .logo-pill {
    background: var(--fs-paper);
    color: var(--fs-ink);
}

/* ------------------------------------------------------------
   The work. Thirteen covers stop being a contact sheet: a twelve column
   field with varied spans and vertical offsets, and every cover parallaxes
   inside its own frame.
   ------------------------------------------------------------ */
.fs-work {
    position: relative;
    z-index: 2;
    background: var(--fs-paper);
    padding: clamp(4rem, 9vw, 9rem) clamp(1.5rem, 5vw, 5rem) clamp(5rem, 10vw, 10rem);
}

.fs-work-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    margin-bottom: clamp(2rem, 5vw, 4rem);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: #737373;
}

.fs-grid {
    display: grid;
    grid-template-columns: 1fr;
    column-gap: clamp(1.5rem, 3vw, 3.5rem);
    row-gap: clamp(3.5rem, 7vw, 7rem);
}

@media (min-width: 768px) {
    .fs-grid { grid-template-columns: 1fr 1fr; }
}

.fs-card {
    text-decoration: none;
    color: inherit;
    display: block;
}

.fs-shot {
    display: block;
    position: relative;
    overflow: hidden;
    background: #f5f5f5;
    aspect-ratio: 4 / 3;
}

.fs-shot-inner {
    position: absolute;
    inset: 0;
    display: block;
    overflow: hidden;
}

/* No parallax inside the frame. Moving the artwork needs it blown up past the
   frame, which took another 6% off the top and bottom of every cover on top of
   whatever the 4:3 crop already costs. A cover that has to be read whole
   cannot travel, so it does not. */
.fs-shot img,
.fs-shot video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.fs-meta {
    display: flex;
    align-items: baseline;
    gap: clamp(0.75rem, 1.6vw, 1.5rem);
    margin-top: 1.25rem;
}

/* The index is a mark, not a caption: set in the display face at the size of
   the project name, with the slash recessed so the number reads first. */
.fs-num {
    flex: none;
    font-family: 'Space Grotesk', sans-serif;
    font-weight: 700;
    font-size: clamp(1.125rem, 1.7vw, 1.75rem);
    line-height: 1;
    letter-spacing: -0.01em;
    color: #171717;
    font-variant-numeric: tabular-nums;
}

.fs-num i {
    font-style: normal;
    color: #d4d4d4;
}

.fs-meta-text {
    display: block;
    flex: 1 1 auto;
    min-width: 0;
}

.fs-name,
.fs-desc { display: block; }

/* The grid carries some of the headline's weight rather than dropping back to
   a caption under a picture. */
.fs-name {
    font-family: 'Space Grotesk', sans-serif;
    font-weight: 700;
    font-size: clamp(1.5rem, 2.6vw, 2.75rem);
    line-height: 1.05;
    letter-spacing: -0.025em;
    color: var(--fs-ink);
}

.fs-desc {
    margin-top: 0.5rem;
    color: #737373;
    font-size: clamp(0.9375rem, 1.05vw, 1.0625rem);
}

/* The Type label was on every card in the original grid and is the only thing
   separating thirteen covers that are otherwise all "a project". It sits over
   the year, right aligned, the way .card-meta does on the live site. */
.fs-tags {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.5rem;
    text-align: right;
}

.fs-tag {
    display: inline-block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: #737373;
    border: 1px solid #e5e5e5;
    padding: 0.375rem 0.625rem;
    white-space: nowrap;
    transition: background-color 300ms var(--ease-out), color 300ms var(--ease-out), border-color 300ms var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
    .fs-card:hover .fs-tag {
        background: var(--fs-ink);
        border-color: var(--fs-ink);
        color: var(--fs-paper);
    }
}

.fs-year {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: #a3a3a3;
    white-space: nowrap;
}

@media (hover: hover) and (pointer: fine) {
    .fs-shot-inner { transition: transform 700ms var(--ease-out); }
    .fs-card:hover .fs-shot-inner { transform: scale(1.055); }
    .fs-name { transition: transform 300ms var(--ease-out); }
    .fs-card:hover .fs-name { transform: translateX(10px); }
}

/* ------------------------------------------------------------
   Reduced motion. The field stops dead, the hero stops pinning, the drawn
   cursor never mounts and every parallax is left at rest.
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
    .fs-rig { height: auto; }
    .fs-hero { position: relative; }
    .fs-rise { transform: none; animation: none; }
    .fs-sub,
    .fs-hero-foot { opacity: 1; animation: none; }
    .fs-shot-inner { transition: none; }
    .fs-card:hover .fs-shot-inner { transform: none; }
    .fs-card:hover .fs-name { transform: none; }
}

/* ------------------------------------------------------------
   The statement band. White, black, white: the page needed a beat between
   thirteen covers and a column of prose.
   ------------------------------------------------------------ */
.fs-say {
    position: relative;
    z-index: 2;
    background: var(--fs-ink);
    padding: clamp(4rem, 9vw, 7rem) clamp(1.5rem, 5vw, 5rem) clamp(4rem, 10vw, 8rem);
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* The sentence is the section's own label now, not a claim competing with the
   mark beside it. The hairline is the same ornament the hero place line uses. */
.fs-say-kicker {
    align-self: flex-start;
    display: flex;
    align-items: center;
    gap: 1rem;
    margin: 0 0 clamp(2.5rem, 6vw, 5rem);
    font-size: clamp(0.9375rem, 1vw, 1.125rem);
    line-height: 1.4;
    color: #a3a3a3;
    overflow: hidden;
}

.fs-say-rule {
    flex: none;
    display: block;
    width: 3rem;
    height: 1px;
    background: #525252;
}

/* clip-path is the sanctioned fourth property, the same one .cover-reveal and
   the headline entrance already use. */
.fs-say-inner {
    display: block;
    clip-path: inset(0 100% 0 0);
    transition: clip-path 1100ms var(--ease-out);
}

.fs-say-inner.is-said {
    clip-path: inset(0 0 0 0);
}

/* A fixed square, not a box that fits its text: the canvas is sized from this
   element and the mark is sized from the canvas, so a box that grew with each
   word would pump the logo. Same rule the 404 stage is built on. */
.fs-say-mark {
    position: relative;
    width: min(66vmin, 640px);
    height: min(66vmin, 640px);
    font-family: 'Space Grotesk', sans-serif;
    font-weight: 700;
    font-size: clamp(2.5rem, 10vmin, 6.5rem);
    line-height: 1;
    letter-spacing: -0.02em;
    /* the engine draws the specks in this colour */
    color: #e8e8e8;
    text-align: center;
}

/* The specks need somewhere to fly. The default bleed is sized for a word
   that only drifts; a burst that doubles the spread needs the canvas wider
   than the square or the explosion is clipped at the edges. */
.fs-say-mark .cta-dust-canvas {
    left: -0.95em;
    top: -1.05em;
    width: calc(100% + 1.9em);
    height: calc(100% + 2.1em);
}

.fs-say-mark .cta-dust-label {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 420ms var(--ease-out);
}

/* ------------------------------------------------------------
   The phone. One lane of work down the right edge, and the veil carries
   enough weight on the left that the name never fights it.
   ------------------------------------------------------------ */
@media (max-width: 767px) {
    .fs-veil {
        background:
            linear-gradient(180deg, rgba(10,10,10,0.6) 0%, rgba(10,10,10,0) 16%, rgba(10,10,10,0) 58%, rgba(10,10,10,0.96) 100%),
            linear-gradient(90deg, var(--fs-ink) 44%, rgba(10,10,10,0.88) 62%, rgba(10,10,10,0.4) 100%);
    }
}

@media (prefers-reduced-motion: reduce) {
    .fs-say-inner { clip-path: none; transition: none; }
}
