/* ==========================================================================
   Sam Dean — the whole front end.

   Near-black ground, no accent colour. The work supplies every colour on the
   page; the chrome supplies none. That is the entire brief for a retoucher's
   portfolio, and it is why there is no orange in here.
   ========================================================================== */

@font-face {
    font-family: 'Abel';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/abel-latin-400.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Dark is the default, and the only palette a visitor gets without JavaScript.
   The light values live in one block below; an inline script in <head> sets
   data-theme before first paint, from the stored choice or the OS preference,
   so the page never flashes the wrong one. */
:root {
    color-scheme: dark;

    --sd-bg: #0b0b0b;
    --sd-bg-raised: #141414;
    /* Text is pure white in dark and pure black in light — no greys anywhere.
       --sd-muted survives as a name so each rule still reads with its intent,
       but it resolves to the same value; hover feedback is a dip in opacity,
       since there is no lighter shade left to move to. */
    --sd-fg: #ffffff;
    --sd-muted: #ffffff;
    --sd-line: rgba(255, 255, 255, .12);

    --sd-header-bg: rgba(11, 11, 11, .72);

    /* Chrome that sits *on top of photographs* rather than on the page, so it
       cannot use --sd-fg: it has to stay legible against whatever the image is
       doing underneath. */
    --sd-chrome-fg: #ffffff;
    --sd-chrome-muted: #ffffff;
    --sd-chrome-shadow: 0 1px 14px rgba(0, 0, 0, .8), 0 0 4px rgba(0, 0, 0, .6);
    --sd-chrome-drop: drop-shadow(0 1px 10px rgba(0, 0, 0, .85)) drop-shadow(0 0 3px rgba(0, 0, 0, .6));
    --sd-chrome-scrim: linear-gradient(to bottom, rgba(0, 0, 0, .55) 0%, rgba(0, 0, 0, .22) 55%, rgba(0, 0, 0, 0) 100%);
    --sd-chrome-pill: rgba(0, 0, 0, .34);
    --sd-chrome-pill-hover: rgba(0, 0, 0, .72);

    --sd-tile-scrim: linear-gradient(to top, rgba(0, 0, 0, .8) 0%, rgba(0, 0, 0, .34) 38%, rgba(0, 0, 0, 0) 74%);
    --sd-tile-fg: #fff;

    /* Tracks the brand lockup: name + gap + role (.4478em of it) + breathing
       room. Undersize this and the logo clips. */
    --sd-brand-size: clamp(38px, 3.56vw, 50px);
    --sd-nav-h: clamp(92px, 7.7vw, 116px);
    --sd-filter-h: 46px;
    --sd-chrome-h: calc(var(--sd-nav-h) + var(--sd-filter-h));

    /* Notched phones: with viewport-fit=cover the page runs under the status
       bar, which is what makes the grid full-bleed — but the fixed chrome has
       to be pushed clear of it or the logo is sliced off at the top. */
    --sd-safe-top: env(safe-area-inset-top, 0px);

    /* Hairline, not a gutter. The grid should read as one surface. */
    --sd-gap: 4px;

    --sd-ease: cubic-bezier(.22, .61, .36, 1);
}

:root[data-theme="light"] {
    color-scheme: light;

    --sd-bg: #ffffff;
    --sd-bg-raised: #f1f1f1;
    --sd-fg: #000000;
    --sd-muted: #000000;
    --sd-line: rgba(0, 0, 0, .14);

    --sd-header-bg: rgba(255, 255, 255, .8);

    /* In light mode the slider's surround is white and the peek neighbours read
       as pale rather than darkened, so chrome over them has to invert too. */
    --sd-chrome-fg: #000000;
    --sd-chrome-muted: #000000;
    --sd-chrome-shadow: 0 1px 14px rgba(255, 255, 255, .95), 0 0 5px rgba(255, 255, 255, .85);
    --sd-chrome-drop: drop-shadow(0 1px 10px rgba(255, 255, 255, .95)) drop-shadow(0 0 3px rgba(255, 255, 255, .85));
    --sd-chrome-scrim: linear-gradient(to bottom, rgba(255, 255, 255, .72) 0%, rgba(255, 255, 255, .34) 55%, rgba(255, 255, 255, 0) 100%);
    --sd-chrome-pill: rgba(255, 255, 255, .6);
    --sd-chrome-pill-hover: rgba(255, 255, 255, .9);

    /* Tile labels stay light-on-dark in both themes: they sit on the photograph
       itself, not on the page, and a photograph is not a background colour. */
}

/* --------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
}

body {
    margin: 0;
    background: var(--sd-bg);
    color: var(--sd-fg);
    font-family: 'Abel', ui-sans-serif, system-ui, 'Segoe UI', Roboto, Arial, sans-serif;
    font-size: 17px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overflow-x: hidden;
}

img,
video {
    max-width: 100%;
    height: auto;
    display: block;
}

a {
    color: inherit;
    text-decoration: none;
}

h1, h2, h3 {
    font-weight: 400;
    line-height: 1.12;
    margin: 0;
}

::selection {
    background: var(--sd-fg);
    color: var(--sd-bg);
}

:focus-visible {
    outline: 2px solid var(--sd-fg);
    outline-offset: 2px;
}

.sd-skip {
    position: absolute;
    left: -9999px;
}

.sd-skip:focus {
    left: 12px;
    top: 12px;
    z-index: 999;
    background: var(--sd-fg);
    color: var(--sd-bg);
    padding: 8px 14px;
}

/* --------------------------------------------------------------------------
   Header — fixed, translucent, gets out of the way as you scroll down
   -------------------------------------------------------------------------- */

.sd-header,
.sd-filter {
    position: fixed;
    left: 0;
    right: 0;
    z-index: 50;
    background: var(--sd-header-bg);
    backdrop-filter: blur(16px) saturate(140%);
    -webkit-backdrop-filter: blur(16px) saturate(140%);
    transform: translateY(var(--sd-chrome-shift, 0));
    transition: transform .34s var(--sd-ease);
}

/* The WP admin bar is position:fixed at the top for logged-in users, so the
   site's own fixed chrome has to start below it or it sits underneath. */
:root {
    --sd-admin-bar-h: 0px;
}

body.admin-bar {
    --sd-admin-bar-h: 32px;
}

@media screen and (max-width: 782px) {
    body.admin-bar {
        --sd-admin-bar-h: 46px;
    }
}

/* Below 600px WordPress switches the admin bar to position:absolute, so it
   scrolls away with the page. Fixed chrome offset by its height would then hang
   46px down from the top of the viewport with a gap above it. Only offset while
   the bar is actually fixed. Logged-in view only; visitors never see either. */
@media screen and (max-width: 600px) {
    body.admin-bar {
        --sd-admin-bar-h: 0px;
    }
}

.sd-header {
    top: var(--sd-admin-bar-h);
    height: calc(var(--sd-nav-h) + var(--sd-safe-top));
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: var(--sd-safe-top) clamp(14px, 2.4vw, 30px) 0;
    border-bottom: 1px solid var(--sd-line);
}

.sd-header-right {
    display: flex;
    align-items: center;
    gap: clamp(16px, 2.4vw, 30px);
    min-width: 0;
}

/* Stacked: logo, then the way back out beneath it. */
.sd-header-left {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 18px;
    min-width: 0;
}

/* The lockup: name on top, role beneath, both the same width.
 *
 * The width match is arithmetic, not justification. "FREELANCE RETOUCHER" is
 * two words, so text-align-last:justify dumped every spare pixel into the one
 * word space and left a canyon in the middle. Instead the role is sized so it
 * *naturally* spans the name's width, with only ordinary tracking.
 *
 * Measured in Abel: "SAM DEAN" at .16em tracking is 5.063x its font-size wide
 * (excluding the trailing letter-space); "FREELANCE RETOUCHER" is 9.407x its
 * own. Solving 9.407k + 19(0.1)k = 5.063 for a 0.1em tracked role gives
 * k = 0.4478. Both sizes hang off .sd-brand's font-size, so the whole lockup
 * scales as one piece and the match holds at every breakpoint.
 */
.sd-brand {
    display: inline-grid;
    justify-items: start;
    gap: 9px;
    white-space: nowrap;
    line-height: 1;
    font-size: var(--sd-brand-size);
}

.sd-brand-name {
    font-size: 1em;
    letter-spacing: .16em;
    text-transform: uppercase;
    /* letter-spacing adds a trailing gap after the final letter, which would
       make the grid column wider than the name looks and leave the role
       overhanging to the right. Pull it back. */
    margin-right: -.16em;
}

.sd-brand-role {
    font-size: .4478em;
    letter-spacing: .1em;
    margin-right: -.1em;
    text-transform: uppercase;
    color: var(--sd-muted);
}

/* --------------------------------------------------------------------------
   Social icons
   -------------------------------------------------------------------------- */

.sd-social {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 0;
    padding: 0 0 0 clamp(4px, 1.2vw, 14px);
    list-style: none;
    border-left: 1px solid var(--sd-line);
}

.sd-social a {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    color: var(--sd-fg);
    transition: opacity .2s var(--sd-ease);
}

.sd-social a:hover {
    opacity: .6;
}

/* --------------------------------------------------------------------------
   Light / dark toggle
   -------------------------------------------------------------------------- */

.sd-theme-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    background: none;
    border: 0;
    cursor: pointer;
    color: var(--sd-fg);
    transition: opacity .2s var(--sd-ease);
}

