/* ============================================================
   CONTACT SECTION
   Companion stylesheet for template-parts/contact-section.php.
   Enqueued by rjb_enqueue_contact_section() in functions.php —
   any template that includes the part gets this with it.

   Design tokens come from the theme's style.css :root; nothing
   here defines one. --contact-* are genuinely local card
   geometry, scoped to .contact-content (PROJECT.md §5).

   Breakpoints copied verbatim from the reference block at the
   top of the plugin's assets/base-sections.css. The compound
   max-height clauses are load-bearing for landscape phones and
   short tablets — do not simplify them.
   ============================================================ */

/* Contact Section */
.contact-section {
    min-height: auto;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    background: transparent !important; /* Override white background from .content-section */
    margin-bottom: 0;
    /* Matched top and bottom. The figure is the fixed footer's
       height plus 80px of air, which the bottom has to clear anyway. */
    padding: calc(2vw + 40px + 80px) 0;
}

/* Contact section gradient - mirrors About section but reversed */
.contact-section::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0; /* Full viewport width since section is outside main wrapper */
    right: 0; /* Full viewport width since section is outside main wrapper */
    bottom: calc(-2vw - 40px); /* Extend by footer height: 1vw top + 40px logo + 1vw bottom */
    background: linear-gradient(to bottom, var(--main-content-bg) 0%, var(--main-content-bg) 40%, #39e58f 100%);
    z-index: -1;
}

/* ============================================================
   CONTACT CARDS
   Two cards wearing the photography page's card treatment: the
   same 1px --text-color hairline, the same --main-content-bg
   face, and the same 0 8px 25px lift as .wc-stage. None of the
   watercolor machinery comes with them — the only motion here is
   the hover tilt.

   Both cards are the SAME portrait box at every breakpoint: one
   width, one aspect ratio, declared once on the wrapper. That
   fixed height is what lets the links grid sit on the bottom edge
   of the info card rather than wherever its copy happens to end.

   The photograph is the back card, rotated -7deg. The info card
   sits square on top and is pulled left over the photograph's
   edge by its own negative margin, so the underlap is one number
   rather than absolute positioning re-guessed per breakpoint.
   ============================================================ */
.contact-content {
    /* Card geometry, local to this pair. The ratio is the
       headshot's own 768x1024, so the info card is cut from the
       same block as the photograph. --contact-pad drives both the
       info card's padding and the logo's inset, so a breakpoint
       changes one number and the two stay in register. */
    --contact-card-w: 33%;
    --contact-card-ratio: 768 / 1024;
    --contact-pad: 1.5vw;
    /* Which card is in front at rest: 0 = the photograph,
       1 = the contact card. A breakpoint flips the whole pile by
       setting this one value — the cut inverts whatever it says,
       and the z-index rules below read the result, so nothing has
       to be restated per breakpoint or fought on specificity. */
    --contact-rest: 0;
    --contact-front: var(--contact-rest);

    /* How far the two cards overlap. The info card's copy runs
       into that strip on purpose: some of what's underneath has
       to be covered for the pile to read as a pile, and for the
       cut to be worth making. */
    --contact-overlap: 4%;

    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 2vw;
    box-sizing: border-box;
}

.contact-image,
.contact-info {
    box-sizing: border-box;
    flex: 0 1 var(--contact-card-w);
    aspect-ratio: var(--contact-card-ratio);
    /* Local to the card pair: light mode casts a black shadow,
       dark mode lifts with a white one. One custom property so
       the hover state doesn't have to restate both. */
    --contact-shadow-rgb: 0, 0, 0;
    background: var(--main-content-bg);
    border: 1px solid var(--text-color);
    box-shadow: 0 8px 25px rgba(var(--contact-shadow-rgb), 0.2);
    transition: transform 0.35s ease, box-shadow 0.35s ease;
}

/* Matching .wc-stage on the photography page: a black shadow is
   invisible on a near-black ground, so it flips to white. */
