/**
 * Block content styles for this site
 *
 * The parent registers this file for both the front end and the block editor
 * canvas, so a rule written here applies identically in each.
 *
 * Site chrome — header, footer, navigation, login — stays in style.css, which
 * the canvas does not load.
 *
 * The filename must stay site-blocks.css: the parent's own block rules live in
 * its assets/css/blocks.css, and a file of that name here would replace the
 * parent's copy in the editor rather than adding to it.
 *
 * @package Quantcore
 */

/* ==========================================================================
   Buttons

   The fill button is the default and is defined in theme.json
   (styles.elements.button). It is not in the Figma file: white ground, black
   label, accent blue on hover, chosen to sit as the solid counterpart of the
   outline button.

   The outline button is the design's own button — transparent, hairline
   white border, 5px radius. Core styles its outline variation with
   .wp-block-button.is-style-outline > .wp-block-button__link:not(.has-background),
   which outranks anything theme.json emits, so the design has to be restated
   at that same specificity. The parent already does this for padding; border,
   background and colour need the same treatment.

   :not(.has-background) is deliberate — it lets an editor's own background
   colour take over, which is how core's variation behaves.
   ========================================================================== */

.wp-block-button.is-style-outline > .wp-block-button__link:not(.has-background),
.wp-block-button .wp-block-button__link.is-style-outline:not(.has-background) {
    background-color: transparent;
    border: 1px solid var(--wp--preset--color--white);
    color: var(--wp--preset--color--white);
}

/* Hover and focus fill the outline in with white. Accent blue is reserved for
   the fill button, so the two stay distinguishable in both states rather than
   converging on the same colour. Focus is styled alongside hover rather than
   left to the browser default, which is invisible against black. */
.wp-block-button.is-style-outline > .wp-block-button__link:not(.has-background):hover,
.wp-block-button.is-style-outline > .wp-block-button__link:not(.has-background):focus,
.wp-block-button .wp-block-button__link.is-style-outline:not(.has-background):hover,
.wp-block-button .wp-block-button__link.is-style-outline:not(.has-background):focus {
    background-color: var(--wp--preset--color--white);
    border-color: var(--wp--preset--color--white);
    color: var(--wp--preset--color--black);
}

/* Every button in the design carries a trailing arrow, so it belongs to the
   button itself rather than to the text an editor types.

   Drawn as a mask rather than an <img> so the arrow takes its colour from
   currentColor: white on the outline button, black on the fill, and inverting
   with them on hover without a second rule. The exported SVG has stroke="white"
   baked in, which a mask ignores — only its alpha is read.

   The link becomes inline-flex to get the design's 10px gap and vertical
   centring; justify-content keeps the label centred on buttons given a set
   width, which core otherwise handles with text-align.
   ========================================================================== */

.wp-block-button__link {
    align-items: center;
    display: inline-flex;
    gap: 10px;
    justify-content: center;
}

.wp-block-button__link::after {
    background-color: currentColor;
    content: "";
    flex: none;
    height: 10.71px;
    /* Relative to this stylesheet, not the theme root: a url() in CSS resolves
       against the file it is written in. */
    mask: url("../images/arrow-right.svg") no-repeat center / contain;
    width: 12.21px;
    -webkit-mask: url("../images/arrow-right.svg") no-repeat center / contain;
}


/* ==========================================================================
   Full-height Covers

   Two rules, and neither needs a class. An editor adds a Cover block and sets
   its minimum height to 100vh; everything below follows from that.

   The height itself is deliberately not set here. It belongs in the editor,
   where it can be seen and changed, and where the block shows its real height
   on the canvas rather than a stub.

   The selector matches the inline style WordPress writes for that setting
   (`min-height:100vh`), which is how CSS can react to a block's own value.
   The i flag guards against a stray 100VH. A Cover set to 90vh or 900px is
   left alone, which is the point: only a full-viewport Cover is affected.
   ========================================================================== */