.sd-theme-toggle:hover {
    opacity: .6;
}

/* One icon each way: the sun means "go light", so it shows while dark. */
.sd-theme-toggle .sd-icon-moon {
    display: none;
}

:root[data-theme="light"] .sd-theme-toggle .sd-icon-sun {
    display: none;
}

:root[data-theme="light"] .sd-theme-toggle .sd-icon-moon {
    display: block;
}

/* --------------------------------------------------------------------------
   Back out of the project view
   -------------------------------------------------------------------------- */

.sd-back {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 14px 7px 11px;
    border: 1px solid var(--sd-line);
    border-radius: 999px;
    background: var(--sd-chrome-pill);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    font-size: 12px;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--sd-chrome-fg);
    text-shadow: var(--sd-chrome-shadow);
    white-space: nowrap;
    transition: background .2s var(--sd-ease), border-color .2s var(--sd-ease);
}

.sd-back:hover {
    background: var(--sd-chrome-pill-hover);
}

.sd-back svg {
    transition: transform .2s var(--sd-ease);
}

.sd-back:hover svg {
    transform: translateX(-2px);
}

.sd-nav-list {
    display: flex;
    align-items: center;
    gap: clamp(16px, 2.2vw, 32px);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sd-nav-list a {
    font-size: 16px;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--sd-fg);
    transition: opacity .2s var(--sd-ease);
}