@media (prefers-color-scheme: dark) {
    .contact-image,
    .contact-info {
        --contact-shadow-rgb: 255, 255, 255;
    }
}

/* The photograph, tilted. In front at rest on desktop; see
   --contact-rest for which card that actually is. */
.contact-image {
    position: relative;
    z-index: calc(1 - var(--contact-front));
    margin: 0;
    padding: 0;
    overflow: hidden;
    transform: rotate(-7deg);
    cursor: crosshair;
}

.contact-image img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* The contact card, square to the page. Its own negative margin
   is what creates the overlap, whichever card is on top. Its copy
   is deliberately NOT inset to clear that strip — part of it being
   obscured is the point. */
.contact-info {
    position: relative;
    z-index: var(--contact-front);
    margin-left: calc(-1 * var(--contact-overlap));
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: var(--contact-pad);
    cursor: crosshair;
}

/* Hovering either card moves both — the pair is one object, and
   having only the card under the cursor react left the other
   looking inert. Read on the wrapper so the motion survives the
   cursor crossing between them. Each card leans away from the
   overlap: the photograph deepens its own angle, the info card
   takes the opposite one, so the pair opens.

   Gated on an actual pointing device. On touch, :hover latches on
   tap and there is nothing to un-latch it — the card would simply
   stay in the hover pose. Gating here rather than overriding in
   the mobile block means the resting angle is stated once and the
   breakpoints don't have to restate it to undo this. */
@media (hover: hover) {
    .contact-content:hover .contact-image {
        transform: rotate(-9.5deg) translate(-10px, -10px);
        box-shadow: 0 16px 38px rgba(var(--contact-shadow-rgb), 0.28);
    }

    .contact-content:hover .contact-info {
        transform: rotate(1.5deg) translate(10px, -10px);
        box-shadow: 0 16px 38px rgba(var(--contact-shadow-rgb), 0.28);
    }
}

/* THE SHUFFLE. Clicking either card sends the pair apart, swaps
   which one is in front, and lets them fall back together — a
   deck being cut. Only the z-order actually changes; the travel
   exists so the swap happens while the two are clear of each
   other and never reads as a card blinking through another.

   The apart pose has to beat the hover pose, and both are
   (0,2,1), so these rules sit after it deliberately — during a
   shuffle the cursor is by definition over a card, so hover is
   live the whole time.

   .contact-cards-swapped is the resting state after an odd number
   of clicks; .contact-shuffling is the transient apart pose. JS
   toggles the first at the apex, while they're separated. */
.contact-content.contact-cards-swapped {
    --contact-front: calc(1 - var(--contact-rest));
}

.contact-content.contact-shuffling .contact-image {
    transform: rotate(-13deg) translate(-22%, -7%);
}

.contact-content.contact-shuffling .contact-info {
    transform: rotate(5deg) translate(22%, 7%);
}

/* The cut's own timing, on a class of its own rather than on
   .contact-shuffling because the return leg happens after that
   one comes off — scoping it to the apart pose alone would have
   sent the cards out at one speed and brought them back at
   another. The JS holds this class for the whole cut and reads
   the duration from it, so this stays the only place the timing
   is written down.

   This is PER LEG, and there are two, so the figure below is half
   the total: 0.3s out, 0.3s back, 0.6s end to end.

   The curve is near-linear rather than the resting `ease`, which
   front-loads its travel and coasts into the end — over two legs
   meeting at a hard apex that read as a snap out and a drift
   back. This one is essentially the diagonal, with just enough
   softening at each end to round off the direction change at the
   apex without reintroducing the snap. Hover keeps `ease`; that
   one IS a settle. */
.contact-content.contact-cutting .contact-image,
.contact-content.contact-cutting .contact-info {
    transition-duration: 0.3s;
    transition-timing-function: cubic-bezier(0.45, 0.35, 0.55, 0.65);
}

/* Reduced motion: the cards still swap, they just don't travel to
   do it. The JS timing is unchanged — there is simply nothing to
   watch between the click and the new order. */