/* Any Cover asked for a full viewport gets the small-viewport unit too. svh
   is the viewport with the mobile browser's toolbar showing, so the block
   does not resize as the address bar collapses on scroll. !important because
   the block's own height arrives as an inline style, which no selector beats.

   Anywhere on the page, not only at the top: whatever the block is doing, if
   it asks for a screenful it should mean the screen the reader actually has. */
.wp-block-cover[style*="min-height:100vh" i] {
    min-height: 100svh !important;
}

/* A Cover opening a page is a hero: the navigation sits over it rather than
   above it, as the design has it. Any height: most pages open on a full
   viewport, the News page on something shorter, and the header belongs over
   both.

   The header stays sticky and is not taken out of the flow, so it still
   behaves normally once the page scrolls. Instead the hero is lifted by the
   header's height to sit underneath it. For a full-height hero the lift puts
   the top edge at y=0, so anything more overshoots the fold.

   :first-child holds because the page template prints no title when the
   content carries its own h1, which a hero always does. */
.entry-content > .wp-block-cover:first-child {
    margin-top: calc(-1 * var(--hero-header-offset));
    /* clip rather than hidden: hidden would make the hero a scroll container,
       which breaks position: sticky in anything it contains. */
    overflow-x: clip;
    /* The background runs behind the navigation, but the content must not. */
    padding-top: var(--hero-header-offset);
    position: relative;
}

/* The page's top padding would reopen the gap the lift just closed. :has()
   because the padding sits on an ancestor of the Cover, and a selector cannot
   otherwise reach upwards. */
.site-main:has(> article > .entry-content > .wp-block-cover:first-child) {
    padding-top: 0;
}


/* ==========================================================================
   Utility: bleed-right

   Runs an element past the right edge of its container, where it is clipped
   by the page rather than stopping short of it.

   Only between the width at which columns sit side by side and the width at
   which a wide container stops touching the page edge. Wider than that the
   container has margins of its own, and an element bleeding past it would be
   cut off mid-page rather than at the edge, which reads as a mistake.
   Narrower, columns are stacked and there is nothing to bleed out of.

   transform rather than a margin: it moves the element without changing the
   space it occupies, so the column keeps its width and nothing reflows.
   ========================================================================== */

@media (min-width: 783px) and (max-width: 1399px) {
    .bleed-right {
        transform: translateX(12%);
    }
}


/* ==========================================================================
   Utility: card-hover

   Lifts a card and brings its border up to the accent colour on hover. The
   block editor has no hover state to set, so this is the one part of the
   card that cannot come from block settings.

   :focus-within as well as :hover, so the state appears for someone moving
   through the page by keyboard once a card contains a link. Without a link
   inside, the card is not focusable and only the pointer sees it.

   The lift is suppressed under prefers-reduced-motion. The colour change
   stays: it carries the meaning, and a colour change is not motion.
   ========================================================================== */

.card-hover {
    transition: background-color 200ms ease, border-color 200ms ease,
        transform 200ms ease;
}

.card-hover:hover,
.card-hover:focus-within {
    /* The card's resting border colour is set in the editor, which writes it
       as an inline style on the element. An inline style outranks every
       selector, so the hover colour cannot win without !important — the
       alternative is taking the resting colour out of the editor, where it
       belongs. Only the colour needs it; the lift is not set inline. */
    border-color: var(--wp--preset--color--cyan) !important;
    transform: translateY(-10px);
}

/* A card that rests on the page's own black takes the mid-grey of the raised
   cards on hover, so it lifts out of the page rather than only off it. Only
   the cards whose resting ground is black want this, so it is a second class
   an editor adds rather than part of card-hover — and it needs !important for
   the same reason the border does. */
.card-hover-fill:hover,
.card-hover-fill:focus-within {
    background-color: var(--wp--preset--color--mid-grey) !important;
}

@media (prefers-reduced-motion: reduce) {
    .card-hover {
        transition: background-color 200ms ease, border-color 200ms ease;
    }

    .card-hover:hover,
    .card-hover:focus-within {
        transform: none;
    }
}


