/*
 Theme Name:   Checkpoint Creative (Bricks Child)
 Theme URI:    https://chkpt.com.au/
 Description:  Custom Bricks child theme by Checkpoint Creative.
 Author:       Checkpoint Creative Pty Ltd
 Author URI:   https://chkpt.com.au/
 Template:     bricks
 Version:      1.0
 Text Domain:  chkpt
*/

/* Motion tokens — single source for CSS and GSAP (read by js/src/core/motion.js).
   Values follow Emil Kowalski's animation standards (.claude/skills/review-animations/STANDARDS.md). */
:root {
    --ease-out: cubic-bezier(0.23, 1, 0.32, 1);       /* enter / exit */
    --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);   /* on-screen movement, clip-path reveals */
    --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);    /* drawers, sheets */

    --dur-press: 140ms;        /* button press feedback */
    --dur-ui: 200ms;           /* tooltips, dropdowns, hover */
    --dur-reveal: 450ms;       /* scroll-in reveals (marketing) */
    --dur-reveal-long: 600ms;  /* clip / image reveals */
    --dur-dither-step: 110ms;       /* per resolution step, dither reveal */
    --dur-dither-swap-step: 50ms;   /* per resolution step, dither hover swap */

    --stagger: 60ms;
    --stagger-loose: 100ms;

    /* Dither filter: duotone ends (dark / light) and the number of tones blended between them */
    --dither-ink: #1b3b72;
    --dither-paper: #17e9f0;
    --dither-tones: 4;
    --dither-cell: 2;  /* resting cell size in px: 2, or 1 for fine line art */

    /* Dither field background (js/src/bespoke/dither-field.js, CTA) */
    --field-colour: var(--fg-brand-primary, #17e9f0);
    --field-cell: 4.5px;            /* grid pitch (rounded to whole device px) */
    --field-dot: 3.4px;             /* square dot inside each cell */
    --field-bayer: 4;               /* 4 or 8 */
    --field-edge-desktop: 25% 28%;  /* left, right: how far in the density reaches zero */
    --field-edge-mobile: 22%;
    --field-drift: 10s;             /* slowest cycle of the field */
    --trail-radius: 40px;
    --trail-decay: 600ms;
    --trail-max-centre: 0.35;       /* trail cap over the clear centre (text zone) */
    --pulse-radius: 320px;          /* press pulse: how far the ring travels */
    --pulse-width: 36px;            /* press pulse: ring thickness */
    --pulse-duration: 700ms;        /* press pulse: travel and fade time */

    /* Home hero: security document under a UV torch (js/src/bespoke/hero-*.js) */
    --hero-focus: 70% 30%;          /* focal point of the artwork for cover-fitting */
    --hero-patch-area: 0.07;        /* touch devices: share of the hero open at once */
    --hero-speckle-band: 4;         /* touch patches' edge depth: about this many cells of each size (large, medium, fine) */
    --hero-patch-life: 8s;          /* touch devices: a patch forms, drifts and dissolves over this */
    --hero-torch-radius: 380px;     /* the cursor reveal; its edge band is 45% of this */
    --hero-torch-follow: 120ms;
    --hero-uv-strength: 1;
    --hero-foil-strength: 0.85;     /* holographic foil on the map panels */
    --hero-holo-sheen: 0;           /* optional faint foil sheen across the rest of the document (0 = off) */
    --hero-text-loop: 24s;
    --hero-text-rest: 0.55;         /* text row opacity in resting patches */
}

/* Scroll reveals (js/src/reusable/framework.js) — hide targets before first paint.
   html.cc-js is added by an inline <head> script (inc/enqueue-scripts.php) and
   removed if the framework hasn't started within 4s, so content never stays hidden. */
html.cc-js :is(.cc-fade-up, .cc-fade, .cc-slide-left, .cc-slide-right, .cc-float-in, .cc-clip-reveal, .cc-img-unveil, .cc-dither, .cc-dither-static),
html.cc-js :is(.cc-stagger, .cc-stagger-loose) > * {
    visibility: hidden;
}

/* Finer resting dither (1px cells) for line art such as the guilloche illustrations.
   Add to the image, its wrapper, or a cross-promo frame. */