@media (prefers-reduced-motion: reduce) {
    .contact-image,
    .contact-info {
        transition: none;
    }

    .contact-content.contact-shuffling .contact-image,
    .contact-content.contact-shuffling .contact-info {
        transform: none;
    }
}

/* PP Right Serif and Legitima take literal sizes. The --fs-* scale
   is derived from Innovator Grotesk's metrics and is for sans type
   only — it reads wrong on the serif and display faces. */
.contact-card-name {
    font-family: var(--compressed-font) !important;
    font-size: 108px !important;
    /* A real face, not a synthesized bold: style.css maps PP Right
       Serif 600 to Tall Regular and 400 to Tall Fine. */
    font-weight: 600 !important;
    line-height: 0.8 !important;
    color: var(--text-color);
    margin: 0 !important;
}

.contact-card-role {
    font-family: var(--serif-font) !important;
    font-size: 1.5rem !important;
    font-weight: 400 !important;
    font-style: italic !important;
    line-height: 1 !important;
    color: var(--text-color-muted);
    margin: 0.75rem 0 0 0 !important;
}

/* A single column of four. margin-top: auto pins it to the bottom
   of the card rather than to the end of the copy above it. */
.contact-links-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.5rem;
    width: 100%;
    margin-top: auto;
}

/* The two wrappers are scaffolding left from the 2x2 layout.
   display: contents drops them out of the box tree so all four
   items are direct grid children and share one gap — nested
   wrappers would have put a different rhythm between Signal and
   Instagram than between the rest. */
.contact-column {
    display: contents;
}

.contact-item {
    display: flex;
    flex-direction: column;
    gap: 0;
}

/* Innovator Grotesk, so the token scale applies here. */
.contact-item p {
    font-family: var(--primary-font) !important;
    font-weight: 400 !important;
    font-size: var(--fs-base) !important;
    line-height: 1.4 !important;
    margin: 0 !important;
}

p.contact-headline {
    font-weight: 600 !important;
}

.contact-item a {
    color: var(--text-color) !important;
    text-decoration: none;
    transition: color 0.3s ease;
}

.contact-item a:hover {
    color: var(--link-hover-color) !important;
}

/* style.css gives every `p a` an absolutely positioned ::after —
   an 8px highlighter swipe that grows to width: 100% on hover.
   `p a` is never itself positioned, so that pseudo-element takes
   its containing block from the nearest positioned ancestor,
   which in here is the card: left: 0 / bottom: 0 / width: 100%
   resolved to a green bar across the bottom of .contact-info
   rather than an underline beneath the link. Its --highlight-color
   is the same #39e58f as the section gradient, which is why it
   read as the page showing through.

   The card's hover affordance is the colour change, and a green
   swipe under green hover text would be unreadable anyway, so the
   pseudo-element is removed outright here. */
.contact-item a::after {
    content: none;
}

/* Out of flow, so it shares the bottom line with the links grid
   instead of stacking under it — they're allowed to overlap.
   Inset tracks the card's own padding through --contact-pad.

   The source PNG is 490x567, not square, so only the height is
   set and the width follows: the footer's width=40 height=40
   squashes the mark, and this doesn't inherit that. Same
   invert(1) the footer logo gets — the file is the black mark. */
.contact-card-logo {
    position: absolute;
    right: var(--contact-pad);
    bottom: var(--contact-pad);
    display: block;
    height: 28px;
    width: auto;
}

@media (prefers-color-scheme: dark) {
    .contact-card-logo {
        filter: invert(1);
    }
}

/* Tablet Responsive */
@media (max-width: 1200px) {
    .contact-content {
        --contact-card-w: 39%;
        --contact-pad: 2.5vw;
        padding: 0 4vw;
    }

    .contact-card-name {
        font-size: 84px !important;
    }

    .contact-card-role {
        font-size: 1.25rem !important;
    }

    /* A notch back down from the desktop --fs-base: the card is
       narrower here and the email address is its widest line. */
    .contact-item p {
        font-size: var(--fs-sm) !important;
    }

    .contact-links-grid {
        gap: 1.25rem;
    }
}