/* ==========================================================================
   Reduced motion

   A background video plays on its own and loops, which is exactly what someone
   who has asked their system to reduce motion is asking not to see. CSS cannot
   pause a video and the preference cannot be read on the server, so the swap is
   between two things already in the page: the video is hidden and the still
   underneath it — the video's own poster frame, put there by
   quantcore_cover_video() — is shown in its place.

   The still is the frame the video opens on, so the hero looks composed rather
   than broken. It sits above the Cover's overlay and below its content, where
   the video was.
   ========================================================================== */

.quantcore-cover-still {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    .wp-block-cover__video-background {
        display: none;
    }

    .quantcore-cover-still {
        background-position: center;
        background-repeat: no-repeat;
        background-size: cover;
        display: block;
        inset: 0;
        position: absolute;
        z-index: 0;
    }
}


/* ==========================================================================
   Video play button

   A video with controls shows a bar along its bottom edge, which is easy to
   miss on a large still. This puts a play mark over the middle of one that is
   not playing, and takes it away once it is.

   The mark ignores the pointer. The video keeps its own controls, so what
   actually plays it — and what a keyboard reaches — is unchanged; this is an
   affordance, not a control. Clicking the video itself toggles playback.

   CSS has :playing and :paused for exactly this, but no browser we support
   implements them yet, so the class comes from assets/js/main.js.
   ========================================================================== */

.wp-block-video {
    position: relative;
}

.wp-block-video::after {
    background: url("../images/play.svg") no-repeat center / contain;
    content: "";
    height: 88px;
    inset: 0;
    margin: auto;
    opacity: 1;
    pointer-events: none;
    position: absolute;
    transition: opacity 200ms ease;
    width: 88px;
}

.wp-block-video.is-playing::after {
    opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
    .wp-block-video::after {
        transition: none;
    }
}


/* ==========================================================================
   Team member

   A portrait cut out of its background, sitting on a circle. The circle is
   white at rest and the site gradient on hover.

   The gradient's two stops are registered custom properties, which is what
   makes the change animate. A custom property only interpolates once it has a
   type — untyped, it would flip halfway through instead of fading — and a
   gradient cannot be transitioned directly: browsers snap to the end value
   even between gradients of matching shape. Animating the colours the
   gradient reads from sidesteps that.

   Namespaced because @property registers globally. A bare --stop-1 would give
   every other use of that name on the site this one's type and starting
   colour, whatever it was meant for.

   Falls back without @property: the properties stay untyped, so the hover
   changes at once rather than fading. Nothing looks broken.
   ========================================================================== */

/* Both stops are palette colours, so both come from their tokens. */
:root {
    --quantcore-gradient-start: var(--wp--preset--color--cyan);
    --quantcore-gradient-end: var(--wp--preset--color--green);
}

@property --team-photo-from {
    syntax: "<color>";
    inherits: false;
    initial-value: #ffffff;
}

@property --team-photo-to {
    syntax: "<color>";
    inherits: false;
    initial-value: #ffffff;
}

/* The portrait is a cut-out, so its own background is the circle behind the
   person — no wrapper, no second layer, nothing to stack. */
.team-member__photo img {
    background-image: linear-gradient(
        180deg,
        var(--team-photo-from),
        var(--team-photo-to)
    );
    border-radius: 50%;
    display: block;
    height: auto;
    transition: --team-photo-from 300ms ease, --team-photo-to 300ms ease;
    width: 100%;
}

.team-member__photo {
    margin: 0;
}

/* The whole card, not the portrait: hovering the name or the role counts too,
   which is a larger and more forgiving target. :focus-within alongside it, so
   the state appears for a keyboard once a portrait carries a link. */
.team-member:hover .team-member__photo img,
.team-member:focus-within .team-member__photo img {
    --team-photo-from: var(--quantcore-gradient-start);
    --team-photo-to: var(--quantcore-gradient-end);
}