.cc-dither-fine {
    --dither-cell: 1;
}

/* Dither swap (js/src/bespoke/dither-swap.js) — images stack in .cc-dither-swap-frame
   and only the active one shows, through the dither filter. The frame stays hidden
   until the filter is applied (or has failed), so the raw photo never flashes.
   Without JS the first image shows. */
.cc-dither-swap-frame {
    display: grid;
    position: relative;
}

.cc-dither-swap-frame > * {
    grid-area: 1 / 1;
}

html.cc-js .cc-dither-swap:not(.is-ready) .cc-dither-swap-frame,
.cc-dither-swap:not(.is-ready) .cc-dither-swap-image ~ .cc-dither-swap-image,
.cc-dither-swap.is-ready .cc-dither-swap-image:not(.is-active) {
    visibility: hidden;
}

/* Dither field (js/src/bespoke/dither-field.js) — the canvas crossfades in over the
   container's fallback images once its first frame has drawn, then the images hide. */
.cc-dither-field > canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--dur-reveal) var(--ease-out);
}

.cc-dither-field.is-ready > canvas {
    opacity: 1;
}

/* Home hero layers (js/src/bespoke/hero-document-scene.js): document canvas, text
   rows, pixel cover. Same poster-to-canvas crossfade as the dither field. */
.cc-hero-document > :is(canvas, .cc-hero-document__text) {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    opacity: 0;
    transition: opacity var(--dur-reveal) var(--ease-out);
}

.cc-hero-document.is-ready > :is(canvas, .cc-hero-document__text) {
    opacity: 1;
}

/* The cover is the resting state and matches the section colour, so it appears
   at full strength at once. Fading it with the layers under it would let the
   document show through mid-fade (a flash of the UV artwork on load). */
.cc-hero-document > .cc-hero-document__cover {
    transition: none;
}

.cc-hero-document__text {
    overflow: hidden;
}

.cc-hero-document__svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.cc-hero-document__svg text {
    font-family: var(--font-mono), ui-monospace, monospace;
    letter-spacing: 0.08em;
    fill: var(--uv-lime);
}

.cc-hero-document__svg--rest {
    opacity: var(--hero-text-rest);
}

/* Bright copy under the torch: masked to the torch disc, with a soft glow */
.cc-hero-document__svg--bright {
    opacity: 0;
    -webkit-mask-image: radial-gradient(circle var(--torch-r, 140px) at var(--torch-x, -999px) var(--torch-y, -999px), #000 55%, transparent);
    mask-image: radial-gradient(circle var(--torch-r, 140px) at var(--torch-x, -999px) var(--torch-y, -999px), #000 55%, transparent);
}

.cc-hero-document__svg--bright {
    filter: drop-shadow(0 0 4px var(--uv-lime));
}

:is(.cc-dither-field, .cc-hero-document) img {
    transition: opacity var(--dur-reveal) var(--ease-out);
}

:is(.cc-dither-field, .cc-hero-document).is-ready img {
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--dur-reveal) var(--ease-out), visibility 0s linear var(--dur-reveal);
}

/* The hero's resting state is the flat pixel cover, so the poster is hidden from
   first paint while the scene loads. It comes back (.is-poster, set by
   hero-document.js / -scene.js) only if the scene can't run: no WebGL2, a failed
   load or a lost context. Reduced motion and no JS (html.cc-js removed after 4s)
   keep the poster via the conditions here. */
@media (prefers-reduced-motion: no-preference) {
    html.cc-js .cc-hero-document:not(.is-poster) img {
        opacity: 0;
        visibility: hidden;
    }
}

/* Micrographics (js/src/bespoke/micrographics.js for .cc-approve; the rest is CSS only).
   All loops are off under reduced motion, leaving the static design.
   .cc-matrix    on the 3x3 dot-matrix SVG: the X-pattern five and the plus-pattern four swap brightness
   .cc-cursor    on a text element (Specimen, Fig, Doc): a small blinking square cursor after the text
   .cc-reg-dots  on the 3-dot registration SVG (rotated into a column): grows 1 > 3 > 1 up the side,
                 turns about the corner dot, then does the same along the bottom
   .cc-approve   on .micrographic-signoff: click toggles a tick in the box
   .cc-ticks     on a scale SVG: a highlight scans across the ticks every few seconds
   .cc-crosshair on a crosshair SVG: turns 45deg while its section is hovered (fine pointers) */
@media (prefers-reduced-motion: no-preference) {
    .cc-matrix rect {
        animation: cc-matrix-a 3.2s var(--ease-in-out) infinite;
    }

    .cc-matrix rect:nth-child(even) {
        animation-name: cc-matrix-b;
    }

    .cc-cursor::after {
        animation: cc-blink 1.1s steps(1, end) infinite;
    }

    .cc-reg-dots {
        transform-origin: 15.5px 1.5px; /* the corner (third) dot */
        animation: cc-reg-turn 6s steps(1, end) infinite;
    }

    .cc-reg-dots circle:nth-child(1) {
        animation: cc-reg-far 6s steps(1, end) infinite;
    }

    .cc-reg-dots circle:nth-child(2) {
        animation: cc-reg-mid 6s steps(1, end) infinite;
    }

    .cc-ticks path {
        animation: cc-tick-scan 5.4s var(--ease-out) infinite;
        animation-delay: calc(var(--i, 0) * 120ms);
    }
}

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
    .cc-crosshair {
        transition: transform var(--dur-reveal) var(--ease-out);
    }

    section:hover .cc-crosshair {
        transform: rotate(45deg);
    }
}