/* General Mobile Responsive - See breakpoint reference in plugin base-sections.css */
@media (max-width: 768px), ((max-width: 1200px) and (max-height: 768px)), (max-width: 480px) {
    .contact-section {
        min-height: auto;
        padding: calc(2vw + 35px + 80px) 0; /* Matched, on the shorter mobile footer */
    }

    /* Contact section gradient mobile - constrain to viewport */
    .contact-section::before {
        left: 0;
        right: 0;
        bottom: calc(-2vw - 35px); /* Mobile footer height: 1vw top + logo + contact pill + 1vw bottom */
    }

    /* Contact cards on mobile: one pile rather than a row. The
       two sit almost on top of each other, offset just enough
       that the card underneath shows below the top one — which
       is the whole affordance, since there is no hover here to
       suggest the pair does anything. Tapping cuts the deck the
       same way a click does on desktop.

       The stack offset is vertical, and percentage margins
       resolve against the containing block's WIDTH, not its
       height — so the pull-up is written in terms of the card's
       own width and its aspect ratio (height = width * 4/3)
       rather than as a percentage of height, which would silently
       mean something else. */
    .contact-content {
        --contact-pad: 4vw;
        /* The contact card greets you here and the photograph is
           what a tap turns up — the reverse of desktop. */
        --contact-rest: 1;
        /* Side-by-side overlap is meaningless in a pile. */
        --contact-overlap: 0%;
        /* One number for the card size, so the offset below can
           be derived from it instead of guessed alongside it.

           The tilt sets the footprint, not the card box: a -7deg
           rotation of a w by 4w/3 card sweeps a bounding width of
           w*cos7 + (4w/3)*sin7 = 1.155w. The budget is written as
           the division rather than its answer so the constraint
           stays legible — change 92vw or the tilt and the card
           follows. */
        --contact-card-w-mobile: min(calc(92vw / 1.155), 340px);

        flex-direction: column;
        align-items: center;
        /* The pull-up does the spacing; a gap would fight it. */
        gap: 0;
        width: 100%;
        max-width: 100%;
        padding: 0 4vw;
        /* Drops the 300ms tap delay on the pile, so a cut starts
           when the finger lifts. */
        touch-action: manipulation;
    }

    .contact-image,
    .contact-info {
        flex: 0 1 auto;
        width: var(--contact-card-w-mobile);
        max-width: none;
        /* Both cards are one box. The pile is a column flex
           container, so height is the MAIN axis here and each
           item's automatic minimum size is its content — which
           let the info card grow past its aspect-ratio height
           whenever the copy ran long, leaving the two visibly
           different sizes. min-height: 0 hands the height back to
           the ratio, so they match. (On desktop the row axis is
           horizontal and this never applied.) */
        min-height: 0;
    }

    /* Second in the DOM, so this is the one that climbs under the
       photograph. Pulled back by exactly one card height, which
       puts the two concentric — same centre, same box. What shows
       of the card underneath is purely what the photograph's
       -7deg tilt fails to cover: a wedge at each corner, the way
       a squared-up card under a crooked one reads as a pile. */
    .contact-info {
        margin-top: calc(-1 * var(--contact-card-w-mobile) * 4 / 3);
    }

    /* The cut, fanned rather than pulled fully apart — at this
       overlap nothing short of a leap would clear, and a fan is
       what cutting a real deck looks like anyway. The z-swap
       still lands at the apex, with the two at their furthest. */
    .contact-content.contact-shuffling .contact-image {
        transform: translate(-15%, -9%) rotate(-17deg);
    }

    .contact-content.contact-shuffling .contact-info {
        transform: translate(15%, 9%) rotate(9deg);
    }

    .contact-card-name {
        font-size: 72px !important;
    }

    .contact-card-role {
        font-size: 1rem !important;
    }

    .contact-links-grid {
        gap: 1rem;
    }
}