@media (prefers-reduced-motion: reduce) {
    .team-member__photo img {
        transition: none;
    }
}

/* Two to a row on a phone. The grid's 210px minimum column, set in the page,
   leaves room for only one card below about 470px. Capping the minimum at 40%
   of the row lets two fit with any reasonable gap, and three never can, so
   wider screens keep the 210px columns exactly as before.

   Selected by its children rather than a class, so every grid of team members
   behaves this way without anyone having to remember to add one. */
.wp-block-group:has(> .team-member) {
    grid-template-columns: repeat(auto-fill, minmax(min(210px, 40%), 1fr));
}


/* ==========================================================================
   Investor logos

   Grey at rest, colour on hover. The design does this with a black overlay in
   colour blend mode; grayscale() is the same idea in one declaration and does
   not need a second layer over the image.

   Full colour by default: the grey only applies where the primary pointer can
   hover. A touch screen has no hover to bring the colour back, so there the
   logos would otherwise stay grey for good.

   The logos arrive as square artwork on white, and are cropped to this band
   before upload, so the image is sized for the slot rather than fitted into it.
   ========================================================================== */

.investor-logo img {
    border-radius: 10px;
    display: block;
    transition: filter 300ms ease;
    width: 100%;
}

@media (hover: hover) {
    .investor-logo img {
        filter: grayscale(1);
    }

    .investor-logo:hover img,
    .investor-logo:focus-within img {
        filter: grayscale(0);
    }
}

/* The row is a no-wrap flex group in the page, which squeezes five logos into
   a phone's width at around 50px each. Wrapping two to a row on a phone and
   three on a tablet, centred so the odd one out sits in the middle, keeps them
   legible; desktops get the single row back.

   The 25px in the flex bases is the row's gap, set in the page. The artwork is
   352px wide, so no width here upscales it. */
.wp-block-group:has(> .investor-logo) {
    flex-wrap: wrap;
    justify-content: center;
}

.wp-block-group:has(> .investor-logo) > .investor-logo {
    flex: 0 0 calc((100% - 25px) / 2);
}

@media (min-width: 600px) {
    .wp-block-group:has(> .investor-logo) > .investor-logo {
        flex-basis: calc((100% - 2 * 25px) / 3);
    }
}

@media (min-width: 1024px) {
    .wp-block-group:has(> .investor-logo) {
        flex-wrap: nowrap;
    }

    .wp-block-group:has(> .investor-logo) > .investor-logo {
        flex: 1 1 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .investor-logo img {
        transition: none;
    }
}


/* ==========================================================================
   Eyebrow

   The small line above a page heading.

   Nothing here is beyond the editor any more — size, weight, tracking, case
   and now the colour are all block settings. The class is kept so the
   eyebrows stay identifiable as one thing and can be changed together; it
   holds the colour so an author does not have to remember which of the
   palette's colours this line takes.
   ========================================================================== */

.eyebrow {
    color: var(--wp--preset--color--cyan);
}

/* ==========================================================================
   Chip tile

   A square tile carrying the design's dot grid, with a chip photograph
   sitting on it. The photographs are transparent, so the grid shows through
   around each one and the three tiles read as a set.

   The grid is drawn rather than shipped as an image: 4px squares on a 24px
   pitch, inset 4px, which is exactly what the design measures. A mask would
   let the colour come from a token, but the grid is a fixed decorative grey
   and a mask on the tile would take the photograph with it.

   The photograph is contained rather than covered: each one is a tight crop
   of its own object with its own transparent margins, and those margins are
   what give the three chips their different apparent sizes in the design.
   ========================================================================== */

.chip-tile {
    aspect-ratio: 1;
    background-image: url("data:image/svg+xml,%3Csvg width='24' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='4' y='4' width='4' height='4' fill='%23767676'/%3E%3C/svg%3E");
}

.chip-tile img {
    height: 100%;
    object-fit: contain;
    width: 100%;
}