@keyframes cc-tick-scan { 0% { stroke: currentColor; } 4% { stroke: var(--fg-brand-primary); } 18%, 100% { stroke: currentColor; } }

@keyframes cc-matrix-a { 0%, 40% { opacity: 1; } 50%, 90% { opacity: 0.4; } 100% { opacity: 1; } }
@keyframes cc-matrix-b { 0%, 40% { opacity: 0.4; } 50%, 90% { opacity: 1; } 100% { opacity: 0.4; } }

@keyframes cc-blink { 50% { opacity: 0; } }

/* Column (up from the corner dot) for the first half, row (right along the bottom) for the second;
   the turn only happens while the corner dot is the only one showing */
@keyframes cc-reg-turn {
    0%, 100% { transform: translate(-14px, 0) rotate(90deg); }
    50%      { transform: translate(-14px, 0) rotate(180deg); }
}
@keyframes cc-reg-mid { 0% { opacity: 0; } 8% { opacity: 1; } 48% { opacity: 0; } 58% { opacity: 1; } 98%, 100% { opacity: 0; } }
@keyframes cc-reg-far { 0% { opacity: 0; } 16% { opacity: 1; } 40% { opacity: 0; } 66% { opacity: 1; } 90%, 100% { opacity: 0; } }

.cc-cursor::after {
    content: "";
    display: inline-block;
    width: 0.5em;
    height: 0.5em;
    margin-left: 0.35em;
    background-color: currentColor;
    vertical-align: 0.05em;
}

.cc-approve {
    position: relative;
    cursor: pointer;
    user-select: none;
}

.cc-approve > * {
    transition: color var(--dur-ui) ease;
}

.cc-approve::before {
    transition: background-color var(--dur-ui) var(--ease-out), border-color var(--dur-ui) var(--ease-out), transform var(--dur-press) var(--ease-out);
}

.cc-approve::after {
    content: "";
    position: absolute;
    left: 4px;
    top: 50%;
    width: 4px;
    height: 7px;
    border: solid var(--bg-primary);
    border-width: 0 1.5px 1.5px 0;
    opacity: 0;
    transform: translateY(-65%) rotate(45deg) scale(0.6);
    transition: opacity var(--dur-ui) var(--ease-out), transform var(--dur-ui) var(--ease-out);
}

.cc-approve:active::before {
    transform: scale(0.9);
}

/* On the label itself: Bricks' own .micrographic-signoff colour rule loads later */
.cc-approve.is-checked > * {
    color: var(--fg-brand-primary);
}

.cc-approve.is-checked::before {
    background-color: var(--fg-brand-primary);
    border-color: var(--fg-brand-primary);
}