.sd-nav-list a:hover {
    opacity: .6;
}

.sd-burger {
    display: none;
    width: 34px;
    height: 34px;
    padding: 0;
    background: none;
    border: 0;
    cursor: pointer;
    position: relative;
}

.sd-burger span {
    position: absolute;
    left: 6px;
    right: 6px;
    height: 1px;
    background: var(--sd-fg);
    transition: transform .28s var(--sd-ease), opacity .2s var(--sd-ease);
}

.sd-burger span:nth-child(1) { top: 13px; }
.sd-burger span:nth-child(2) { top: 20px; }

.sd-burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(3.5px) rotate(45deg); }
.sd-burger[aria-expanded="true"] span:nth-child(2) { transform: translateY(-3.5px) rotate(-45deg); }

/* --------------------------------------------------------------------------
   Category filter bar
   -------------------------------------------------------------------------- */

.sd-filter {
    top: calc(var(--sd-admin-bar-h) + var(--sd-nav-h) + var(--sd-safe-top));
    height: var(--sd-filter-h);
    border-bottom: 1px solid var(--sd-line);
    display: flex;
    align-items: center;
    overflow-x: auto;
    scrollbar-width: none;
}

.sd-filter::-webkit-scrollbar {
    display: none;
}

.sd-filter ul {
    display: flex;
    align-items: center;
    gap: clamp(18px, 2.6vw, 38px);
    margin: 0 auto;
    padding: 0 clamp(14px, 2.4vw, 30px);
    list-style: none;
    white-space: nowrap;
}

.sd-filter a {
    display: inline-block;
    font-size: 13px;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--sd-fg);
    padding: 4px 0;
    border-bottom: 1px solid transparent;
    transition: opacity .2s var(--sd-ease), border-color .2s var(--sd-ease);
}

.sd-filter a:hover {
    opacity: .6;
}

.sd-filter .is-current a {
    color: var(--sd-fg);
    border-bottom-color: var(--sd-fg);
}