.cc-approve.is-checked::after {
    opacity: 1;
    transform: translateY(-65%) rotate(45deg) scale(1);
}

@media (hover: hover) and (pointer: fine) {
    .cc-approve:hover::before {
        border-color: var(--fg-brand-primary);
    }
}

/* Interaction utilities — add these classes in Bricks.
   .cc-press      buttons: scales down while pressed
   .cc-underline  inline text links: underline draws in on hover/focus
   .cc-lift       cards: rises slightly on hover/focus
   .cc-nudge      buttons/links with an icon: the icon slides right on hover
   .cc-zoom       image wrappers: the image zooms inside the frame on hover */
.cc-press {
    transition: transform var(--dur-press) var(--ease-out);
}

.cc-press:active {
    transform: scale(0.97);
}

.cc-underline {
    text-decoration: none;
    background-image: linear-gradient(currentColor, currentColor);
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 0% 1px;
    transition: background-size var(--dur-ui) var(--ease-out);
}

.cc-underline:focus-visible {
    background-size: 100% 1px;
}

.cc-lift,
.cc-nudge :is(svg, i),
.cc-zoom :is(img, canvas) {
    transition: transform var(--dur-ui) var(--ease-out);
}

.cc-zoom {
    overflow: hidden;
}

.cc-zoom :is(img, canvas) {
    transition-duration: var(--dur-reveal);
}

@media (hover: hover) and (pointer: fine) {
    .cc-underline:hover {
        background-size: 100% 1px;
    }
}

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
    .cc-lift:hover {
        transform: translateY(-4px);
    }

    .cc-nudge:hover :is(svg, i) {
        transform: translateX(4px);
    }

    .cc-zoom:hover :is(img, canvas) {
        transform: scale(1.04);
    }
}

@media (prefers-reduced-motion: no-preference) {
    .cc-lift:is(:focus-visible, :has(:focus-visible)) {
        transform: translateY(-4px);
    }
}

/* Button hover: the hover colour wipes in from the left and out to the right,
   instead of Bricks' background-color fade. The wipe is a background-image over
   the resting background-color, which stays put. Applies to the Bricks button
   classes and the form submit button; no extra class needed. The extra
   .bricks-button in each selector outranks the Bricks class :hover rules. */
.btn-primary.brxe-button.bricks-button,
.brxe-form button.bricks-button {
    --wipe-colour: var(--button-primary-hover);
}

.btn-secondary.brxe-button.bricks-button {
    --wipe-colour: var(--button-secondary-hover);
}

:is(.btn-primary, .btn-secondary).brxe-button.bricks-button,
.brxe-form button.bricks-button.bricks-button {
    background-image: linear-gradient(var(--wipe-colour), var(--wipe-colour));
    background-repeat: no-repeat;
    background-position: right;
    background-size: 0% 100%;
    transition:
        background-size var(--dur-ui) var(--ease-in-out),
        border-color var(--dur-ui) ease,
        color var(--dur-ui) ease,
        transform var(--dur-press) var(--ease-out);
}

.btn-primary.brxe-button.bricks-button:is(:hover, :focus-visible),
.brxe-form button.bricks-button.bricks-button:is(:hover, :focus-visible) {
    background-color: var(--button-primary);
}

.btn-secondary.brxe-button.bricks-button:is(:hover, :focus-visible) {
    background-color: var(--button-secondary);
}

:is(.btn-primary, .btn-secondary).brxe-button.bricks-button:focus-visible,
.brxe-form button.bricks-button.bricks-button:focus-visible {
    background-position: left;
    background-size: 100% 100%;
}

@media (hover: hover) and (pointer: fine) {
    :is(.btn-primary, .btn-secondary).brxe-button.bricks-button:hover,
    .brxe-form button.bricks-button.bricks-button:hover {
        background-position: left;
        background-size: 100% 100%;
    }
}

@media (prefers-reduced-motion: reduce) {
    :is(.btn-primary, .btn-secondary).brxe-button.bricks-button,
    .brxe-form button.bricks-button.bricks-button {
        transition-property: border-color, color, transform;
    }
}

/* Text scramble (js/src/reusable/text-scramble.js): the real text stays in place,
   kerned and readable to assistive tech, but transparent; glyphs are drawn on an
   overlay, each over its character's box, so nothing shifts when it settles. */
.scramble-hidden {
    color: transparent;
    -webkit-text-fill-color: transparent;
}

.scramble-overlay {
    position: absolute;
    left: 0;
    top: 0;
    pointer-events: none;
    user-select: none;
}

.scramble-glyph {
    position: absolute;
    text-align: center;
    white-space: pre;
    font-family: var(--scramble-family, inherit);
}

.scramble-glyph.is-alternate {
    font-family: var(--scramble-font, ui-monospace, monospace);
}
/* Autofill: stop Chrome/Safari's light-blue fill so prefilled fields keep the form style */
.contact-form.brxe-form input:is(:-webkit-autofill, :autofill),
.contact-form.brxe-form input:is(:-webkit-autofill, :autofill):is(:hover, :focus) {
    -webkit-text-fill-color: var(--text-primary);
    caret-color: var(--text-primary);
    -webkit-box-shadow: 0 0 0 1000px var(--bg-primary) inset;
    box-shadow: 0 0 0 1000px var(--bg-primary) inset;
    transition: background-color 600000s 0s;
}

/* Form dropdowns (js/src/reusable/select.js, Tom Select). The closed control
   matches the Bricks .contact-form field; the chevron is Bricks' form-group
   ::after, which still matches because the original <select> stays in place. */
.ts-hidden-accessible {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    border: 0 !important;
    overflow: hidden !important;
    clip-path: inset(50%) !important;
    white-space: nowrap !important;
}

.brxe-form .ts-wrapper {
    position: relative;
    width: 100%;
}

.brxe-form .ts-control {
    display: flex;
    align-items: center;
    box-sizing: border-box;
    height: calc(var(--line-height-label-sm) + 2 * var(--spacing-2xl));
    padding: 0 calc(var(--spacing-2xl) * 2 + 16px) 0 var(--spacing-2xl);
    border-top: 1px solid var(--border-tertiary);
    border-bottom: 1px solid var(--border-tertiary);
    font-family: Geist;
    font-size: var(--font-size-label-sm);
    line-height: var(--line-height-label-sm);
    color: var(--text-primary);
    cursor: pointer;
}

.brxe-form .ts-control:focus-visible {
    outline: 1px solid var(--border-brand);
    outline-offset: -1px;
}

.brxe-form .ts-wrapper:not(.has-items) .ts-control::before {
    content: attr(data-placeholder);
    color: var(--text-secondary);
}

.brxe-form .ts-control .item {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.brxe-form .ts-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 10;
    margin-top: -1px;
    background: var(--bg-primary);
    border: 1px solid var(--border-tertiary);
    border-top-color: var(--border-brand);
    animation: cc-select-in var(--dur-ui) var(--ease-out);
}

.brxe-form .ts-dropdown-content {
    max-height: 320px;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* Left padding less the dropdown's 1px border, so options line up with the control text */
.brxe-form .ts-dropdown .option {
    padding: var(--spacing-lg) var(--spacing-2xl) var(--spacing-lg) calc(var(--spacing-2xl) - 1px);
    font-family: Geist;
    font-size: var(--font-size-label-sm);
    line-height: var(--line-height-label-sm);
    color: var(--text-primary);
    cursor: pointer;
}

.brxe-form .ts-dropdown .option.active {
    background: var(--bg-secondary);
}

.brxe-form .ts-dropdown .option.selected {
    color: var(--fg-brand-primary);
}

.brxe-form .form-group:has(.ts-wrapper)::after {
    transition: transform var(--dur-ui) var(--ease-out);
}

.brxe-form .form-group:has(.ts-wrapper.dropdown-active)::after {
    transform: rotate(180deg);
}

@keyframes cc-select-in {
    from { opacity: 0; transform: translateY(-4px); }
}

@media (prefers-reduced-motion: reduce) {
    .brxe-form .ts-dropdown {
        animation-name: cc-fade-in;
    }

    .brxe-form .form-group:has(.ts-wrapper)::after {
        transition: none;
    }
}

@keyframes cc-fade-in {
    from { opacity: 0; }
}