/* --------------------------------------------------------------------------
   Main
   -------------------------------------------------------------------------- */

.sd-main {
    /* Clears the fixed chrome. The grid is full-bleed left-to-right; it does not
       also need to hide its first row behind the nav to prove the point. */
    padding-top: calc(var(--sd-chrome-h) + var(--sd-safe-top));
    min-height: 60vh;
}

body.sd-no-filter .sd-main {
    padding-top: calc(var(--sd-nav-h) + var(--sd-safe-top));
}

/* --------------------------------------------------------------------------
   The grid
   -------------------------------------------------------------------------- */

.sd-grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--sd-gap);
    padding: var(--sd-gap);
    background: var(--sd-bg);
}

.sd-tile {
    position: relative;
    display: block;
    aspect-ratio: 4 / 5;
    overflow: hidden;
    background: var(--sd-bg-raised);
}

.sd-tile-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .7s var(--sd-ease), opacity .4s var(--sd-ease);
}

.sd-tile::after {
    content: '';
    position: absolute;
    inset: 0;
    /* Deeper and taller than a caption scrim needs to be, because the label it
       has to carry is now large, centred and sitting further up the tile. */
    background: var(--sd-tile-scrim);
    opacity: 0;
    transition: opacity .35s var(--sd-ease);
}

/* Centred at the foot of the tile. Centring is what lets the title carry more
   weight without looking like a caption bolted to the corner — but it only
   works if the type stays inside the tile, hence the wrap and the padding. */
.sd-tile-meta {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 7px;
    padding: 20px clamp(12px, 1.4vw, 22px) 26px;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity .35s var(--sd-ease), transform .35s var(--sd-ease);
    /* Set explicitly, and NOT from --sd-fg. These labels sit on the photograph
       with a dark scrim behind them, so they stay white in both themes —
       inheriting the page's text colour turned them black in light mode, on top
       of a scrim that is still black. --sd-tile-fg has no light-mode override
       for exactly this reason. */
    color: var(--sd-tile-fg);
}

.sd-tile-title {
    font-size: clamp(19px, 1.75vw, 28px);
    letter-spacing: .07em;
    text-transform: uppercase;
    line-height: 1.18;
    text-wrap: balance;
    text-shadow: 0 1px 18px rgba(0, 0, 0, .55);
}

/* A hairline between title and category, sized to the text — it gives the pair
   a bit of structure now that they are centred rather than stacked on an edge. */
.sd-tile-cat {
    position: relative;
    padding-top: 9px;
    font-size: 11px;
    letter-spacing: .22em;
    text-transform: uppercase;
    color: var(--sd-tile-fg);
}

.sd-tile-cat::before {
    content: '';
    position: absolute;
    top: 0;
    left: 50%;
    width: 26px;
    height: 1px;
    background: var(--sd-tile-fg);
    transform: translateX(-50%);
}

@media (hover: hover) {
    .sd-tile:hover .sd-tile-img,
    .sd-tile:focus-visible .sd-tile-img {
        transform: scale(1.035);
    }

    .sd-tile:hover::after,
    .sd-tile:focus-visible::after,
    .sd-tile:hover .sd-tile-meta,
    .sd-tile:focus-visible .sd-tile-meta {
        opacity: 1;
    }

    .sd-tile:hover .sd-tile-meta,
    .sd-tile:focus-visible .sd-tile-meta {
        transform: none;
    }
}

/* Touch devices have no hover to reveal the title, so it is always shown. */
@media (hover: none) {
    .sd-tile::after,
    .sd-tile-meta {
        opacity: 1;
    }

    .sd-tile-meta {
        transform: none;
        padding: 16px 14px 20px;
    }
}

.sd-empty {
    padding: 22vh 24px;
    text-align: center;
    color: var(--sd-muted);
    letter-spacing: .1em;
    text-transform: uppercase;
    font-size: 13px;
}

@media (max-width: 1279px) {
    .sd-grid { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 899px) {
    .sd-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 599px) {
    .sd-grid { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   Project page
   -------------------------------------------------------------------------- */

.sd-project-fallback img {
    width: 100%;
    height: var(--sd-slider-h);
    object-fit: contain;
}

/* The slider fills what is left of the viewport once the fixed header, the
   admin bar and the thumbnail strip have taken their share — so a project opens
   as one full screen of image with its contact sheet visible underneath, no
   scrolling required. */
/* Declared on body, not :root — --sd-admin-bar-h is set by the .admin-bar class
   on body, and a custom property is resolved against the element that declares
   it, so computing this on :root would always read the 0px default.

   In the project view the slider takes the entire viewport: the header floats
   over it rather than sitting above it, and the thumbnail strip is overlaid on
   the bottom of the image instead of taking a band of its own. */
body {
    --sd-slider-h: calc(100dvh - var(--sd-admin-bar-h));
}

/* --------------------------------------------------------------------------
   Client strip
   -------------------------------------------------------------------------- */

.sd-clients {
    padding: clamp(46px, 7vw, 90px) clamp(18px, 4vw, 40px) clamp(40px, 6vw, 76px);
    border-top: 1px solid var(--sd-line);
    text-align: center;
}

.sd-clients-title {
    font-size: 10px;
    letter-spacing: .32em;
    text-transform: uppercase;
    opacity: .55;
    margin-bottom: clamp(24px, 3vw, 40px);
}

.sd-clients-list {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: baseline;
    gap: clamp(20px, 3.4vw, 56px);
    margin: 0 auto;
    padding: 0;
    max-width: 1180px;
    list-style: none;
}

.sd-clients-list li {
    font-size: clamp(17px, 1.7vw, 24px);
    letter-spacing: .13em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Project view — a full screen of image, chrome floating on top
   -------------------------------------------------------------------------- */

/* No bar, no blur, no rule. The header dissolves into the image; it stays
   readable because the brand and the nav sit at the far left and right, over
   the darkened peek neighbours rather than the active slide. The scrim is
   there for the occasional image that is bright right to its edges — it is
   invisible over the dark peek. */
.sd-project-view .sd-header {
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-bottom: 0;
    /* Auto height: the back control now sits under the logo, so this column is
       taller than the bar on grid pages and a fixed height would clip it. */
    height: auto;
    min-height: 0;
    align-items: flex-start;
    padding-top: calc(16px + var(--sd-safe-top));
    padding-bottom: 24px;
}

/* Inside a project the chrome gets out of the way of the work: the logo drops
   another quarter and the menu to two thirds. Nothing here competes with the
   image. */
body.sd-project-view {
    --sd-brand-size: clamp(28px, 2.68vw, 38px);
}

/* The left column is exactly as wide as the logo (measured: the name is 5.063x
   its font-size). Everything stacked under it — the project title and the way
   back — inherits that width, so the title can never run past the logo and the
   button lines up with both. */
.sd-project-view .sd-header-left {
    width: calc(5.12 * var(--sd-brand-size));
    gap: 22px;
}

.sd-project-title {
    margin: 0;
    font-size: calc(.62 * var(--sd-brand-size));
    font-weight: 400;
    line-height: 1.25;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--sd-chrome-fg);
    text-shadow: var(--sd-chrome-shadow);
    /* Long titles wrap down the column rather than shrinking or overlapping. */
    overflow-wrap: anywhere;
}

/* Client / year / services under the title. Label above value, because the
   column is only as wide as the logo and "Services: Retouching, CGI" on one line
   would wrap into a mess. */
.sd-project-meta {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.sd-project-meta div {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.sd-project-meta dt {
    font-size: 9px;
    letter-spacing: .26em;
    text-transform: uppercase;
    opacity: .62;
    color: var(--sd-chrome-fg);
    text-shadow: var(--sd-chrome-shadow);
}

.sd-project-meta dd {
    margin: 0;
    font-size: 12px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--sd-chrome-fg);
    text-shadow: var(--sd-chrome-shadow);
}

/* Full width of the column, matching the logo and the title above it. */
.sd-project-view .sd-back {
    width: 100%;
    justify-content: center;
}

.sd-project-view .sd-header-right {
    padding: 3px clamp(10px, 1.2vw, 16px);
    border: 1px solid var(--sd-line);
    border-radius: 999px;
    background: var(--sd-chrome-pill);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    gap: clamp(12px, 1.6vw, 22px);
}

.sd-project-view .sd-nav-list a {
    font-size: 11px;
}

.sd-project-view .sd-social a {
    width: 24px;
    height: 24px;
}

.sd-project-view .sd-social a svg {
    width: 15px;
    height: 15px;
}

.sd-project-view .sd-social {
    gap: 8px;
}

.sd-project-view .sd-back {
    font-size: 10px;
    padding: 6px 12px 6px 9px;
}

body.sd-project-view .sd-main {
    padding-top: 0;
}

/* The brand and the counter land on the darkened peek neighbours, but the nav
   is far enough in that on a wide landscape shot it sits over the active image
   — and against a bright one, muted grey disappears. In this view only, the nav
   goes near-white and everything picks up a shadow, so the chrome stays
   readable over any image without resorting to a solid bar. */
.sd-project-view .sd-brand-name,
.sd-project-view .sd-brand-role,
.sd-project-view .sd-nav-list a,
.sd-project-view .sd-social a,
.sd-project-view .sd-theme-toggle {
    text-shadow: var(--sd-chrome-shadow);
}

.sd-project-view .sd-brand-name,
.sd-project-view .sd-nav-list a:hover,
.sd-project-view .sd-social a:hover,
.sd-project-view .sd-theme-toggle:hover {
    color: var(--sd-chrome-fg);
}

.sd-project-view .sd-nav-list a,
.sd-project-view .sd-social a,
.sd-project-view .sd-brand-role,
.sd-project-view .sd-theme-toggle {
    color: var(--sd-chrome-muted);
}

/* The chrome must not slide away here — the header is the only way out of the
   view, so the auto-hide that helps while scrolling a grid would strand you. */
.sd-project-view .sd-header {
    transform: none;
}

.sd-project .bbs-slider {
    position: relative;
}

/* Thumbnails overlay the foot of the image rather than sitting under it, so the
   slider really is the full viewport. They fade with the rest of the controls
   when idle. */
/* The counter is the only navigation aid in this view — the thumbnail strip is
   not rendered at all here (bbs_render 'thumbs' => false), because a strip
   either steals a band from the image or covers part of it.

   It sits bottom-right, which with peek turned up lands it over the darkened
   next image rather than over the one being viewed. No pill, no box: plain
   letterspaced type on an already-dark neighbour, with a shadow for the case
   where that neighbour happens to be a light image. */
/* The counter does not fade with the rest of the controls. It is the only thing
   telling you where you are in the set now the thumbnail strip has gone, and a
   position indicator that disappears after two seconds of looking at a picture
   is not a position indicator. It is small, and it sits on the darkened peek,
   so it costs the image nothing. */
.sd-project-view .bbs-idle-hide.is-idle .bbs-counter {
    opacity: 1;
}

.sd-project-view .bbs-counter {
    right: clamp(14px, 2.4vw, 30px);
    bottom: clamp(16px, 2.6vh, 30px);
    padding: 0;
    background: none;
    border: 0;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    font-size: 13px;
    letter-spacing: .24em;
    color: var(--sd-chrome-fg);
    text-shadow: var(--sd-chrome-shadow);
}

/* Bad Boy Slider, dressed for this theme.
   The plugin ships deliberately neutral dark chrome so it works anywhere; these
   overrides live here rather than in the plugin, which is shared with other
   sites. */

.sd-project .bbs-stage {
    background: var(--sd-bg);
}

/* The reactive cursor is drawn on the photograph, so it follows the chrome
   colours rather than the page ones — a white arrow is invisible on a pale
   image in light mode. */
.sd-project .bbs-cursor {
    color: var(--sd-chrome-fg);
}

.sd-project .bbs-cursor svg {
    filter: var(--sd-chrome-drop);
}

.sd-project .bbs-arrow {
    background: var(--sd-chrome-pill);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid var(--sd-line);
    border-radius: 0;
    color: var(--sd-chrome-fg);
}

.sd-project .bbs-arrow:hover {
    background: var(--sd-chrome-pill-hover);
}

.sd-project .bbs-counter {
    font-family: 'Abel', sans-serif;
    letter-spacing: .14em;
    font-size: 12px;
    padding: 6px 11px;
}

/* --------------------------------------------------------------------------
   Prose pages — About, Contact, Thank you
   -------------------------------------------------------------------------- */

.sd-prose {
    max-width: 860px;
    margin: 0 auto;
    padding: clamp(46px, 8vw, 104px) clamp(18px, 4vw, 40px) clamp(60px, 10vw, 120px);
}

.sd-prose-center {
    text-align: center;
}

.sd-page-title {
    font-size: clamp(32px, 5vw, 62px);
    letter-spacing: .04em;
    text-transform: uppercase;
    margin-bottom: .6em;
}

.sd-prose p {
    margin: 0 0 1.25em;
    color: var(--sd-fg);
    font-size: 18px;
}

.sd-prose strong {
    color: var(--sd-fg);
    font-weight: 400;
    border-bottom: 1px solid var(--sd-line);
}

.sd-prose h2 {
    font-size: clamp(22px, 2.6vw, 32px);
    letter-spacing: .06em;
    text-transform: uppercase;
    margin: 2em 0 .7em;
}

.sd-prose p img {
    margin: 2em 0;
}

.sd-link,
.sd-prose a {
    border-bottom: 1px solid var(--sd-muted);
    transition: border-color .2s var(--sd-ease);
}

.sd-link:hover,
.sd-prose a:hover {
    border-bottom-color: var(--sd-fg);
}

/* --------------------------------------------------------------------------
   About
   -------------------------------------------------------------------------- */

.sd-prose .sd-lede {
    font-size: clamp(21px, 2.4vw, 28px);
    color: var(--sd-fg);
    letter-spacing: .02em;
    line-height: 1.4;
    margin-bottom: 1.4em;
}

.sd-about {
    display: grid;
    grid-template-columns: 1.55fr 1fr;
    gap: clamp(30px, 5vw, 70px);
    align-items: start;
}

.sd-about-portrait {
    margin: 0;
}

.sd-about-portrait img {
    width: 100%;
    height: auto;
}

.sd-prose .sd-about-cta {
    margin-top: 2.4em;
    font-size: 13px;
    letter-spacing: .2em;
    text-transform: uppercase;
}

@media (max-width: 767px) {
    .sd-about {
        grid-template-columns: 1fr;
    }

    /* Portrait first on a phone: it is the introduction. */
    .sd-about-portrait {
        order: -1;
    }
}

/* --------------------------------------------------------------------------
   Contact — Bad Boy Forms, restyled for a dark page
   -------------------------------------------------------------------------- */

.sd-prose .sd-contact-direct {
    margin-top: 3em;
    font-size: 15px;
    color: var(--sd-muted);
    line-height: 2;
}

/* Bad Boy Forms ships its own light-theme stylesheet and enqueues it after the
   theme's, so these are scoped under .sd-contact to win on specificity rather
   than depending on load order. Class names are the plugin's: .field-row lays
   out the two-up rows, .field wraps each control, .btn is the submit. */

.sd-contact .bbf-form {
    margin: 2.6em 0 0;
    background: none;
    border: 0;
    box-shadow: none;
    padding: 0;
}

.sd-contact .field {
    margin-bottom: 20px;
}

.sd-contact .bbf-form label {
    display: block;
    margin-bottom: 7px;
    font-size: 11px;
    letter-spacing: .2em;
    text-transform: uppercase;
    color: var(--sd-muted);
}

.sd-contact .bbf-form input[type="text"],
.sd-contact .bbf-form input[type="email"],
.sd-contact .bbf-form input[type="tel"],
.sd-contact .bbf-form input[type="number"],
.sd-contact .bbf-form input[type="date"],
.sd-contact .bbf-form select,
.sd-contact .bbf-form textarea {
    width: 100%;
    padding: 13px 14px;
    background: var(--sd-bg-raised);
    border: 1px solid var(--sd-line);
    border-radius: 0;
    color: var(--sd-fg);
    font-family: inherit;
    font-size: 16px;
    box-shadow: none;
    transition: border-color .2s var(--sd-ease), background .2s var(--sd-ease);
}

.sd-contact .bbf-form textarea {
    resize: vertical;
    min-height: 170px;
}

.sd-contact .bbf-form input:focus,
.sd-contact .bbf-form select:focus,
.sd-contact .bbf-form textarea:focus {
    outline: none;
    border-color: var(--sd-fg);
    background: var(--sd-bg-raised);
}

.sd-contact .bbf-form input::placeholder,
.sd-contact .bbf-form textarea::placeholder {
    color: var(--sd-muted);
}

/* Native dropdowns render with the OS palette; without this the options list is
   black text on a black menu. */
.sd-contact .bbf-form select {
    color-scheme: dark;
}

.sd-contact .bbf-form .btn,
.sd-contact .bbf-form button[type="submit"] {
    appearance: none;
    background: var(--sd-fg);
    color: var(--sd-bg);
    border: 1px solid var(--sd-fg);
    border-radius: 0;
    padding: 14px 34px;
    font-family: inherit;
    font-size: 13px;
    letter-spacing: .2em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background .2s var(--sd-ease), color .2s var(--sd-ease);
}

.sd-contact .bbf-form .btn:hover,
.sd-contact .bbf-form button[type="submit"]:hover {
    background: transparent;
    color: var(--sd-fg);
}

/* The consent row is a checkbox beside a sentence, not a titled field. */
.sd-contact .bbf-form label.consent {
    display: flex;
    gap: 11px;
    align-items: flex-start;
    font-size: 14px;
    letter-spacing: 0;
    text-transform: none;
    line-height: 1.5;
    color: var(--sd-muted);
}

.sd-contact .bbf-form label.consent input[type="checkbox"] {
    width: auto;
    margin: 3px 0 0;
    accent-color: var(--sd-fg);
    flex: 0 0 auto;
}

.sd-contact .bbf-form .req,
.sd-contact .bbf-form .required {
    color: var(--sd-muted);
}

.sd-contact .bbf-form .note {
    border-radius: 0;
    font-size: 14px;
}

.sd-contact .bbf-form .bbf-error,
.sd-contact .bbf-form .note.bbf-error {
    color: #ff8a8a;
    border-color: rgba(255, 138, 138, .4);
    background: rgba(255, 138, 138, .07);
}

.sd-contact .bbf-form .note.bbf-ok {
    color: var(--sd-fg);
    border: 1px solid var(--sd-line);
    background: var(--sd-bg-raised);
    padding: 22px;
}

@media (min-width: 600px) {
    .sd-contact .field-row {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 0 22px;
    }
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.sd-footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 26px clamp(14px, 2.4vw, 30px);
    border-top: 1px solid var(--sd-line);
    font-size: 12px;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--sd-muted);
}

.sd-footer p {
    margin: 0;
}

.sd-footer-credit {
    color: var(--sd-muted);
}

.sd-footer a {
    transition: opacity .2s var(--sd-ease);
}

.sd-footer a:hover {
    opacity: .6;
}

/* --------------------------------------------------------------------------
   Mobile nav
   -------------------------------------------------------------------------- */

@media (max-width: 767px) {
    .sd-burger {
        display: block;
    }

    /* The burger is the middle child of the header, which on a phone would put
       it between the brand and the social icons. Push the brand out to the left
       and let the icons and the burger sit together on the right. */
    .sd-header {
        justify-content: flex-start;
    }

    .sd-header-left {
        margin-right: auto;
        min-width: 0;
    }

    .sd-header-right {
        order: 2;
        gap: 6px;
    }

    .sd-burger {
        order: 3;
        margin-left: 8px;
    }

    .sd-social {
        gap: 2px;
        padding-left: 0;
        border-left: 0;
    }

    /* The doubled logo leaves little room beside it on a phone. */
    .sd-social a {
        width: 28px;
        height: 28px;
    }

    .sd-back {
        padding: 6px 11px 6px 9px;
        font-size: 10px;
        letter-spacing: .12em;
    }

    .sd-nav {
        position: fixed;
        /* Below the admin bar as well as the header, or the panel opens
           underneath its own header for logged-in users. */
        inset: calc(var(--sd-admin-bar-h) + var(--sd-nav-h)) 0 auto;
        background: rgba(11, 11, 11, .96);
        backdrop-filter: blur(20px);
        -webkit-backdrop-filter: blur(20px);
        border-bottom: 1px solid var(--sd-line);
        transform: translateY(-130%);
        transition: transform .34s var(--sd-ease);
    }

    .sd-nav.is-open {
        transform: none;
    }

    .sd-nav-list {
        flex-direction: column;
        align-items: flex-start;
        gap: 0;
        padding: 8px 20px 18px;
    }

    .sd-nav-list li {
        width: 100%;
    }

    .sd-nav-list a {
        display: block;
        padding: 15px 0;
        font-size: 19px;
    }
}

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
        transition-duration: .01ms !important;
        animation-duration: .01ms !important;
    }
}
